summaryrefslogtreecommitdiff
path: root/deps/v8/src/builtins/builtins.h
blob: c3935b53d01679220367daebcce948532e515c7f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
// Copyright 2011 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_BUILTINS_BUILTINS_H_
#define V8_BUILTINS_BUILTINS_H_

#include "src/base/flags.h"
#include "src/builtins/builtins-definitions.h"
#include "src/common/globals.h"

namespace v8 {
namespace internal {

class ByteArray;
class CallInterfaceDescriptor;
class Callable;
template <typename T>
class Handle;
class Isolate;

// Forward declarations.
class BytecodeOffset;
class RootVisitor;
enum class InterpreterPushArgsMode : unsigned;
namespace compiler {
class CodeAssemblerState;
}  // namespace compiler

template <typename T>
static constexpr T FirstFromVarArgs(T x, ...) noexcept {
  return x;
}

// Convenience macro to avoid generating named accessors for all builtins.
#define BUILTIN_CODE(isolate, name) \
  (isolate)->builtins()->code_handle(i::Builtin::k##name)

enum class Builtin : int32_t {
  kNoBuiltinId = -1,
#define DEF_ENUM(Name, ...) k##Name,
  BUILTIN_LIST(DEF_ENUM, DEF_ENUM, DEF_ENUM, DEF_ENUM, DEF_ENUM, DEF_ENUM,
               DEF_ENUM)
#undef DEF_ENUM
#define EXTRACT_NAME(Name, ...) k##Name,
  // Define kFirstBytecodeHandler,
  kFirstBytecodeHandler =
      FirstFromVarArgs(BUILTIN_LIST_BYTECODE_HANDLERS(EXTRACT_NAME) 0)
#undef EXTRACT_NAME
};

V8_INLINE constexpr bool operator<(Builtin a, Builtin b) {
  using type = typename std::underlying_type<Builtin>::type;
  return static_cast<type>(a) < static_cast<type>(b);
}

V8_INLINE Builtin operator++(Builtin& builtin) {
  using type = typename std::underlying_type<Builtin>::type;
  return builtin = static_cast<Builtin>(static_cast<type>(builtin) + 1);
}

class Builtins {
 public:
  explicit Builtins(Isolate* isolate) : isolate_(isolate) {}

  Builtins(const Builtins&) = delete;
  Builtins& operator=(const Builtins&) = delete;

  void TearDown();

  // Disassembler support.
  const char* Lookup(Address pc);

#define ADD_ONE(Name, ...) +1
  static constexpr int kBuiltinCount = 0 BUILTIN_LIST(
      ADD_ONE, ADD_ONE, ADD_ONE, ADD_ONE, ADD_ONE, ADD_ONE, ADD_ONE);
  static constexpr int kBuiltinTier0Count = 0 BUILTIN_LIST_TIER0(
      ADD_ONE, ADD_ONE, ADD_ONE, ADD_ONE, ADD_ONE, ADD_ONE, ADD_ONE);
#undef ADD_ONE

  static constexpr Builtin kFirst = static_cast<Builtin>(0);
  static constexpr Builtin kLast = static_cast<Builtin>(kBuiltinCount - 1);
  static constexpr Builtin kLastTier0 =
      static_cast<Builtin>(kBuiltinTier0Count - 1);

  static constexpr int kFirstWideBytecodeHandler =
      static_cast<int>(Builtin::kFirstBytecodeHandler) +
      kNumberOfBytecodeHandlers;
  static constexpr int kFirstExtraWideBytecodeHandler =
      kFirstWideBytecodeHandler + kNumberOfWideBytecodeHandlers;
  static constexpr int kLastBytecodeHandlerPlusOne =
      kFirstExtraWideBytecodeHandler + kNumberOfWideBytecodeHandlers;
  static_assert(kLastBytecodeHandlerPlusOne == kBuiltinCount);

  static constexpr bool IsBuiltinId(Builtin builtin) {
    return builtin != Builtin::kNoBuiltinId;
  }
  static constexpr bool IsBuiltinId(int maybe_id) {
    static_assert(static_cast<int>(Builtin::kNoBuiltinId) == -1);
    return static_cast<uint32_t>(maybe_id) <
           static_cast<uint32_t>(kBuiltinCount);
  }
  static constexpr bool IsTier0(Builtin builtin) {
    return builtin <= kLastTier0 && IsBuiltinId(builtin);
  }

  static constexpr Builtin FromInt(int id) {
    DCHECK(IsBuiltinId(id));
    return static_cast<Builtin>(id);
  }
  static constexpr int ToInt(Builtin id) {
    DCHECK(IsBuiltinId(id));
    return static_cast<int>(id);
  }

  // The different builtin kinds are documented in builtins-definitions.h.
  enum Kind { CPP, TFJ, TFC, TFS, TFH, BCH, ASM };

  static BytecodeOffset GetContinuationBytecodeOffset(Builtin builtin);
  static Builtin GetBuiltinFromBytecodeOffset(BytecodeOffset);

  static constexpr Builtin GetRecordWriteStub(SaveFPRegsMode fp_mode) {
    switch (fp_mode) {
      case SaveFPRegsMode::kIgnore:
        return Builtin::kRecordWriteIgnoreFP;
      case SaveFPRegsMode::kSave:
        return Builtin::kRecordWriteSaveFP;
    }
  }

  static constexpr Builtin GetEphemeronKeyBarrierStub(SaveFPRegsMode fp_mode) {
    switch (fp_mode) {
      case SaveFPRegsMode::kIgnore:
        return Builtin::kEphemeronKeyBarrierIgnoreFP;
      case SaveFPRegsMode::kSave:
        return Builtin::kEphemeronKeyBarrierSaveFP;
    }
  }

  // Convenience wrappers.
  Handle<CodeT> CallFunction(ConvertReceiverMode = ConvertReceiverMode::kAny);
  Handle<CodeT> Call(ConvertReceiverMode = ConvertReceiverMode::kAny);
  Handle<CodeT> NonPrimitiveToPrimitive(
      ToPrimitiveHint hint = ToPrimitiveHint::kDefault);
  Handle<CodeT> OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint);

  // Used by CreateOffHeapTrampolines in isolate.cc.
  void set_code(Builtin builtin, CodeT code);

  V8_EXPORT_PRIVATE CodeT code(Builtin builtin);
  V8_EXPORT_PRIVATE Handle<CodeT> code_handle(Builtin builtin);

  static CallInterfaceDescriptor CallInterfaceDescriptorFor(Builtin builtin);
  V8_EXPORT_PRIVATE static Callable CallableFor(Isolate* isolate,
                                                Builtin builtin);
  static bool HasJSLinkage(Builtin builtin);

  static int GetStackParameterCount(Builtin builtin);

  V8_EXPORT_PRIVATE static const char* name(Builtin builtin);

  // Support for --print-builtin-size and --print-builtin-code.
  void PrintBuiltinCode();
  void PrintBuiltinSize();

  // Returns the C++ entry point for builtins implemented in C++, and the null
  // Address otherwise.
  static Address CppEntryOf(Builtin builtin);

  static Kind KindOf(Builtin builtin);
  static const char* KindNameOf(Builtin builtin);

  static bool IsCpp(Builtin builtin);

  // True, iff the given code object is a builtin. Note that this does not
  // necessarily mean that its kind is Code::BUILTIN.
  static bool IsBuiltin(const Code code);

  // As above, but safe to access off the main thread since the check is done
  // by handle location. Similar to Heap::IsRootHandle.
  bool IsBuiltinHandle(Handle<HeapObject> maybe_code, Builtin* index) const;

  // True, iff the given builtin contains no isolate-specific code and can be
  // embedded into the binary.
  static constexpr bool kAllBuiltinsAreIsolateIndependent = true;
  static constexpr bool AllBuiltinsAreIsolateIndependent() {
    return kAllBuiltinsAreIsolateIndependent;
  }
  static constexpr bool IsIsolateIndependent(Builtin builtin) {
    static_assert(kAllBuiltinsAreIsolateIndependent);
    return kAllBuiltinsAreIsolateIndependent;
  }

  // True, iff the given code object is a builtin with off-heap embedded code.
  template <typename CodeOrCodeT>
  static bool IsIsolateIndependentBuiltin(CodeOrCodeT code) {
    Builtin builtin = code.builtin_id();
    return Builtins::IsBuiltinId(builtin) &&
           Builtins::IsIsolateIndependent(builtin);
  }

  static void InitializeIsolateDataTables(Isolate* isolate);

  // Emits a CodeCreateEvent for every builtin.
  static void EmitCodeCreateEvents(Isolate* isolate);

  bool is_initialized() const { return initialized_; }

  // Used by SetupIsolateDelegate and Deserializer.
  void MarkInitialized() {
    DCHECK(!initialized_);
    initialized_ = true;
  }

  V8_WARN_UNUSED_RESULT static MaybeHandle<Object> InvokeApiFunction(
      Isolate* isolate, bool is_construct,
      Handle<FunctionTemplateInfo> function, Handle<Object> receiver, int argc,
      Handle<Object> args[], Handle<HeapObject> new_target);

  static void Generate_Adaptor(MacroAssembler* masm, Address builtin_address);

  static void Generate_CEntry(MacroAssembler* masm, int result_size,
                              SaveFPRegsMode save_doubles, ArgvMode argv_mode,
                              bool builtin_exit_frame);

  static bool AllowDynamicFunction(Isolate* isolate, Handle<JSFunction> target,
                                   Handle<JSObject> target_global_proxy);

  // Creates a trampoline code object that jumps to the given off-heap entry.
  // The result should not be used directly, but only from the related Factory
  // function.
  // TODO(delphick): Come up with a better name since it may not generate an
  // executable trampoline.
  static Handle<Code> GenerateOffHeapTrampolineFor(
      Isolate* isolate, Address off_heap_entry, int32_t kind_specific_flags,
      bool generate_jump_to_instruction_stream);

  // Generate the RelocInfo ByteArray that would be generated for an offheap
  // trampoline.
  static Handle<ByteArray> GenerateOffHeapTrampolineRelocInfo(Isolate* isolate);

  // Creates a copy of InterpreterEntryTrampolineForProfiling in the code space.
  static Handle<Code> CreateInterpreterEntryTrampolineForProfiling(
      Isolate* isolate);

  // Only builtins with JS linkage should ever need to be called via their
  // trampoline Code object. The remaining builtins have non-executable Code
  // objects.
  static bool CodeObjectIsExecutable(Builtin builtin);

  static bool IsJSEntryVariant(Builtin builtin) {
    switch (builtin) {
      case Builtin::kJSEntry:
      case Builtin::kJSConstructEntry:
      case Builtin::kJSRunMicrotasksEntry:
        return true;
      default:
        return false;
    }
    UNREACHABLE();
  }

  int js_entry_handler_offset() const {
    DCHECK_NE(js_entry_handler_offset_, 0);
    return js_entry_handler_offset_;
  }

  void SetJSEntryHandlerOffset(int offset) {
    // Check the stored offset is either uninitialized or unchanged (we
    // generate multiple variants of this builtin but they should all have the
    // same handler offset).
    CHECK(js_entry_handler_offset_ == 0 || js_entry_handler_offset_ == offset);
    js_entry_handler_offset_ = offset;
  }

  // Returns given builtin's slot in the main builtin table.
  FullObjectSlot builtin_slot(Builtin builtin);
  // Returns given builtin's slot in the tier0 builtin table.
  FullObjectSlot builtin_tier0_slot(Builtin builtin);

 private:
  static void Generate_CallFunction(MacroAssembler* masm,
                                    ConvertReceiverMode mode);

  static void Generate_CallBoundFunctionImpl(MacroAssembler* masm);

  static void Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode);

