1 | // Copyright 2011 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_BUILTINS_BUILTINS_H_ |
6 | #define V8_BUILTINS_BUILTINS_H_ |
7 | |
8 | #include "src/base/flags.h" |
9 | #include "src/builtins/builtins-definitions.h" |
10 | #include "src/globals.h" |
11 | |
12 | namespace v8 { |
13 | namespace internal { |
14 | |
15 | class ByteArray; |
16 | class Callable; |
17 | template <typename T> |
18 | class Handle; |
19 | class Isolate; |
20 | |
21 | // Forward declarations. |
22 | class BailoutId; |
23 | class RootVisitor; |
24 | enum class InterpreterPushArgsMode : unsigned; |
25 | namespace compiler { |
26 | class CodeAssemblerState; |
27 | } |
28 | |
29 | template <typename T> |
30 | static constexpr T FirstFromVarArgs(T x, ...) noexcept { |
31 | return x; |
32 | } |
33 | |
34 | // Convenience macro to avoid generating named accessors for all builtins. |
35 | #define BUILTIN_CODE(isolate, name) \ |
36 | (isolate)->builtins()->builtin_handle(Builtins::k##name) |
37 | |
38 | class Builtins { |
39 | public: |
40 | explicit Builtins(Isolate* isolate) : isolate_(isolate) {} |
41 | |
42 | void TearDown(); |
43 | |
44 | // Disassembler support. |
45 | const char* Lookup(Address pc); |
46 | |
47 | enum Name : int32_t { |
48 | #define DEF_ENUM(Name, ...) k##Name, |
49 | BUILTIN_LIST(DEF_ENUM, DEF_ENUM, DEF_ENUM, DEF_ENUM, DEF_ENUM, DEF_ENUM, |
50 | DEF_ENUM, DEF_ENUM) |
51 | #undef DEF_ENUM |
52 | builtin_count, |
53 | |
54 | #define (Name, ...) k##Name, |
55 | // Define kFirstBytecodeHandler, |
56 | kFirstBytecodeHandler = |
57 | FirstFromVarArgs(BUILTIN_LIST_BYTECODE_HANDLERS(EXTRACT_NAME) 0) |
58 | #undef EXTRACT_NAME |
59 | }; |
60 | |
61 | static const int32_t kNoBuiltinId = -1; |
62 | |
63 | static constexpr bool IsBuiltinId(int maybe_id) { |
64 | return 0 <= maybe_id && maybe_id < builtin_count; |
65 | } |
66 | |
67 | // The different builtin kinds are documented in builtins-definitions.h. |
68 | enum Kind { CPP, API, TFJ, TFC, TFS, TFH, BCH, ASM }; |
69 | |
70 | static BailoutId GetContinuationBailoutId(Name name); |
71 | static Name GetBuiltinFromBailoutId(BailoutId); |
72 | |
73 | // Convenience wrappers. |
74 | Handle<Code> CallFunction(ConvertReceiverMode = ConvertReceiverMode::kAny); |
75 | Handle<Code> Call(ConvertReceiverMode = ConvertReceiverMode::kAny); |
76 | Handle<Code> NonPrimitiveToPrimitive( |
77 | ToPrimitiveHint hint = ToPrimitiveHint::kDefault); |
78 | Handle<Code> OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint); |
79 | Handle<Code> JSConstructStubGeneric(); |
80 | |
81 | // Used by CreateOffHeapTrampolines in isolate.cc. |
82 | void set_builtin(int index, Code builtin); |
83 | |
84 | V8_EXPORT_PRIVATE Code builtin(int index); |
85 | V8_EXPORT_PRIVATE Handle<Code> builtin_handle(int index); |
86 | |
87 | V8_EXPORT_PRIVATE static Callable CallableFor(Isolate* isolate, Name name); |
88 | |
89 | static int GetStackParameterCount(Name name); |
90 | |
91 | static const char* name(int index); |
92 | |
93 | // Support for --print-builtin-size and --print-builtin-code. |
94 | void PrintBuiltinCode(); |
95 | void PrintBuiltinSize(); |
96 | |
97 | // Returns the C++ entry point for builtins implemented in C++, and the null |
98 | // Address otherwise. |
99 | static Address CppEntryOf(int index); |
100 | |
101 | static Kind KindOf(int index); |
102 | static const char* KindNameOf(int index); |
103 | |
104 | static bool IsCpp(int index); |
105 | static bool HasCppImplementation(int index); |
106 | |
107 | // True, iff the given code object is a builtin. Note that this does not |
108 | // necessarily mean that its kind is Code::BUILTIN. |
109 | static bool IsBuiltin(const Code code); |
110 | |
111 | // As above, but safe to access off the main thread since the check is done |
112 | // by handle location. Similar to Heap::IsRootHandle. |
113 | bool IsBuiltinHandle(Handle<HeapObject> maybe_code, int* index) const; |
114 | |
115 | // True, iff the given code object is a builtin with off-heap embedded code. |
116 | static bool IsIsolateIndependentBuiltin(const Code code); |
117 | |
118 | static constexpr int kFirstWideBytecodeHandler = |
119 | kFirstBytecodeHandler + kNumberOfBytecodeHandlers; |
120 | static constexpr int kFirstExtraWideBytecodeHandler = |
121 | kFirstWideBytecodeHandler + kNumberOfWideBytecodeHandlers; |
122 | STATIC_ASSERT(kFirstExtraWideBytecodeHandler + |
123 | kNumberOfWideBytecodeHandlers == |
124 | builtin_count); |
125 | |
126 | // True, iff the given builtin contains no isolate-specific code and can be |
127 | // embedded into the binary. |
128 | static constexpr bool kAllBuiltinsAreIsolateIndependent = true; |
129 | static constexpr bool AllBuiltinsAreIsolateIndependent() { |
130 | return kAllBuiltinsAreIsolateIndependent; |
131 | } |
132 | static constexpr bool IsIsolateIndependent(int index) { |
133 | STATIC_ASSERT(kAllBuiltinsAreIsolateIndependent); |
134 | return kAllBuiltinsAreIsolateIndependent; |
135 | } |
136 | |
137 | // Wasm runtime stubs are treated specially by wasm. To guarantee reachability |
138 | // through near jumps, their code is completely copied into a fresh off-heap |
139 | // area. |
140 | static bool IsWasmRuntimeStub(int index); |
141 | |
142 | // Updates the table of builtin entry points based on the current contents of |
143 | // the builtins table. |
144 | static void UpdateBuiltinEntryTable(Isolate* isolate); |
145 | |
146 | bool is_initialized() const { return initialized_; } |
147 | |
148 | // Used by SetupIsolateDelegate and Deserializer. |
149 | void MarkInitialized() { |
150 | DCHECK(!initialized_); |
151 | initialized_ = true; |
152 | } |
153 | |
154 | V8_WARN_UNUSED_RESULT static MaybeHandle<Object> InvokeApiFunction( |
155 | Isolate* isolate, bool is_construct, Handle<HeapObject> function, |
156 | Handle<Object> receiver, int argc, Handle<Object> args[], |
157 | Handle<HeapObject> new_target); |
158 | |
159 | enum ExitFrameType { EXIT, BUILTIN_EXIT }; |
160 | |
161 | static void Generate_Adaptor(MacroAssembler* masm, Address builtin_address, |
162 | ExitFrameType exit_frame_type); |
163 | |
164 | static void Generate_CEntry(MacroAssembler* masm, int result_size, |
165 | SaveFPRegsMode save_doubles, ArgvMode argv_mode, |
166 | bool builtin_exit_frame); |
167 | |
168 | static bool AllowDynamicFunction(Isolate* isolate, Handle<JSFunction> target, |
169 | Handle<JSObject> target_global_proxy); |
170 | |
171 | // Creates a trampoline code object that jumps to the given off-heap entry. |
172 | // The result should not be used directly, but only from the related Factory |
173 | // function. |
174 | static Handle<Code> GenerateOffHeapTrampolineFor(Isolate* isolate, |
175 | Address off_heap_entry); |
176 | |
177 | // Generate the RelocInfo ByteArray that would be generated for an offheap |
178 | // trampoline. |
179 | static Handle<ByteArray> GenerateOffHeapTrampolineRelocInfo(Isolate* isolate); |
180 | |
181 | static bool IsJSEntryVariant(int builtin_index) { |
182 | switch (builtin_index) { |
183 | case kJSEntry: |
184 | case kJSConstructEntry: |
185 | case kJSRunMicrotasksEntry: |
186 | return true; |
187 | default: |
188 | return false; |
189 | } |
190 | UNREACHABLE(); |
191 | } |
192 | |
193 | int js_entry_handler_offset() const { |
194 | DCHECK_NE(js_entry_handler_offset_, 0); |
195 | return js_entry_handler_offset_; |
196 | } |
197 | |
198 | void SetJSEntryHandlerOffset(int offset) { |
199 | // Check the stored offset is either uninitialized or unchanged (we |
200 | // generate multiple variants of this builtin but they should all have the |
201 | // same handler offset). |
202 | CHECK(js_entry_handler_offset_ == 0 || js_entry_handler_offset_ == offset); |
203 | js_entry_handler_offset_ = offset; |
204 | } |
205 | |
206 | private: |
207 | static void Generate_CallFunction(MacroAssembler* masm, |
208 | ConvertReceiverMode mode); |
209 | |
210 | static void Generate_CallBoundFunctionImpl(MacroAssembler* masm); |
211 | |
212 | static void Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode); |
213 | |
214 | enum class CallOrConstructMode { kCall, kConstruct }; |
215 | static void Generate_CallOrConstructVarargs(MacroAssembler* masm, |
216 | Handle<Code> code); |
217 | static void Generate_CallOrConstructForwardVarargs(MacroAssembler* masm, |
218 | CallOrConstructMode mode, |
219 | Handle<Code> code); |
220 | |
221 | static void Generate_InterpreterPushArgsThenCallImpl( |
222 | MacroAssembler* masm, ConvertReceiverMode receiver_mode, |
223 | InterpreterPushArgsMode mode); |
224 | |
225 | static void Generate_InterpreterPushArgsThenConstructImpl( |
226 | MacroAssembler* masm, InterpreterPushArgsMode mode); |
227 | |
228 | #define DECLARE_ASM(Name, ...) \ |
229 | static void Generate_##Name(MacroAssembler* masm); |
230 | #define DECLARE_TF(Name, ...) \ |
231 | static void Generate_##Name(compiler::CodeAssemblerState* |
---|