builtins.h 12.7 KB
Newer Older
danno@chromium.org's avatar
danno@chromium.org committed
1
// Copyright 2011 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5 6
#ifndef V8_BUILTINS_BUILTINS_H_
#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

12 13
namespace v8 {
namespace internal {
14

15
class ByteArray;
16
class CallInterfaceDescriptor;
17
class Callable;
marja's avatar
marja committed
18 19 20 21
template <typename T>
class Handle;
class Isolate;

22
// Forward declarations.
23
class BytecodeOffset;
24
class RootVisitor;
25
enum class InterpreterPushArgsMode : unsigned;
26 27
namespace compiler {
class CodeAssemblerState;
28
}  // namespace compiler
29

30 31 32 33 34
template <typename T>
static constexpr T FirstFromVarArgs(T x, ...) noexcept {
  return x;
}

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

39
enum class Builtin : int32_t {
40 41 42 43 44 45 46 47 48 49 50
  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
};
51

52 53 54 55 56 57 58 59 60 61
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);
}

62
class Builtins {
63
 public:
64
  explicit Builtins(Isolate* isolate) : isolate_(isolate) {}
65

66 67 68
  Builtins(const Builtins&) = delete;
  Builtins& operator=(const Builtins&) = delete;

69
  void TearDown();
70 71

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

74 75 76
#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);
77 78
  static constexpr int kBuiltinTier0Count = 0 BUILTIN_LIST_TIER0(
      ADD_ONE, ADD_ONE, ADD_ONE, ADD_ONE, ADD_ONE, ADD_ONE, ADD_ONE);
79
#undef ADD_ONE
80

81 82
  static constexpr Builtin kFirst = static_cast<Builtin>(0);
  static constexpr Builtin kLast = static_cast<Builtin>(kBuiltinCount - 1);
83 84
  static constexpr Builtin kLastTier0 =
      static_cast<Builtin>(kBuiltinTier0Count - 1);
85

86
  static constexpr int kFirstWideBytecodeHandler =
87 88
      static_cast<int>(Builtin::kFirstBytecodeHandler) +
      kNumberOfBytecodeHandlers;
89 90 91 92
  static constexpr int kFirstExtraWideBytecodeHandler =
      kFirstWideBytecodeHandler + kNumberOfWideBytecodeHandlers;
  static constexpr int kLastBytecodeHandlerPlusOne =
      kFirstExtraWideBytecodeHandler + kNumberOfWideBytecodeHandlers;
93
  STATIC_ASSERT(kLastBytecodeHandlerPlusOne == kBuiltinCount);
94

95 96 97
  static constexpr bool IsBuiltinId(Builtin builtin) {
    return builtin != Builtin::kNoBuiltinId;
  }
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 104 105
  static constexpr bool IsTier0(Builtin builtin) {
    return builtin <= kLastTier0 && IsBuiltinId(builtin);
  }
106

107 108 109 110
  static constexpr Builtin FromInt(int id) {
    DCHECK(IsBuiltinId(id));
    return static_cast<Builtin>(id);
  }
111 112 113 114
  static constexpr int ToInt(Builtin id) {
    DCHECK(IsBuiltinId(id));
    return static_cast<int>(id);
  }
115

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

119 120
  static BytecodeOffset GetContinuationBytecodeOffset(Builtin builtin);
  static Builtin GetBuiltinFromBytecodeOffset(BytecodeOffset);
121

122 123
  static constexpr Builtin GetRecordWriteStub(
      RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode) {
124 125 126 127
    switch (remembered_set_action) {
      case RememberedSetAction::kEmit:
        switch (fp_mode) {
          case SaveFPRegsMode::kIgnore:
128
            return Builtin::kRecordWriteEmitRememberedSetIgnoreFP;
129
          case SaveFPRegsMode::kSave:
130
            return Builtin::kRecordWriteEmitRememberedSetSaveFP;
131 132 133 134
        }
      case RememberedSetAction::kOmit:
        switch (fp_mode) {
          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 144
    switch (fp_mode) {
      case SaveFPRegsMode::kIgnore:
145
        return Builtin::kEphemeronKeyBarrierIgnoreFP;
146
      case SaveFPRegsMode::kSave:
147
        return Builtin::kEphemeronKeyBarrierSaveFP;
148 149 150
    }
  }

151
  // Convenience wrappers.
152 153 154
  Handle<CodeT> CallFunction(ConvertReceiverMode = ConvertReceiverMode::kAny);
  Handle<CodeT> Call(ConvertReceiverMode = ConvertReceiverMode::kAny);
  Handle<CodeT> NonPrimitiveToPrimitive(
155
      ToPrimitiveHint hint = ToPrimitiveHint::kDefault);
156 157
  Handle<CodeT> OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint);
  Handle<CodeT> JSConstructStubGeneric();
158

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

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

165 166 167
  static CallInterfaceDescriptor CallInterfaceDescriptorFor(Builtin builtin);
  V8_EXPORT_PRIVATE static Callable CallableFor(Isolate* isolate,
                                                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 175 176 177
  // Support for --print-builtin-size and --print-builtin-code.
  void PrintBuiltinCode();
  void PrintBuiltinSize();

178 179
  // Returns the C++ entry point for builtins implemented in C++, and the null
  // 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 188
  // True, iff the given code object is a builtin. Note that this does not
  // necessarily mean that its kind is Code::BUILTIN.
189
  static bool IsBuiltin(const Code code);
190

191 192
  // As above, but safe to access off the main thread since the check is done
  // 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 199
  // True, iff the given builtin contains no isolate-specific code and can be
  // embedded into the binary.
200 201 202 203
  static constexpr bool kAllBuiltinsAreIsolateIndependent = true;
  static constexpr bool AllBuiltinsAreIsolateIndependent() {
    return kAllBuiltinsAreIsolateIndependent;
  }
204
  static constexpr bool IsIsolateIndependent(Builtin builtin) {
205 206 207
    STATIC_ASSERT(kAllBuiltinsAreIsolateIndependent);
    return kAllBuiltinsAreIsolateIndependent;
  }
208

209
  static void InitializeIsolateDataTables(Isolate* isolate);
210

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

214 215
  bool is_initialized() const { return initialized_; }

216 217 218 219 220 221
  // Used by SetupIsolateDelegate and Deserializer.
  void MarkInitialized() {
    DCHECK(!initialized_);
    initialized_ = true;
  }

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

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

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

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

236 237 238
  // 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.
239 240 241 242 243
  // 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);
244

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

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

254 255 256 257 258
  static bool IsJSEntryVariant(Builtin builtin) {
    switch (builtin) {
      case Builtin::kJSEntry:
      case Builtin::kJSConstructEntry:
      case Builtin::kJSRunMicrotasksEntry:
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
        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;
  }

279 280 281 282 283
  // 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);

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 300
  static void Generate_InterpreterPushArgsThenCallImpl(
      MacroAssembler* masm, ConvertReceiverMode receiver_mode,
301
      InterpreterPushArgsMode mode);
302

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

306 307
  template <class Descriptor>
  static void Generate_DynamicCheckMapsTrampoline(MacroAssembler* masm,
308
                                                  Handle<CodeT> builtin_target);
309

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

315 316
  BUILTIN_LIST(IGNORE_BUILTIN, DECLARE_TF, DECLARE_TF, DECLARE_TF, DECLARE_TF,
               IGNORE_BUILTIN, DECLARE_ASM)
317

318 319
#undef DECLARE_ASM
#undef DECLARE_TF
320

321 322
  Isolate* isolate_;
  bool initialized_ = false;
323

324 325 326 327 328
  // 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;

329
  friend class SetupIsolateDelegate;
330 331
};

332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
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::kBaselineOrInterpreterEnterAtBytecode ||
          builtin_id == Builtin::kBaselineOrInterpreterEnterAtNextBytecode);
}

350
Builtin ExampleBuiltinForTorqueFunctionPointerType(
351 352
    size_t function_pointer_type_id);

353 354
}  // namespace internal
}  // namespace v8
355

356
#endif  // V8_BUILTINS_BUILTINS_H_