1// Copyright 2018 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/codegen/turbo-assembler.h"
6
7#include "src/builtins/builtins.h"
8#include "src/builtins/constants-table-builder.h"
9#include "src/codegen/external-reference-encoder.h"
10#include "src/common/globals.h"
11#include "src/execution/isolate-data.h"
12#include "src/execution/isolate-inl.h"
13#include "src/snapshot/embedded/embedded-data-inl.h"
14
15namespace v8 {
16namespace internal {
17
18TurboAssemblerBase::TurboAssemblerBase(Isolate* isolate,
19                                       const AssemblerOptions& options,
20                                       CodeObjectRequired create_code_object,
21                                       std::unique_ptr<AssemblerBuffer> buffer)
22    : Assembler(options, std::move(buffer)), isolate_(isolate) {
23  if (create_code_object == CodeObjectRequired::kYes) {
24    code_object_ = Handle<HeapObject>::New(
25        ReadOnlyRoots(isolate).self_reference_marker(), isolate);
26  }
27}
28
29Address TurboAssemblerBase::BuiltinEntry(Builtin builtin) {
30  DCHECK(Builtins::IsBuiltinId(builtin));
31  if (isolate_ != nullptr) {
32    Address entry =
33        isolate_->builtin_entry_table()[static_cast<int32_t>(builtin)];
34    DCHECK_EQ(entry, EmbeddedData::FromBlob(isolate_).InstructionStartOfBuiltin(
35                         builtin));
36    return entry;
37  }
38  EmbeddedData d = EmbeddedData::FromBlob();
39  return d.InstructionStartOfBuiltin(builtin);
40}
41
42void TurboAssemblerBase::IndirectLoadConstant(Register destination,
43                                              Handle<HeapObject> object) {
44  CHECK(root_array_available_);
45
46  // Before falling back to the (fairly slow) lookup from the constants table,
47  // check if any of the fast paths can be applied.
48
49  Builtin builtin;
50  RootIndex root_index;
51  if (isolate()->roots_table().IsRootHandle(object, &root_index)) {
52    // Roots are loaded relative to the root register.
53    LoadRoot(destination, root_index);
54  } else if (isolate()->builtins()->IsBuiltinHandle(object, &builtin)) {
55    // Similar to roots, builtins may be loaded from the builtins table.
56    LoadRootRelative(destination, RootRegisterOffsetForBuiltin(builtin));
57  } else if (object.is_identical_to(code_object_) &&
58             Builtins::IsBuiltinId(maybe_builtin_)) {
59    // The self-reference loaded through Codevalue() may also be a builtin
60    // and thus viable for a fast load.
61    LoadRootRelative(destination, RootRegisterOffsetForBuiltin(maybe_builtin_));
62  } else {
63    CHECK(isolate()->IsGeneratingEmbeddedBuiltins());
64    // Ensure the given object is in the builtins constants table and fetch its
65    // index.
66    BuiltinsConstantsTableBuilder* builder =
67        isolate()->builtins_constants_table_builder();
68    uint32_t index = builder->AddObject(object);
69
70    // Slow load from the constants table.
71    LoadFromConstantsTable(destination, index);
72  }
73}
74
75void TurboAssemblerBase::IndirectLoadExternalReference(
76    Register destination, ExternalReference reference) {
77  CHECK(root_array_available_);
78
79  if (IsAddressableThroughRootRegister(isolate(), reference)) {
80    // Some external references can be efficiently loaded as an offset from
81    // kRootRegister.
82    intptr_t offset =
83        RootRegisterOffsetForExternalReference(isolate(), reference);
84    LoadRootRegisterOffset(destination, offset);
85  } else {
86    // Otherwise, do a memory load from the external reference table.
87    LoadRootRelative(
88        destination,
89        RootRegisterOffsetForExternalReferenceTableEntry(isolate(), reference));
90  }
91}
92
93// static
94int32_t TurboAssemblerBase::RootRegisterOffsetForRootIndex(
95    RootIndex root_index) {
96  return IsolateData::root_slot_offset(root_index);
97}
98
99// static
100int32_t TurboAssemblerBase::RootRegisterOffsetForBuiltin(Builtin builtin) {
101  return IsolateData::BuiltinSlotOffset(builtin);
102}
103
104// static
105intptr_t TurboAssemblerBase::RootRegisterOffsetForExternalReference(
106    Isolate* isolate, const ExternalReference& reference) {
107  return static_cast<intptr_t>(reference.address() - isolate->isolate_root());
108}
109
110// static
111int32_t TurboAssemblerBase::RootRegisterOffsetForExternalReferenceTableEntry(
112    Isolate* isolate, const ExternalReference& reference) {
113  // Encode as an index into the external reference table stored on the
114  // isolate.
115  ExternalReferenceEncoder encoder(isolate);
116  ExternalReferenceEncoder::Value v = encoder.Encode(reference.address());
117  CHECK(!v.is_from_api());
118
119  return IsolateData::external_reference_table_offset() +
120         ExternalReferenceTable::OffsetOfEntry(v.index());
121}
122
123// static
124bool TurboAssemblerBase::IsAddressableThroughRootRegister(
125    Isolate* isolate, const ExternalReference& reference) {
126  Address address = reference.address();
127  return isolate->root_register_addressable_region().contains(address);
128}
129
130}  // namespace internal
131}  // namespace v8
132