• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 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 #include "src/builtins/builtins.h"
6 
7 #include "src/api/api-inl.h"
8 #include "src/builtins/builtins-descriptors.h"
9 #include "src/codegen/assembler-inl.h"
10 #include "src/codegen/callable.h"
11 #include "src/codegen/macro-assembler-inl.h"
12 #include "src/codegen/macro-assembler.h"
13 #include "src/diagnostics/code-tracer.h"
14 #include "src/execution/isolate.h"
15 #include "src/interpreter/bytecodes.h"
16 #include "src/logging/code-events.h"  // For CodeCreateEvent.
17 #include "src/logging/log.h"          // For Logger.
18 #include "src/objects/fixed-array.h"
19 #include "src/objects/objects-inl.h"
20 #include "src/objects/visitors.h"
21 #include "src/snapshot/embedded/embedded-data-inl.h"
22 #include "src/utils/ostreams.h"
23 
24 namespace v8 {
25 namespace internal {
26 
27 // Forward declarations for C++ builtins.
28 #define FORWARD_DECLARE(Name) \
29   Address Builtin_##Name(int argc, Address* args, Isolate* isolate);
30 BUILTIN_LIST_C(FORWARD_DECLARE)
31 #undef FORWARD_DECLARE
32 
33 namespace {
34 
35 // TODO(jgruber): Pack in CallDescriptors::Key.
36 struct BuiltinMetadata {
37   const char* name;
38   Builtins::Kind kind;
39 
40   struct BytecodeAndScale {
41     interpreter::Bytecode bytecode : 8;
42     interpreter::OperandScale scale : 8;
43   };
44 
45   STATIC_ASSERT(sizeof(interpreter::Bytecode) == 1);
46   STATIC_ASSERT(sizeof(interpreter::OperandScale) == 1);
47   STATIC_ASSERT(sizeof(BytecodeAndScale) <= sizeof(Address));
48 
49   // The `data` field has kind-specific contents.
50   union KindSpecificData {
51     // TODO(jgruber): Union constructors are needed since C++11 does not support
52     // designated initializers (e.g.: {.parameter_count = count}). Update once
53     // we're at C++20 :)
54     // The constructors are marked constexpr to avoid the need for a static
55     // initializer for builtins.cc (see check-static-initializers.sh).
KindSpecificData()56     constexpr KindSpecificData() : cpp_entry(kNullAddress) {}
KindSpecificData(Address cpp_entry)57     constexpr KindSpecificData(Address cpp_entry) : cpp_entry(cpp_entry) {}
KindSpecificData(int parameter_count,int)58     constexpr KindSpecificData(int parameter_count,
59                                int /* To disambiguate from above */)
60         : parameter_count(static_cast<int16_t>(parameter_count)) {}
KindSpecificData(interpreter::Bytecode bytecode,interpreter::OperandScale scale)61     constexpr KindSpecificData(interpreter::Bytecode bytecode,
62                                interpreter::OperandScale scale)
63         : bytecode_and_scale{bytecode, scale} {}
64     Address cpp_entry;                    // For CPP builtins.
65     int16_t parameter_count;              // For TFJ builtins.
66     BytecodeAndScale bytecode_and_scale;  // For BCH builtins.
67   } data;
68 };
69 
70 #define DECL_CPP(Name, ...) \
71   {#Name, Builtins::CPP, {FUNCTION_ADDR(Builtin_##Name)}},
72 #define DECL_TFJ(Name, Count, ...) {#Name, Builtins::TFJ, {Count, 0}},
73 #define DECL_TFC(Name, ...) {#Name, Builtins::TFC, {}},
74 #define DECL_TFS(Name, ...) {#Name, Builtins::TFS, {}},
75 #define DECL_TFH(Name, ...) {#Name, Builtins::TFH, {}},
76 #define DECL_BCH(Name, OperandScale, Bytecode) \
77   {#Name, Builtins::BCH, {Bytecode, OperandScale}},
78 #define DECL_ASM(Name, ...) {#Name, Builtins::ASM, {}},
79 const BuiltinMetadata builtin_metadata[] = {BUILTIN_LIST(
80     DECL_CPP, DECL_TFJ, DECL_TFC, DECL_TFS, DECL_TFH, DECL_BCH, DECL_ASM)};
81 #undef DECL_CPP
82 #undef DECL_TFJ
83 #undef DECL_TFC
84 #undef DECL_TFS
85 #undef DECL_TFH
86 #undef DECL_BCH
87 #undef DECL_ASM
88 
89 }  // namespace
90 
GetContinuationBytecodeOffset(Builtin builtin)91 BytecodeOffset Builtins::GetContinuationBytecodeOffset(Builtin builtin) {
92   DCHECK(Builtins::KindOf(builtin) == TFJ || Builtins::KindOf(builtin) == TFC ||
93          Builtins::KindOf(builtin) == TFS);
94   return BytecodeOffset(BytecodeOffset::kFirstBuiltinContinuationId +
95                         ToInt(builtin));
96 }
97 
GetBuiltinFromBytecodeOffset(BytecodeOffset id)98 Builtin Builtins::GetBuiltinFromBytecodeOffset(BytecodeOffset id) {
99   Builtin builtin = Builtins::FromInt(
100       id.ToInt() - BytecodeOffset::kFirstBuiltinContinuationId);
101   DCHECK(Builtins::KindOf(builtin) == TFJ || Builtins::KindOf(builtin) == TFC ||
102          Builtins::KindOf(builtin) == TFS);
103   return builtin;
104 }
105 
TearDown()106 void Builtins::TearDown() { initialized_ = false; }
107 
Lookup(Address pc)108 const char* Builtins::Lookup(Address pc) {
109   // Off-heap pc's can be looked up through binary search.
110   Builtin builtin = OffHeapInstructionStream::TryLookupCode(isolate_, pc);
111   if (Builtins::IsBuiltinId(builtin)) return name(builtin);
112 
113   // May be called during initialization (disassembler).
114   if (!initialized_) return nullptr;
115   for (Builtin builtin_ix = Builtins::kFirst; builtin_ix <= Builtins::kLast;
116        ++builtin_ix) {
117     if (FromCodeT(code(builtin_ix)).contains(isolate_, pc)) {
118       return name(builtin_ix);
119     }
120   }
121   return nullptr;
122 }
123 
CallFunction(ConvertReceiverMode mode)124 Handle<CodeT> Builtins::CallFunction(ConvertReceiverMode mode) {
125   switch (mode) {
126     case ConvertReceiverMode::kNullOrUndefined:
127       return code_handle(Builtin::kCallFunction_ReceiverIsNullOrUndefined);
128     case ConvertReceiverMode::kNotNullOrUndefined:
129       return code_handle(Builtin::kCallFunction_ReceiverIsNotNullOrUndefined);
130     case ConvertReceiverMode::kAny:
131       return code_handle(Builtin::kCallFunction_ReceiverIsAny);
132   }
133   UNREACHABLE();
134 }
135 
Call(ConvertReceiverMode mode)136 Handle<CodeT> Builtins::Call(ConvertReceiverMode mode) {
137   switch (mode) {
138     case ConvertReceiverMode::kNullOrUndefined:
139       return code_handle(Builtin::kCall_ReceiverIsNullOrUndefined);
140     case ConvertReceiverMode::kNotNullOrUndefined:
141       return code_handle(Builtin::kCall_ReceiverIsNotNullOrUndefined);
142     case ConvertReceiverMode::kAny:
143       return code_handle(Builtin::kCall_ReceiverIsAny);
144   }
145   UNREACHABLE();
146 }
147 
NonPrimitiveToPrimitive(ToPrimitiveHint hint)148 Handle<CodeT> Builtins::NonPrimitiveToPrimitive(ToPrimitiveHint hint) {
149   switch (hint) {
150     case ToPrimitiveHint::kDefault:
151       return code_handle(Builtin::kNonPrimitiveToPrimitive_Default);
152     case ToPrimitiveHint::kNumber:
153       return code_handle(Builtin::kNonPrimitiveToPrimitive_Number);
154     case ToPrimitiveHint::kString:
155       return code_handle(Builtin::kNonPrimitiveToPrimitive_String);
156   }
157   UNREACHABLE();
158 }
159 
OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint)160 Handle<CodeT> Builtins::OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint) {
161   switch (hint) {
162     case OrdinaryToPrimitiveHint::kNumber:
163       return code_handle(Builtin::kOrdinaryToPrimitive_Number);
164     case OrdinaryToPrimitiveHint::kString:
165       return code_handle(Builtin::kOrdinaryToPrimitive_String);
166   }
167   UNREACHABLE();
168 }
169 
builtin_slot(Builtin builtin)170 FullObjectSlot Builtins::builtin_slot(Builtin builtin) {
171   Address* location = &isolate_->builtin_table()[Builtins::ToInt(builtin)];
172   return FullObjectSlot(location);
173 }
174 
builtin_tier0_slot(Builtin builtin)175 FullObjectSlot Builtins::builtin_tier0_slot(Builtin builtin) {
176   DCHECK(IsTier0(builtin));
177   Address* location =
178       &isolate_->builtin_tier0_table()[Builtins::ToInt(builtin)];
179   return FullObjectSlot(location);
180 }
181 
set_code(Builtin builtin,CodeT code)182 void Builtins::set_code(Builtin builtin, CodeT code) {
183   DCHECK_EQ(builtin, code.builtin_id());
184   if (V8_EXTERNAL_CODE_SPACE_BOOL) {
185     DCHECK_EQ(builtin, FromCodeT(code).builtin_id());
186   }
187   DCHECK(Internals::HasHeapObjectTag(code.ptr()));
188   // The given builtin may be uninitialized thus we cannot check its type here.
189   isolate_->builtin_table()[Builtins::ToInt(builtin)] = code.ptr();
190 }
191 
code(Builtin builtin)192 CodeT Builtins::code(Builtin builtin) {
193   Address ptr = isolate_->builtin_table()[Builtins::ToInt(builtin)];
194   return CodeT::cast(Object(ptr));
195 }
196 
code_handle(Builtin builtin)197 Handle<CodeT> Builtins::code_handle(Builtin builtin) {
198   Address* location = &isolate_->builtin_table()[Builtins::ToInt(builtin)];
199   return Handle<CodeT>(location);
200 }
201 
202 // static
GetStackParameterCount(Builtin builtin)203 int Builtins::GetStackParameterCount(Builtin builtin) {
204   DCHECK(Builtins::KindOf(builtin) == TFJ);
205   return builtin_metadata[ToInt(builtin)].data.parameter_count;
206 }
207 
208 // static
CallInterfaceDescriptorFor(Builtin builtin)209 CallInterfaceDescriptor Builtins::CallInterfaceDescriptorFor(Builtin builtin) {
210   CallDescriptors::Key key;
211   switch (builtin) {
212 // This macro is deliberately crafted so as to emit very little code,
213 // in order to keep binary size of this function under control.
214 #define CASE_OTHER(Name, ...)                          \
215   case Builtin::k##Name: {                             \
216     key = Builtin_##Name##_InterfaceDescriptor::key(); \
217     break;                                             \
218   }
219     BUILTIN_LIST(IGNORE_BUILTIN, IGNORE_BUILTIN, CASE_OTHER, CASE_OTHER,
220                  CASE_OTHER, IGNORE_BUILTIN, CASE_OTHER)
221 #undef CASE_OTHER
222     default:
223       Builtins::Kind kind = Builtins::KindOf(builtin);
224       DCHECK_NE(BCH, kind);
225       if (kind == TFJ || kind == CPP) {
226         return JSTrampolineDescriptor{};
227       }
228       UNREACHABLE();
229   }
230   return CallInterfaceDescriptor{key};
231 }
232 
233 // static
CallableFor(Isolate * isolate,Builtin builtin)234 Callable Builtins::CallableFor(Isolate* isolate, Builtin builtin) {
235   Handle<CodeT> code = isolate->builtins()->code_handle(builtin);
236   return Callable{code, CallInterfaceDescriptorFor(builtin)};
237 }
238 
239 // static
HasJSLinkage(Builtin builtin)240 bool Builtins::HasJSLinkage(Builtin builtin) {
241   DCHECK_NE(BCH, Builtins::KindOf(builtin));
242   return CallInterfaceDescriptorFor(builtin) == JSTrampolineDescriptor{};
243 }
244 
245 // static
name(Builtin builtin)246 const char* Builtins::name(Builtin builtin) {
247   int index = ToInt(builtin);
248   DCHECK(IsBuiltinId(index));
249   return builtin_metadata[index].name;
250 }
251 
PrintBuiltinCode()252 void Builtins::PrintBuiltinCode() {
253   DCHECK(FLAG_print_builtin_code);
254 #ifdef ENABLE_DISASSEMBLER
255   for (Builtin builtin = Builtins::kFirst; builtin <= Builtins::kLast;
256        ++builtin) {
257     const char* builtin_name = name(builtin);
258     if (PassesFilter(base::CStrVector(builtin_name),
259                      base::CStrVector(FLAG_print_builtin_code_filter))) {
260       CodeTracer::Scope trace_scope(isolate_->GetCodeTracer());
261       OFStream os(trace_scope.file());
262       Code builtin_code = FromCodeT(code(builtin));
263       builtin_code.Disassemble(builtin_name, os, isolate_);
264       os << "\n";
265     }
266   }
267 #endif
268 }
269 
PrintBuiltinSize()270 void Builtins::PrintBuiltinSize() {
271   DCHECK(FLAG_print_builtin_size);
272   for (Builtin builtin = Builtins::kFirst; builtin <= Builtins::kLast;
273        ++builtin) {
274     const char* builtin_name = name(builtin);
275     const char* kind = KindNameOf(builtin);
276     Code code = FromCodeT(Builtins::code(builtin));
277     PrintF(stdout, "%s Builtin, %s, %d\n", kind, builtin_name,
278            code.InstructionSize());
279   }
280 }
281 
282 // static
CppEntryOf(Builtin builtin)283 Address Builtins::CppEntryOf(Builtin builtin) {
284   DCHECK(Builtins::IsCpp(builtin));
285   return builtin_metadata[ToInt(builtin)].data.cpp_entry;
286 }
287 
288 // static
IsBuiltin(const Code code)289 bool Builtins::IsBuiltin(const Code code) {
290   return Builtins::IsBuiltinId(code.builtin_id());
291 }
292 
IsBuiltinHandle(Handle<HeapObject> maybe_code,Builtin * builtin) const293 bool Builtins::IsBuiltinHandle(Handle<HeapObject> maybe_code,
294                                Builtin* builtin) const {
295   Address* handle_location = maybe_code.location();
296   Address* builtins_table = isolate_->builtin_table();
297   if (handle_location < builtins_table) return false;
298   Address* builtins_table_end = &builtins_table[Builtins::kBuiltinCount];
299   if (handle_location >= builtins_table_end) return false;
300   *builtin = FromInt(static_cast<int>(handle_location - builtins_table));
301   return true;
302 }
303 
304 // static
IsIsolateIndependentBuiltin(const Code code)305 bool Builtins::IsIsolateIndependentBuiltin(const Code code) {
306   const Builtin builtin = code.builtin_id();
307   return Builtins::IsBuiltinId(builtin) &&
308          Builtins::IsIsolateIndependent(builtin);
309 }
310 
311 // static
InitializeIsolateDataTables(Isolate * isolate)312 void Builtins::InitializeIsolateDataTables(Isolate* isolate) {
313   EmbeddedData embedded_data = EmbeddedData::FromBlob(isolate);
314   IsolateData* isolate_data = isolate->isolate_data();
315 
316   // The entry table.
317   for (Builtin i = Builtins::kFirst; i <= Builtins::kLast; ++i) {
318     DCHECK(Builtins::IsBuiltinId(isolate->builtins()->code(i).builtin_id()));
319     DCHECK(isolate->builtins()->code(i).is_off_heap_trampoline());
320     isolate_data->builtin_entry_table()[ToInt(i)] =
321         embedded_data.InstructionStartOfBuiltin(i);
322   }
323 
324   // T0 tables.
325   for (Builtin i = Builtins::kFirst; i <= Builtins::kLastTier0; ++i) {
326     const int ii = ToInt(i);
327     isolate_data->builtin_tier0_entry_table()[ii] =
328         isolate_data->builtin_entry_table()[ii];
329     isolate_data->builtin_tier0_table()[ii] = isolate_data->builtin_table()[ii];
330   }
331 }
332 
333 // static
EmitCodeCreateEvents(Isolate * isolate)334 void Builtins::EmitCodeCreateEvents(Isolate* isolate) {
335   if (!isolate->logger()->is_listening_to_code_events() &&
336       !isolate->is_profiling()) {
337     return;  // No need to iterate the entire table in this case.
338   }
339 
340   Address* builtins = isolate->builtin_table();
341   int i = 0;
342   HandleScope scope(isolate);
343   for (; i < ToInt(Builtin::kFirstBytecodeHandler); i++) {
344     Code builtin_code = FromCodeT(CodeT::cast(Object(builtins[i])));
345     Handle<AbstractCode> code(AbstractCode::cast(builtin_code), isolate);
346     PROFILE(isolate, CodeCreateEvent(CodeEventListener::BUILTIN_TAG, code,
347                                      Builtins::name(FromInt(i))));
348   }
349 
350   STATIC_ASSERT(kLastBytecodeHandlerPlusOne == kBuiltinCount);
351   for (; i < kBuiltinCount; i++) {
352     Code builtin_code = FromCodeT(CodeT::cast(Object(builtins[i])));
353     Handle<AbstractCode> code(AbstractCode::cast(builtin_code), isolate);
354     interpreter::Bytecode bytecode =
355         builtin_metadata[i].data.bytecode_and_scale.bytecode;
356     interpreter::OperandScale scale =
357         builtin_metadata[i].data.bytecode_and_scale.scale;
358     PROFILE(isolate,
359             CodeCreateEvent(
360                 CodeEventListener::BYTECODE_HANDLER_TAG, code,
361                 interpreter::Bytecodes::ToString(bytecode, scale).c_str()));
362   }
363 }
364 
365 namespace {
366 enum TrampolineType { kAbort, kJump };
367 
368 class OffHeapTrampolineGenerator {
369  public:
OffHeapTrampolineGenerator(Isolate * isolate)370   explicit OffHeapTrampolineGenerator(Isolate* isolate)
371       : isolate_(isolate),
372         masm_(isolate, AssemblerOptions::DefaultForOffHeapTrampoline(isolate),
373               CodeObjectRequired::kYes,
374               ExternalAssemblerBuffer(buffer_, kBufferSize)) {}
375 
Generate(Address off_heap_entry,TrampolineType type)376   CodeDesc Generate(Address off_heap_entry, TrampolineType type) {
377     // Generate replacement code that simply tail-calls the off-heap code.
378     DCHECK(!masm_.has_frame());
379     {
380       FrameScope scope(&masm_, StackFrame::NO_FRAME_TYPE);
381       if (type == TrampolineType::kJump) {
382         masm_.CodeEntry();
383         masm_.JumpToOffHeapInstructionStream(off_heap_entry);
384       } else {
385         DCHECK_EQ(type, TrampolineType::kAbort);
386         masm_.Trap();
387       }
388     }
389 
390     CodeDesc desc;
391     masm_.GetCode(isolate_, &desc);
392     return desc;
393   }
394 
CodeObject()395   Handle<HeapObject> CodeObject() { return masm_.CodeObject(); }
396 
397  private:
398   Isolate* isolate_;
399   // Enough to fit the single jmp.
400   static constexpr int kBufferSize = 256;
401   byte buffer_[kBufferSize];
402   MacroAssembler masm_;
403 };
404 
405 constexpr int OffHeapTrampolineGenerator::kBufferSize;
406 
407 }  // namespace
408 
409 // static
GenerateOffHeapTrampolineFor(Isolate * isolate,Address off_heap_entry,int32_t kind_specfic_flags,bool generate_jump_to_instruction_stream)410 Handle<Code> Builtins::GenerateOffHeapTrampolineFor(
411     Isolate* isolate, Address off_heap_entry, int32_t kind_specfic_flags,
412     bool generate_jump_to_instruction_stream) {
413   DCHECK_NOT_NULL(isolate->embedded_blob_code());
414   DCHECK_NE(0, isolate->embedded_blob_code_size());
415 
416   OffHeapTrampolineGenerator generator(isolate);
417 
418   CodeDesc desc =
419       generator.Generate(off_heap_entry, generate_jump_to_instruction_stream
420                                              ? TrampolineType::kJump
421                                              : TrampolineType::kAbort);
422 
423   return Factory::CodeBuilder(isolate, desc, CodeKind::BUILTIN)
424       .set_kind_specific_flags(kind_specfic_flags)
425       .set_read_only_data_container(!V8_EXTERNAL_CODE_SPACE_BOOL)
426       .set_self_reference(generator.CodeObject())
427       .set_is_executable(generate_jump_to_instruction_stream)
428       .Build();
429 }
430 
431 // static
GenerateOffHeapTrampolineRelocInfo(Isolate * isolate)432 Handle<ByteArray> Builtins::GenerateOffHeapTrampolineRelocInfo(
433     Isolate* isolate) {
434   OffHeapTrampolineGenerator generator(isolate);
435   // Generate a jump to a dummy address as we're not actually interested in the
436   // generated instruction stream.
437   CodeDesc desc = generator.Generate(kNullAddress, TrampolineType::kJump);
438 
439   Handle<ByteArray> reloc_info = isolate->factory()->NewByteArray(
440       desc.reloc_size, AllocationType::kReadOnly);
441   Code::CopyRelocInfoToByteArray(*reloc_info, desc);
442 
443   return reloc_info;
444 }
445 
KindOf(Builtin builtin)446 Builtins::Kind Builtins::KindOf(Builtin builtin) {
447   DCHECK(IsBuiltinId(builtin));
448   return builtin_metadata[ToInt(builtin)].kind;
449 }
450 
451 // static
KindNameOf(Builtin builtin)452 const char* Builtins::KindNameOf(Builtin builtin) {
453   Kind kind = Builtins::KindOf(builtin);
454   // clang-format off
455   switch (kind) {
456     case CPP: return "CPP";
457     case TFJ: return "TFJ";
458     case TFC: return "TFC";
459     case TFS: return "TFS";
460     case TFH: return "TFH";
461     case BCH: return "BCH";
462     case ASM: return "ASM";
463   }
464   // clang-format on
465   UNREACHABLE();
466 }
467 
468 // static
IsCpp(Builtin builtin)469 bool Builtins::IsCpp(Builtin builtin) {
470   return Builtins::KindOf(builtin) == CPP;
471 }
472 
473 // static
AllowDynamicFunction(Isolate * isolate,Handle<JSFunction> target,Handle<JSObject> target_global_proxy)474 bool Builtins::AllowDynamicFunction(Isolate* isolate, Handle<JSFunction> target,
475                                     Handle<JSObject> target_global_proxy) {
476   if (FLAG_allow_unsafe_function_constructor) return true;
477   HandleScopeImplementer* impl = isolate->handle_scope_implementer();
478   Handle<Context> responsible_context = impl->LastEnteredOrMicrotaskContext();
479   // TODO(verwaest): Remove this.
480   if (responsible_context.is_null()) {
481     return true;
482   }
483   if (*responsible_context == target->context()) return true;
484   return isolate->MayAccess(responsible_context, target_global_proxy);
485 }
486 
487 // static
CodeObjectIsExecutable(Builtin builtin)488 bool Builtins::CodeObjectIsExecutable(Builtin builtin) {
489   // If the runtime/optimized code always knows when executing a given builtin
490   // that it is a builtin, then that builtin does not need an executable Code
491   // object. Such Code objects can go in read_only_space (and can even be
492   // smaller with no branch instruction), thus saving memory.
493 
494   // Builtins with JS linkage will always have executable Code objects since
495   // they can be called directly from jitted code with no way of determining
496   // that they are builtins at generation time. E.g.
497   //   f = Array.of;
498   //   f(1, 2, 3);
499   // TODO(delphick): This is probably too loose but for now Wasm can call any JS
500   // linkage builtin via its Code object. Once Wasm is fixed this can either be
501   // tighted or removed completely.
502   if (Builtins::KindOf(builtin) != BCH && HasJSLinkage(builtin)) {
503     return true;
504   }
505 
506   // There are some other non-TF builtins that also have JS linkage like
507   // InterpreterEntryTrampoline which are explicitly allow-listed below.
508   // TODO(delphick): Some of these builtins do not fit with the above, but
509   // currently cause problems if they're not executable. This list should be
510   // pared down as much as possible.
511   switch (builtin) {
512     case Builtin::kInterpreterEntryTrampoline:
513     case Builtin::kCompileLazy:
514     case Builtin::kCompileLazyDeoptimizedCode:
515     case Builtin::kCallFunction_ReceiverIsNullOrUndefined:
516     case Builtin::kCallFunction_ReceiverIsNotNullOrUndefined:
517     case Builtin::kCallFunction_ReceiverIsAny:
518     case Builtin::kCallBoundFunction:
519     case Builtin::kCall_ReceiverIsNullOrUndefined:
520     case Builtin::kCall_ReceiverIsNotNullOrUndefined:
521     case Builtin::kCall_ReceiverIsAny:
522     case Builtin::kHandleApiCall:
523     case Builtin::kInstantiateAsmJs:
524 #if V8_ENABLE_WEBASSEMBLY
525     case Builtin::kGenericJSToWasmWrapper:
526 #endif  // V8_ENABLE_WEBASSEMBLY
527 
528     // TODO(delphick): Remove this when calls to it have the trampoline inlined
529     // or are converted to use kCallBuiltinPointer.
530     case Builtin::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit:
531       return true;
532     default:
533 #if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
534       // TODO(Loongson): Move non-JS linkage builtins code objects into RO_SPACE
535       // caused MIPS platform to crash, and we need some time to handle it. Now
536       // disable this change temporarily on MIPS platform.
537       return true;
538 #else
539       return false;
540 #endif  // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
541   }
542 }
543 
ExampleBuiltinForTorqueFunctionPointerType(size_t function_pointer_type_id)544 Builtin ExampleBuiltinForTorqueFunctionPointerType(
545     size_t function_pointer_type_id) {
546   switch (function_pointer_type_id) {
547 #define FUNCTION_POINTER_ID_CASE(id, name) \
548   case id:                                 \
549     return Builtin::k##name;
550     TORQUE_FUNCTION_POINTER_TYPE_TO_BUILTIN_MAP(FUNCTION_POINTER_ID_CASE)
551 #undef FUNCTION_POINTER_ID_CASE
552     default:
553       UNREACHABLE();
554   }
555 }
556 
557 }  // namespace internal
558 }  // namespace v8
559