  enum class CallOrConstructMode { kCall, kConstruct };
  static void Generate_CallOrConstructVarargs(MacroAssembler* masm,
                                              Handle<CodeT> code);
  static void Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
                                                     CallOrConstructMode mode,
                                                     Handle<CodeT> code);

  enum class InterpreterEntryTrampolineMode {
    // The version of InterpreterEntryTrampoline used by default.
    kDefault,
    // The position independent version of InterpreterEntryTrampoline used as
    // a template to create copies of the builtin at runtime. The copies are
    // used to create better profiling information for ticks in bytecode
    // execution. See v8_flags.interpreted_frames_native_stack for details.
    kForProfiling
  };
  static void Generate_InterpreterEntryTrampoline(
      MacroAssembler* masm, InterpreterEntryTrampolineMode mode);

  static void Generate_InterpreterPushArgsThenCallImpl(
      MacroAssembler* masm, ConvertReceiverMode receiver_mode,
      InterpreterPushArgsMode mode);

  static void Generate_InterpreterPushArgsThenConstructImpl(
      MacroAssembler* masm, InterpreterPushArgsMode mode);

#define DECLARE_ASM(Name, ...) \
  static void Generate_##Name(MacroAssembler* masm);
#define DECLARE_TF(Name, ...) \
  static void Generate_##Name(compiler::CodeAssemblerState* state);

