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