• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
12 namespace v8 {
13 namespace internal {
14 
15 class ByteArray;
16 class CallInterfaceDescriptor;
17 class Callable;
18 template <typename T>
19 class Handle;
20 class Isolate;
21 
22 // Forward declarations.
23 class BytecodeOffset;
24 class RootVisitor;
25 enum class InterpreterPushArgsMode : unsigned;
26 namespace compiler {
27 class CodeAssemblerState;
28 }  // namespace compiler
29 
30 template <typename T>
FirstFromVarArgs(T x,...)31 static 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 
39 enum 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 
52 V8_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 
57 V8_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 
62 class Builtins {
63  public:
Builtins(Isolate * isolate)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 
IsBuiltinId(Builtin builtin)95   static constexpr bool IsBuiltinId(Builtin builtin) {
96     return builtin != Builtin::kNoBuiltinId;
97   }
IsBuiltinId(int maybe_id)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   }
IsTier0(Builtin builtin)103   static constexpr bool IsTier0(Builtin builtin) {
104     return builtin <= kLastTier0 && IsBuiltinId(builtin);
105   }
106 
FromInt(int id)107   static constexpr Builtin FromInt(int id) {
108     DCHECK(IsBuiltinId(id));
109     return static_cast<Builtin>(id);
110   }
ToInt(Builtin id)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 
GetRecordWriteStub(RememberedSetAction remembered_set_action,SaveFPRegsMode fp_mode)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 
GetEphemeronKeyBarrierStub(SaveFPRegsMode fp_mode)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;
AllBuiltinsAreIsolateIndependent()201   static constexpr bool AllBuiltinsAreIsolateIndependent() {
202     return kAllBuiltinsAreIsolateIndependent;
203   }
IsIsolateIndependent(Builtin builtin)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 
is_initialized()214   bool is_initialized() const { return initialized_; }
215 
216   // Used by SetupIsolateDelegate and Deserializer.
MarkInitialized()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 
IsJSEntryVariant(Builtin builtin)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 
js_entry_handler_offset()266   int js_entry_handler_offset() const {
267     DCHECK_NE(js_entry_handler_offset_, 0);
268     return js_entry_handler_offset_;
269   }
270 
SetJSEntryHandlerOffset(int offset)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 
328 V8_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 
337 V8_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 
346 Builtin ExampleBuiltinForTorqueFunctionPointerType(
347     size_t function_pointer_type_id);
348 
349 }  // namespace internal
350 }  // namespace v8
351 
352 #endif  // V8_BUILTINS_BUILTINS_H_
353