  BUILTIN_LIST(IGNORE_BUILTIN, DECLARE_TF, DECLARE_TF, DECLARE_TF, DECLARE_TF,
               IGNORE_BUILTIN, DECLARE_ASM)

#undef DECLARE_ASM
#undef DECLARE_TF

  Isolate* isolate_;
  bool initialized_ = false;

  // Stores the offset of exception handler entry point (the handler_entry
  // label) in JSEntry and its variants. It's used to generate the handler table
  // during codegen (mksnapshot-only).
  int js_entry_handler_offset_ = 0;

  friend class SetupIsolateDelegate;
};

V8_INLINE constexpr bool IsInterpreterTrampolineBuiltin(Builtin builtin_id) {
  // Check for kNoBuiltinId first to abort early when the current Code object
  // is not a builtin.
  return builtin_id != Builtin::kNoBuiltinId &&
         (builtin_id == Builtin::kInterpreterEntryTrampoline ||
          builtin_id == Builtin::kInterpreterEnterAtBytecode ||
          builtin_id == Builtin::kInterpreterEnterAtNextBytecode);
}

V8_INLINE constexpr bool IsBaselineTrampolineBuiltin(Builtin builtin_id) {
  // Check for kNoBuiltinId first to abort early when the current Code object
  // is not a builtin.
  return builtin_id != Builtin::kNoBuiltinId &&
         (builtin_id == Builtin::kBaselineOutOfLinePrologue ||
          builtin_id == Builtin::kBaselineOutOfLinePrologueDeopt ||
          builtin_id == Builtin::kBaselineOrInterpreterEnterAtBytecode ||
          builtin_id == Builtin::kBaselineOrInterpreterEnterAtNextBytecode);
}

Builtin ExampleBuiltinForTorqueFunctionPointerType(
    size_t function_pointer_type_id);

}  // namespace internal
}  // namespace v8

#endif  // V8_BUILTINS_BUILTINS_H_