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 #ifndef V8_CODEGEN_TURBO_ASSEMBLER_H_ 6 #define V8_CODEGEN_TURBO_ASSEMBLER_H_ 7 8 #include <memory> 9 10 #include "src/base/template-utils.h" 11 #include "src/builtins/builtins.h" 12 #include "src/codegen/assembler-arch.h" 13 #include "src/roots/roots.h" 14 15 namespace v8 { 16 namespace internal { 17 18 // Common base class for platform-specific TurboAssemblers containing 19 // platform-independent bits. 20 // You will encounter two subclasses, TurboAssembler (derives from 21 // TurboAssemblerBase), and MacroAssembler (derives from TurboAssembler). The 22 // main difference is that MacroAssembler is allowed to access the isolate, and 23 // TurboAssembler accesses the isolate in a very limited way. TurboAssembler 24 // contains all the functionality that is used by Turbofan, and does not expect 25 // to be running on the main thread. 26 class V8_EXPORT_PRIVATE TurboAssemblerBase : public Assembler { 27 public: 28 // Constructors are declared public to inherit them in derived classes 29 // with `using` directive. 30 TurboAssemblerBase(Isolate* isolate, CodeObjectRequired create_code_object, 31 std::unique_ptr<AssemblerBuffer> buffer = {}) TurboAssemblerBase(isolate,AssemblerOptions::Default (isolate),create_code_object,std::move (buffer))32 : TurboAssemblerBase(isolate, AssemblerOptions::Default(isolate), 33 create_code_object, std::move(buffer)) {} 34 35 TurboAssemblerBase(Isolate* isolate, const AssemblerOptions& options, 36 CodeObjectRequired create_code_object, 37 std::unique_ptr<AssemblerBuffer> buffer = {}); 38 isolate()39 Isolate* isolate() const { 40 return isolate_; 41 } 42 CodeObject()43 Handle<HeapObject> CodeObject() const { 44 DCHECK(!code_object_.is_null()); 45 return code_object_; 46 } 47 root_array_available()48 bool root_array_available() const { return root_array_available_; } set_root_array_available(bool v)49 void set_root_array_available(bool v) { root_array_available_ = v; } 50 trap_on_abort()51 bool trap_on_abort() const { return trap_on_abort_; } 52 should_abort_hard()53 bool should_abort_hard() const { return hard_abort_; } set_abort_hard(bool v)54 void set_abort_hard(bool v) { hard_abort_ = v; } 55 set_builtin(Builtin builtin)56 void set_builtin(Builtin builtin) { maybe_builtin_ = builtin; } 57 set_has_frame(bool v)58 void set_has_frame(bool v) { has_frame_ = v; } has_frame()59 bool has_frame() const { return has_frame_; } 60 61 // Loads the given constant or external reference without embedding its direct 62 // pointer. The produced code is isolate-independent. 63 void IndirectLoadConstant(Register destination, Handle<HeapObject> object); 64 void IndirectLoadExternalReference(Register destination, 65 ExternalReference reference); 66 67 Address BuiltinEntry(Builtin builtin); 68 69 virtual void LoadFromConstantsTable(Register destination, 70 int constant_index) = 0; 71 72 // Corresponds to: destination = kRootRegister + offset. 73 virtual void LoadRootRegisterOffset(Register destination, 74 intptr_t offset) = 0; 75 76 // Corresponds to: destination = [kRootRegister + offset]. 77 virtual void LoadRootRelative(Register destination, int32_t offset) = 0; 78 79 virtual void LoadRoot(Register destination, RootIndex index) = 0; 80 81 static int32_t RootRegisterOffsetForRootIndex(RootIndex root_index); 82 static int32_t RootRegisterOffsetForBuiltin(Builtin builtin); 83 84 // Returns the root-relative offset to reference.address(). 85 static intptr_t RootRegisterOffsetForExternalReference( 86 Isolate* isolate, const ExternalReference& reference); 87 88 // Returns the root-relative offset to the external reference table entry, 89 // which itself contains reference.address(). 90 static int32_t RootRegisterOffsetForExternalReferenceTableEntry( 91 Isolate* isolate, const ExternalReference& reference); 92 93 // An address is addressable through kRootRegister if it is located within 94 // isolate->root_register_addressable_region(). 95 static bool IsAddressableThroughRootRegister( 96 Isolate* isolate, const ExternalReference& reference); 97 98 #if defined(V8_TARGET_OS_WIN) || defined(V8_TARGET_OS_MACOS) 99 // Minimum page size. We must touch memory once per page when expanding the 100 // stack, to avoid access violations. 101 static constexpr int kStackPageSize = 4 * KB; 102 #endif 103 CommentForOffHeapTrampoline(const char * prefix,Builtin builtin)104 V8_INLINE std::string CommentForOffHeapTrampoline(const char* prefix, 105 Builtin builtin) { 106 if (!FLAG_code_comments) return ""; 107 std::ostringstream str; 108 str << "Inlined Trampoline for " << prefix << " to " 109 << Builtins::name(builtin); 110 return str.str(); 111 } 112 RecordCommentForOffHeapTrampoline(Builtin builtin)113 V8_INLINE void RecordCommentForOffHeapTrampoline(Builtin builtin) { 114 if (!FLAG_code_comments) return; 115 std::ostringstream str; 116 str << "[ Inlined Trampoline to " << Builtins::name(builtin); 117 RecordComment(str.str().c_str()); 118 } 119 120 enum class RecordWriteCallMode { kDefault, kWasm }; 121 122 protected: 123 Isolate* const isolate_ = nullptr; 124 125 // This handle will be patched with the code object on installation. 126 Handle<HeapObject> code_object_; 127 128 // Whether kRootRegister has been initialized. 129 bool root_array_available_ = true; 130 131 // Immediately trap instead of calling {Abort} when debug code fails. 132 bool trap_on_abort_ = FLAG_trap_on_abort; 133 134 // Emit a C call to abort instead of a runtime call. 135 bool hard_abort_ = false; 136 137 // May be set while generating builtins. 138 Builtin maybe_builtin_ = Builtin::kNoBuiltinId; 139 140 bool has_frame_ = false; 141 142 int comment_depth_ = 0; 143 144 DISALLOW_IMPLICIT_CONSTRUCTORS(TurboAssemblerBase); 145 }; 146 147 // Avoids emitting calls to the {Builtin::kAbort} builtin when emitting 148 // debug code during the lifetime of this scope object. 149 class V8_NODISCARD HardAbortScope { 150 public: HardAbortScope(TurboAssemblerBase * assembler)151 explicit HardAbortScope(TurboAssemblerBase* assembler) 152 : assembler_(assembler), old_value_(assembler->should_abort_hard()) { 153 assembler_->set_abort_hard(true); 154 } ~HardAbortScope()155 ~HardAbortScope() { assembler_->set_abort_hard(old_value_); } 156 157 private: 158 TurboAssemblerBase* assembler_; 159 bool old_value_; 160 }; 161 162 } // namespace internal 163 } // namespace v8 164 165 #endif // V8_CODEGEN_TURBO_ASSEMBLER_H_ 166