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
12namespace v8 {
13namespace internal {
14
15class ByteArray;
16class Callable;
17template <typename T>
18class Handle;
19class Isolate;
20
21// Forward declarations.
22class BailoutId;
23class RootVisitor;
24enum class InterpreterPushArgsMode : unsigned;
25namespace compiler {
26class CodeAssemblerState;
27}
28
29template <typename T>
30static 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
38class 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 EXTRACT_NAME(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* state);
232
233 BUILTIN_LIST(IGNORE_BUILTIN, IGNORE_BUILTIN, DECLARE_TF, DECLARE_TF,
234 DECLARE_TF, DECLARE_TF, IGNORE_BUILTIN, DECLARE_ASM)
235
236#undef DECLARE_ASM
237#undef DECLARE_TF
238
239 Isolate* isolate_;
240 bool initialized_ = false;
241
242 // Stores the offset of exception handler entry point (the handler_entry
243 // label) in JSEntry and its variants. It's used to generate the handler table
244 // during codegen (mksnapshot-only).
245 int js_entry_handler_offset_ = 0;
246
247 friend class SetupIsolateDelegate;
248
249 DISALLOW_COPY_AND_ASSIGN(Builtins);
250};
251
252Builtins::Name ExampleBuiltinForTorqueFunctionPointerType(
253 size_t function_pointer_type_id);
254
255} // namespace internal
256} // namespace v8
257
258#endif // V8_BUILTINS_BUILTINS_H_
259