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