5 #include "src/builtins/builtins.h" 7 #include "src/api-inl.h" 8 #include "src/assembler-inl.h" 9 #include "src/builtins/builtins-descriptors.h" 10 #include "src/callable.h" 11 #include "src/code-tracer.h" 12 #include "src/isolate.h" 13 #include "src/macro-assembler.h" 14 #include "src/objects-inl.h" 15 #include "src/objects/fixed-array.h" 16 #include "src/snapshot/embedded-data.h" 17 #include "src/visitors.h" 23 #define FORWARD_DECLARE(Name) \ 24 Object* Builtin_##Name(int argc, Address* args, Isolate* isolate); 25 BUILTIN_LIST_C(FORWARD_DECLARE)
26 #undef FORWARD_DECLARE 31 struct BuiltinMetadata {
36 int8_t parameter_count;
41 #define DECL_CPP(Name, ...) { #Name, Builtins::CPP, \ 42 { FUNCTION_ADDR(Builtin_##Name) }}, 43 #define DECL_API(Name, ...) { #Name, Builtins::API, \ 44 { FUNCTION_ADDR(Builtin_##Name) }}, 45 #ifdef V8_TARGET_BIG_ENDIAN 46 #define DECL_TFJ(Name, Count, ...) { #Name, Builtins::TFJ, \ 47 { static_cast<Address>(static_cast<uintptr_t>( \ 48 Count) << (kBitsPerByte * (kPointerSize - 1))) }}, 50 #define DECL_TFJ(Name, Count, ...) { #Name, Builtins::TFJ, \ 51 { static_cast<Address>(Count) }}, 53 #define DECL_TFC(Name, ...) { #Name, Builtins::TFC, {} }, 54 #define DECL_TFS(Name, ...) { #Name, Builtins::TFS, {} }, 55 #define DECL_TFH(Name, ...) { #Name, Builtins::TFH, {} }, 56 #define DECL_BCH(Name, ...) { #Name, Builtins::BCH, {} }, 57 #define DECL_ASM(Name, ...) { #Name, Builtins::ASM, {} }, 58 const BuiltinMetadata builtin_metadata[] = {
59 BUILTIN_LIST(DECL_CPP, DECL_API, DECL_TFJ, DECL_TFC, DECL_TFS, DECL_TFH,
74 BailoutId Builtins::GetContinuationBailoutId(Name name) {
75 DCHECK(Builtins::KindOf(name) == TFJ || Builtins::KindOf(name) == TFC);
76 return BailoutId(BailoutId::kFirstBuiltinContinuationId + name);
79 Builtins::Name Builtins::GetBuiltinFromBailoutId(BailoutId
id) {
80 int builtin_index =
id.ToInt() - BailoutId::kFirstBuiltinContinuationId;
81 DCHECK(Builtins::KindOf(builtin_index) == TFJ ||
82 Builtins::KindOf(builtin_index) == TFC);
83 return static_cast<Name
>(builtin_index);
86 void Builtins::TearDown() { initialized_ =
false; }
88 const char* Builtins::Lookup(Address pc) {
90 if (FLAG_embedded_builtins) {
91 Code maybe_builtin = InstructionStream::TryLookupCode(isolate_, pc);
92 if (!maybe_builtin.is_null())
return name(maybe_builtin->builtin_index());
97 for (
int i = 0;
i < builtin_count;
i++) {
98 if (isolate_->heap()->builtin(
i)->contains(pc))
return name(
i);
104 Handle<Code> Builtins::NewFunctionContext(ScopeType scope_type) {
105 switch (scope_type) {
106 case ScopeType::EVAL_SCOPE:
107 return builtin_handle(kFastNewFunctionContextEval);
108 case ScopeType::FUNCTION_SCOPE:
109 return builtin_handle(kFastNewFunctionContextFunction);
113 return Handle<Code>::null();
116 Handle<Code> Builtins::NonPrimitiveToPrimitive(ToPrimitiveHint hint) {
118 case ToPrimitiveHint::kDefault:
119 return builtin_handle(kNonPrimitiveToPrimitive_Default);
120 case ToPrimitiveHint::kNumber:
121 return builtin_handle(kNonPrimitiveToPrimitive_Number);
122 case ToPrimitiveHint::kString:
123 return builtin_handle(kNonPrimitiveToPrimitive_String);
128 Handle<Code> Builtins::OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint) {
130 case OrdinaryToPrimitiveHint::kNumber:
131 return builtin_handle(kOrdinaryToPrimitive_Number);
132 case OrdinaryToPrimitiveHint::kString:
133 return builtin_handle(kOrdinaryToPrimitive_String);
138 void Builtins::set_builtin(
int index, Code builtin) {
139 isolate_->heap()->set_builtin(index, builtin);
142 Code Builtins::builtin(
int index) {
return isolate_->heap()->builtin(index); }
144 Handle<Code> Builtins::builtin_handle(
int index) {
145 DCHECK(IsBuiltinId(index));
147 reinterpret_cast<Address*
>(isolate_->heap()->builtin_address(index)));
151 int Builtins::GetStackParameterCount(Name name) {
152 DCHECK(Builtins::KindOf(name) == TFJ);
153 return builtin_metadata[name].kind_specific_data.parameter_count;
157 Callable Builtins::CallableFor(Isolate* isolate, Name name) {
158 Handle<Code> code = isolate->builtins()->builtin_handle(name);
159 CallDescriptors::Key key;
163 #define CASE_OTHER(Name, ...) \ 165 key = Builtin_##Name##_InterfaceDescriptor::key(); \ 168 BUILTIN_LIST(IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, CASE_OTHER,
169 CASE_OTHER, CASE_OTHER, IGNORE_BUILTIN, IGNORE_BUILTIN)
172 Builtins::Kind kind = Builtins::KindOf(name);
173 DCHECK_NE(BCH, kind);
174 if (kind == TFJ || kind == CPP) {
175 return Callable(code, JSTrampolineDescriptor{});
179 CallInterfaceDescriptor descriptor(key);
180 return Callable(code, descriptor);
184 const char* Builtins::name(
int index) {
185 DCHECK(IsBuiltinId(index));
186 return builtin_metadata[index].name;
189 void Builtins::PrintBuiltinCode() {
190 DCHECK(FLAG_print_builtin_code);
191 #ifdef ENABLE_DISASSEMBLER 192 for (
int i = 0;
i < builtin_count;
i++) {
193 const char* builtin_name = name(
i);
194 Handle<Code> code = builtin_handle(
i);
195 if (PassesFilter(CStrVector(builtin_name),
196 CStrVector(FLAG_print_builtin_code_filter))) {
197 CodeTracer::Scope trace_scope(isolate_->GetCodeTracer());
198 OFStream os(trace_scope.file());
199 code->Disassemble(builtin_name, os);
206 void Builtins::PrintBuiltinSize() {
207 DCHECK(FLAG_print_builtin_size);
208 for (
int i = 0;
i < builtin_count;
i++) {
209 const char* builtin_name = name(
i);
210 const char* kind = KindNameOf(
i);
211 Code code = builtin(
i);
212 PrintF(stdout,
"%s Builtin, %s, %d\n", kind, builtin_name,
213 code->InstructionSize());
218 Address Builtins::CppEntryOf(
int index) {
219 DCHECK(Builtins::HasCppImplementation(index));
220 return builtin_metadata[index].kind_specific_data.cpp_entry;
224 bool Builtins::IsBuiltin(
const Code code) {
225 return Builtins::IsBuiltinId(code->builtin_index());
228 bool Builtins::IsBuiltinHandle(Handle<HeapObject> maybe_code,
230 Heap* heap = isolate_->heap();
231 Address handle_location = maybe_code.address();
232 Address start = heap->builtin_address(0);
233 Address end = heap->builtin_address(Builtins::builtin_count);
234 if (handle_location >= end)
return false;
235 if (handle_location < start)
return false;
236 *index =
static_cast<int>(handle_location - start) >> kPointerSizeLog2;
237 DCHECK(Builtins::IsBuiltinId(*index));
242 bool Builtins::IsIsolateIndependentBuiltin(
const Code code) {
243 if (FLAG_embedded_builtins) {
244 const int builtin_index = code->builtin_index();
245 return Builtins::IsBuiltinId(builtin_index) &&
246 Builtins::IsIsolateIndependent(builtin_index);
253 bool Builtins::IsWasmRuntimeStub(
int index) {
254 DCHECK(IsBuiltinId(index));
256 #define CASE_TRAP(Name) case kThrowWasm##Name: 257 #define CASE(Name) case k##Name: 258 WASM_RUNTIME_STUB_LIST(CASE, CASE_TRAP)
270 class OffHeapTrampolineGenerator {
272 explicit OffHeapTrampolineGenerator(Isolate* isolate)
274 masm_(isolate, buffer, kBufferSize, CodeObjectRequired::kYes) {}
276 CodeDesc Generate(Address off_heap_entry) {
278 DCHECK(!masm_.has_frame());
280 FrameScope scope(&masm_, StackFrame::NONE);
281 masm_.JumpToInstructionStream(off_heap_entry);
285 masm_.GetCode(isolate_, &desc);
289 Handle<HeapObject> CodeObject() {
return masm_.CodeObject(); }
294 static constexpr
size_t kBufferSize = 256;
295 byte buffer[kBufferSize];
296 MacroAssembler masm_;
302 Handle<Code> Builtins::GenerateOffHeapTrampolineFor(Isolate* isolate,
303 Address off_heap_entry) {
304 DCHECK_NOT_NULL(isolate->embedded_blob());
305 DCHECK_NE(0, isolate->embedded_blob_size());
307 OffHeapTrampolineGenerator generator(isolate);
308 CodeDesc desc = generator.Generate(off_heap_entry);
310 return isolate->factory()->NewCode(desc, Code::BUILTIN,
311 generator.CodeObject());
315 Handle<ByteArray> Builtins::GenerateOffHeapTrampolineRelocInfo(
317 OffHeapTrampolineGenerator generator(isolate);
320 CodeDesc desc = generator.Generate(kNullAddress);
322 Handle<ByteArray> reloc_info =
323 isolate->factory()->NewByteArray(desc.reloc_size, TENURED_READ_ONLY);
324 Code::CopyRelocInfoToByteArray(*reloc_info, desc);
330 Builtins::Kind Builtins::KindOf(
int index) {
331 DCHECK(IsBuiltinId(index));
332 return builtin_metadata[index].kind;
336 const char* Builtins::KindNameOf(
int index) {
337 Kind kind = Builtins::KindOf(index);
340 case CPP:
return "CPP";
341 case API:
return "API";
342 case TFJ:
return "TFJ";
343 case TFC:
return "TFC";
344 case TFS:
return "TFS";
345 case TFH:
return "TFH";
346 case BCH:
return "BCH";
347 case ASM:
return "ASM";
354 bool Builtins::IsCpp(
int index) {
return Builtins::KindOf(index) == CPP; }
357 bool Builtins::HasCppImplementation(
int index) {
358 Kind kind = Builtins::KindOf(index);
359 return (kind == CPP || kind == API);
363 bool Builtins::AllowDynamicFunction(Isolate* isolate, Handle<JSFunction> target,
364 Handle<JSObject> target_global_proxy) {
365 if (FLAG_allow_unsafe_function_constructor)
return true;
366 HandleScopeImplementer* impl = isolate->handle_scope_implementer();
367 Handle<Context> responsible_context = impl->LastEnteredOrMicrotaskContext();
369 if (responsible_context.is_null()) {
372 if (*responsible_context == target->context())
return true;
373 return isolate->MayAccess(responsible_context, target_global_proxy);
376 Builtins::Name ExampleBuiltinForTorqueFunctionPointerType(
377 size_t function_pointer_type_id) {
378 switch (function_pointer_type_id) {
379 #define FUNCTION_POINTER_ID_CASE(id, name) \ 381 return Builtins::k##name; 382 TORQUE_FUNCTION_POINTER_TYPE_TO_BUILTIN_MAP(FUNCTION_POINTER_ID_CASE)
383 #undef FUNCTION_POINTER_ID_CASE