xref: /third_party/node/deps/v8/src/builtins/builtins.h (revision 1cb0ef41)
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/common/globals.h"
11
12namespace v8 {
13namespace internal {
14
15class ByteArray;
16class CallInterfaceDescriptor;
17class Callable;
18template <typename T>
19class Handle;
20class Isolate;
21
22// Forward declarations.
23class BytecodeOffset;
24class RootVisitor;
25enum class InterpreterPushArgsMode : unsigned;
26namespace compiler {
27class CodeAssemblerState;
28}  // namespace compiler
29
30template <typename T>
31static constexpr T FirstFromVarArgs(T x, ...) noexcept {
32  return x;
33}
34
35// Convenience macro to avoid generating named accessors for all builtins.
36#define BUILTIN_CODE(isolate, name) \
37  (isolate)->builtins()->code_handle(i::Builtin::k##name)
38
39enum class Builtin : int32_t {
40  kNoBuiltinId = -1,
41#define DEF_ENUM(Name, ...) k##Name,
42  BUILTIN_LIST(DEF_ENUM, DEF_ENUM, DEF_ENUM, DEF_ENUM, DEF_ENUM, DEF_ENUM,
43               DEF_ENUM)
44#undef DEF_ENUM
45#define EXTRACT_NAME(Name, ...) k##Name,
46  // Define kFirstBytecodeHandler,
47  kFirstBytecodeHandler =
48      FirstFromVarArgs(BUILTIN_LIST_BYTECODE_HANDLERS(EXTRACT_NAME) 0)
49#undef EXTRACT_NAME
50};
51
52V8_INLINE constexpr bool operator<(Builtin a, Builtin b) {
53  using type = typename std::underlying_type<Builtin>::type;
54  return static_cast<type>(a) < static_cast<type>(b);
55}
56
57V8_INLINE Builtin operator++(Builtin& builtin) {
58  using type = typename std::underlying_type<Builtin>::type;
59  return builtin = static_cast<Builtin>(static_cast<type>(builtin) + 1);
60}
61
62class Builtins {
63 public:
64  explicit Builtins(Isolate* isolate) : isolate_(isolate) {}
65
66  Builtins(const Builtins&) = delete;
67  Builtins& operator=(const Builtins&) = delete;
68
69  void TearDown();
70
71  // Disassembler support.
72  const char* Lookup(Address pc);
73
74#define ADD_ONE(Name, ...) +1
75  static constexpr int kBuiltinCount = 0 BUILTIN_LIST(
76      ADD_ONE, ADD_ONE, ADD_ONE, ADD_ONE, ADD_ONE, ADD_ONE, ADD_ONE);
77  static constexpr int kBuiltinTier0Count = 0 BUILTIN_LIST_TIER0(
78      ADD_ONE, ADD_ONE, ADD_ONE, ADD_ONE, ADD_ONE, ADD_ONE, ADD_ONE);
79#undef ADD_ONE
80
81  static constexpr Builtin kFirst = static_cast<Builtin>(0);
82  static constexpr Builtin kLast = static_cast<Builtin>(kBuiltinCount - 1);
83  static constexpr Builtin kLastTier0 =
84      static_cast<Builtin>(kBuiltinTier0Count - 1);
85
86  static constexpr int kFirstWideBytecodeHandler =
87      static_cast<int>(Builtin::kFirstBytecodeHandler) +
88      kNumberOfBytecodeHandlers;
89  static constexpr int kFirstExtraWideBytecodeHandler =
90      kFirstWideBytecodeHandler + kNumberOfWideBytecodeHandlers;
91  static constexpr int kLastBytecodeHandlerPlusOne =
92      kFirstExtraWideBytecodeHandler + kNumberOfWideBytecodeHandlers;
93  STATIC_ASSERT(kLastBytecodeHandlerPlusOne == kBuiltinCount);
94
95  static constexpr bool IsBuiltinId(Builtin builtin) {
96    return builtin != Builtin::kNoBuiltinId;
97  }
98  static constexpr bool IsBuiltinId(int maybe_id) {
99    STATIC_ASSERT(static_cast<int>(Builtin::kNoBuiltinId) == -1);
100    return static_cast<uint32_t>(maybe_id) <
101           static_cast<uint32_t>(kBuiltinCount);
102  }
103  static constexpr bool IsTier0(Builtin builtin) {
104    return builtin <= kLastTier0 && IsBuiltinId(builtin);
105  }
106
107  static constexpr Builtin FromInt(int id) {
108    DCHECK(IsBuiltinId(id));
109    return static_cast<Builtin>(id);
110  }
111  static constexpr int ToInt(Builtin id) {
112    DCHECK(IsBuiltinId(id));
113    return static_cast<int>(id);
114  }
115
116  // The different builtin kinds are documented in builtins-definitions.h.
117  enum Kind { CPP, TFJ, TFC, TFS, TFH, BCH, ASM };
118
119  static BytecodeOffset GetContinuationBytecodeOffset(Builtin builtin);
120  static Builtin GetBuiltinFromBytecodeOffset(BytecodeOffset);
121
122  static constexpr Builtin GetRecordWriteStub(
123      RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode) {
124    switch (remembered_set_action) {
125      case RememberedSetAction::kEmit:
126        switch (fp_mode) {
127          case SaveFPRegsMode::kIgnore:
128            return Builtin::kRecordWriteEmitRememberedSetIgnoreFP;
129          case SaveFPRegsMode::kSave:
130            return Builtin::kRecordWriteEmitRememberedSetSaveFP;
131        }
132      case RememberedSetAction::kOmit:
133        switch (fp_mode) {
134          case SaveFPRegsMode::kIgnore:
135            return Builtin::kRecordWriteOmitRememberedSetIgnoreFP;
136          case SaveFPRegsMode::kSave:
137            return Builtin::kRecordWriteOmitRememberedSetSaveFP;
138        }
139    }
140  }
141
142  static constexpr Builtin GetEphemeronKeyBarrierStub(SaveFPRegsMode fp_mode) {
143    switch (fp_mode) {
144      case SaveFPRegsMode::kIgnore:
145        return Builtin::kEphemeronKeyBarrierIgnoreFP;
146      case SaveFPRegsMode::kSave:
147        return Builtin::kEphemeronKeyBarrierSaveFP;
148    }
149  }
150
151  // Convenience wrappers.
152  Handle<CodeT> CallFunction(ConvertReceiverMode = ConvertReceiverMode::kAny);
153  Handle<CodeT> Call(ConvertReceiverMode = ConvertReceiverMode::kAny);
154  Handle<CodeT> NonPrimitiveToPrimitive(
155      ToPrimitiveHint hint = ToPrimitiveHint::kDefault);
156  Handle<CodeT> OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint);
157  Handle<CodeT> JSConstructStubGeneric();
158
159  // Used by CreateOffHeapTrampolines in isolate.cc.
160  void set_code(Builtin builtin, CodeT code);
161
162  V8_EXPORT_PRIVATE CodeT code(Builtin builtin);
163  V8_EXPORT_PRIVATE Handle<CodeT> code_handle(Builtin builtin);
164
165  static CallInterfaceDescriptor CallInterfaceDescriptorFor(Builtin builtin);
166  V8_EXPORT_PRIVATE static Callable CallableFor(Isolate* isolate,
167                                                Builtin builtin);
168  static bool HasJSLinkage(Builtin builtin);
169
170  static int GetStackParameterCount(Builtin builtin);
171
172  static const char* name(Builtin builtin);
173
174  // Support for --print-builtin-size and --print-builtin-code.
175  void PrintBuiltinCode();
176  void PrintBuiltinSize();
177
178  // Returns the C++ entry point for builtins implemented in C++, and the null
179  // Address otherwise.
180  static Address CppEntryOf(Builtin builtin);
181
182  static Kind KindOf(Builtin builtin);
183  static const char* KindNameOf(Builtin builtin);
184
185  static bool IsCpp(Builtin builtin);
186
187  // True, iff the given code object is a builtin. Note that this does not
188  // necessarily mean that its kind is Code::BUILTIN.
189  static bool IsBuiltin(const Code code);
190
191  // As above, but safe to access off the main thread since the check is done
192  // by handle location. Similar to Heap::IsRootHandle.
193  bool IsBuiltinHandle(Handle<HeapObject> maybe_code, Builtin* index) const;
194
195  // True, iff the given code object is a builtin with off-heap embedded code.
196  static bool IsIsolateIndependentBuiltin(const Code code);
197
198  // True, iff the given builtin contains no isolate-specific code and can be
199  // embedded into the binary.
200  static constexpr bool kAllBuiltinsAreIsolateIndependent = true;
201  static constexpr bool AllBuiltinsAreIsolateIndependent() {
202    return kAllBuiltinsAreIsolateIndependent;
203  }
204  static constexpr bool IsIsolateIndependent(Builtin builtin) {
205    STATIC_ASSERT(kAllBuiltinsAreIsolateIndependent);
206    return kAllBuiltinsAreIsolateIndependent;
207  }
208
209  static void InitializeIsolateDataTables(Isolate* isolate);
210
211  // Emits a CodeCreateEvent for every builtin.
212  static void EmitCodeCreateEvents(Isolate* isolate);
213
214  bool is_initialized() const { return initialized_; }
215
216  // Used by SetupIsolateDelegate and Deserializer.
217  void MarkInitialized() {
218    DCHECK(!initialized_);
219    initialized_ = true;
220  }
221
222  V8_WARN_UNUSED_RESULT static MaybeHandle<Object> InvokeApiFunction(
223      Isolate* isolate, bool is_construct, Handle<HeapObject> function,
224      Handle<Object> receiver, int argc, Handle<Object> args[],
225      Handle<HeapObject> new_target);
226
227  static void Generate_Adaptor(MacroAssembler* masm, Address builtin_address);
228
229  static void Generate_CEntry(MacroAssembler* masm, int result_size,
230                              SaveFPRegsMode save_doubles, ArgvMode argv_mode,
231                              bool builtin_exit_frame);
232
233  static bool AllowDynamicFunction(Isolate* isolate, Handle<JSFunction> target,
234                                   Handle<JSObject> target_global_proxy);
235
236  // Creates a trampoline code object that jumps to the given off-heap entry.
237  // The result should not be used directly, but only from the related Factory
238  // function.
239  // TODO(delphick): Come up with a better name since it may not generate an
240  // executable trampoline.
241  static Handle<Code> GenerateOffHeapTrampolineFor(
242      Isolate* isolate, Address off_heap_entry, int32_t kind_specific_flags,
243      bool generate_jump_to_instruction_stream);
244
245  // Generate the RelocInfo ByteArray that would be generated for an offheap
246  // trampoline.
247  static Handle<ByteArray> GenerateOffHeapTrampolineRelocInfo(Isolate* isolate);
248
249  // Only builtins with JS linkage should ever need to be called via their
250  // trampoline Code object. The remaining builtins have non-executable Code
251  // objects.
252  static bool CodeObjectIsExecutable(Builtin builtin);
253
254  static bool IsJSEntryVariant(Builtin builtin) {
255    switch (builtin) {
256      case Builtin::kJSEntry:
257      case Builtin::kJSConstructEntry:
258      case Builtin::kJSRunMicrotasksEntry:
259        return true;
260      default:
261        return false;
262    }
263    UNREACHABLE();
264  }
265
266  int js_entry_handler_offset() const {
267    DCHECK_NE(js_entry_handler_offset_, 0);
268    return js_entry_handler_offset_;
269  }
270
271  void SetJSEntryHandlerOffset(int offset) {
272    // Check the stored offset is either uninitialized or unchanged (we
273    // generate multiple variants of this builtin but they should all have the
274    // same handler offset).
275    CHECK(js_entry_handler_offset_ == 0 || js_entry_handler_offset_ == offset);
276    js_entry_handler_offset_ = offset;
277  }
278
279  // Returns given builtin's slot in the main builtin table.
280  FullObjectSlot builtin_slot(Builtin builtin);
281  // Returns given builtin's slot in the tier0 builtin table.
282  FullObjectSlot builtin_tier0_slot(Builtin builtin);
283
284 private:
285  static void Generate_CallFunction(MacroAssembler* masm,
286                                    ConvertReceiverMode mode);
287
288  static void Generate_CallBoundFunctionImpl(MacroAssembler* masm);
289
290  static void Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode);
291
292  enum class CallOrConstructMode { kCall, kConstruct };
293  static void Generate_CallOrConstructVarargs(MacroAssembler* masm,
294                                              Handle<CodeT> code);
295  static void Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
296                                                     CallOrConstructMode mode,
297                                                     Handle<CodeT> code);
298
299  static void Generate_InterpreterPushArgsThenCallImpl(
300      MacroAssembler* masm, ConvertReceiverMode receiver_mode,
301      InterpreterPushArgsMode mode);
302
303  static void Generate_InterpreterPushArgsThenConstructImpl(
304      MacroAssembler* masm, InterpreterPushArgsMode mode);
305
306#define DECLARE_ASM(Name, ...) \
307  static void Generate_##Name(MacroAssembler* masm);
308#define DECLARE_TF(Name, ...) \
309  static void Generate_##Name(compiler::CodeAssemblerState* state);
310
311  BUILTIN_LIST(IGNORE_BUILTIN, DECLARE_TF, DECLARE_TF, DECLARE_TF, DECLARE_TF,
312               IGNORE_BUILTIN, DECLARE_ASM)
313
314#undef DECLARE_ASM
315#undef DECLARE_TF
316
317  Isolate* isolate_;
318  bool initialized_ = false;
319
320  // Stores the offset of exception handler entry point (the handler_entry
321  // label) in JSEntry and its variants. It's used to generate the handler table
322  // during codegen (mksnapshot-only).
323  int js_entry_handler_offset_ = 0;
324
325  friend class SetupIsolateDelegate;
326};
327
328V8_INLINE constexpr bool IsInterpreterTrampolineBuiltin(Builtin builtin_id) {
329  // Check for kNoBuiltinId first to abort early when the current Code object
330  // is not a builtin.
331  return builtin_id != Builtin::kNoBuiltinId &&
332         (builtin_id == Builtin::kInterpreterEntryTrampoline ||
333          builtin_id == Builtin::kInterpreterEnterAtBytecode ||
334          builtin_id == Builtin::kInterpreterEnterAtNextBytecode);
335}
336
337V8_INLINE constexpr bool IsBaselineTrampolineBuiltin(Builtin builtin_id) {
338  // Check for kNoBuiltinId first to abort early when the current Code object
339  // is not a builtin.
340  return builtin_id != Builtin::kNoBuiltinId &&
341         (builtin_id == Builtin::kBaselineOutOfLinePrologue ||
342          builtin_id == Builtin::kBaselineOrInterpreterEnterAtBytecode ||
343          builtin_id == Builtin::kBaselineOrInterpreterEnterAtNextBytecode);
344}
345
346Builtin ExampleBuiltinForTorqueFunctionPointerType(
347    size_t function_pointer_type_id);
348
349}  // namespace internal
350}  // namespace v8
351
352#endif  // V8_BUILTINS_BUILTINS_H_
353