#include "src/builtins/builtins.h"
#include "src/api/api-inl.h"
#include "src/builtins/builtins-descriptors.h"
#include "src/builtins/builtins-inl.h"
#include "src/builtins/data-view-ops.h"
#include "src/codegen/assembler-inl.h"
#include "src/codegen/callable.h"
#include "src/codegen/macro-assembler-inl.h"
#include "src/codegen/macro-assembler.h"
#include "src/diagnostics/code-tracer.h"
#include "src/execution/isolate.h"
#include "src/heap/combined-heap.h"
#include "src/interpreter/bytecodes.h"
#include "src/logging/code-events.h"
#include "src/logging/log.h"
#include "src/objects/fixed-array.h"
#include "src/objects/objects-inl.h"
#include "src/objects/visitors.h"
#include "src/snapshot/embedded/embedded-data-inl.h"
#include "src/utils/ostreams.h"
namespace v8 {
namespace internal {
#define FORWARD_DECLARE(Name, Argc) \
Address Builtin_##Name(int argc, Address* args, Isolate* isolate);
BUILTIN_LIST_C(FORWARD_DECLARE)
#undef FORWARD_DECLARE
namespace {
struct BuiltinMetadata {
const char* name;
Builtins::Kind kind;
struct BytecodeAndScale {
interpreter::Bytecode bytecode : 8;
interpreter::OperandScale scale : 8;
};
static_assert(sizeof(interpreter::Bytecode) == 1);
static_assert(sizeof(interpreter::OperandScale) == 1);
static_assert(sizeof(BytecodeAndScale) <= sizeof(Address));
union KindSpecificData {
constexpr KindSpecificData() : cpp_entry(kNullAddress) {}
constexpr KindSpecificData(Address cpp_entry) : cpp_entry(cpp_entry) {}
constexpr KindSpecificData(int parameter_count,
int )
: parameter_count(static_cast<int16_t>(parameter_count)) {}
constexpr KindSpecificData(interpreter::Bytecode bytecode,
interpreter::OperandScale scale)
: bytecode_and_scale{bytecode, scale} {}
Address cpp_entry;
int16_t parameter_count;
BytecodeAndScale bytecode_and_scale;
} data;
};
#define DECL_CPP(Name, Argc) \
{#Name, Builtins::CPP, {FUNCTION_ADDR(Builtin_##Name)}},
#define DECL_TFJ_TSA(Name, Count, ...) {#Name, Builtins::TFJ_TSA, {Count, 0}},
#define DECL_TFJ(Name, Count, ...) {#Name, Builtins::TFJ, {Count, 0}},
#define DECL_TFC_TSA(Name, ...) {#Name, Builtins::TFC_TSA, {}},
#define DECL_TFC(Name, ...) {#Name, Builtins::TFC, {}},
#define DECL_TFS(Name, ...) {#Name, Builtins::TFS, {}},
#define DECL_TFH(Name, ...) {#Name, Builtins::TFH, {}},
#define DECL_BCH_TSA(Name, OperandScale, Bytecode) \
{#Name, Builtins::BCH_TSA, {Bytecode, OperandScale}},
#define DECL_BCH(Name, OperandScale, Bytecode) \
{#Name, Builtins::BCH, {Bytecode, OperandScale}},
#define DECL_ASM(Name, ...) {#Name, Builtins::ASM, {}},
const BuiltinMetadata builtin_metadata[] = {
BUILTIN_LIST(DECL_CPP, DECL_TFJ_TSA, DECL_TFJ, DECL_TFC_TSA, DECL_TFC,
DECL_TFS, DECL_TFH, DECL_BCH_TSA, DECL_BCH, DECL_ASM)};
#undef DECL_CPP
#undef DECL_TFJ_TSA
#undef DECL_TFJ
#undef DECL_TFC_TSA
#undef DECL_TFC
#undef DECL_TFS
#undef DECL_TFH
#undef DECL_BCH_TSA
#undef DECL_BCH
#undef DECL_ASM
}
BytecodeOffset Builtins::GetContinuationBytecodeOffset(Builtin builtin) {
DCHECK(Builtins::KindOf(builtin) == TFJ || Builtins::KindOf(builtin) == TFC ||
Builtins::KindOf(builtin) == TFS);
return BytecodeOffset(BytecodeOffset::kFirstBuiltinContinuationId +
ToInt(builtin));
}
Builtin Builtins::GetBuiltinFromBytecodeOffset(BytecodeOffset id) {
Builtin builtin = Builtins::FromInt(
id.ToInt() - BytecodeOffset::kFirstBuiltinContinuationId);
DCHECK(Builtins::KindOf(builtin) == TFJ || Builtins::KindOf(builtin) == TFC ||
Builtins::KindOf(builtin) == TFS);
return builtin;
}
void Builtins::TearDown() { initialized_ = false; }
const char* Builtins::Lookup(Address pc) {
Builtin builtin = OffHeapInstructionStream::TryLookupCode(isolate_, pc);
if (Builtins::IsBuiltinId(builtin)) return name(builtin);
if (!initialized_) return nullptr;
for (Builtin builtin_ix = Builtins::kFirst; builtin_ix <= Builtins::kLast;
++builtin_ix) {
if (code(builtin_ix)->contains(isolate_, pc)) {
return name(builtin_ix);
}
}
return nullptr;
}
FullObjectSlot Builtins::builtin_slot(Builtin builtin) {
Address* location = &isolate_->builtin_table()[Builtins::ToInt(builtin)];
return FullObjectSlot(location);
}
FullObjectSlot Builtins::builtin_tier0_slot(Builtin builtin) {
DCHECK(IsTier0(builtin));
Address* location =
&isolate_->builtin_tier0_table()[Builtins::ToInt(builtin)];
return FullObjectSlot(location);
}
void Builtins::set_code(Builtin builtin, Tagged<Code> code) {
DCHECK_EQ(builtin, code->builtin_id());
DCHECK(Internals::HasHeapObjectTag(code.ptr()));
isolate_->builtin_table()[Builtins::ToInt(builtin)] = code.ptr();
}
Tagged<Code> Builtins::code(Builtin builtin) {
Address ptr = isolate_->builtin_table()[Builtins::ToInt(builtin)];
return TrustedCast<Code>(Tagged<Object>(ptr));
}
Handle<Code> Builtins::code_handle(Builtin builtin) {
Address* location = &isolate_->builtin_table()[Builtins::ToInt(builtin)];
return Handle<Code>(location);
}
int Builtins::GetStackParameterCount(Builtin builtin) {
DCHECK(Builtins::KindOf(builtin) == TFJ_TSA ||
Builtins::KindOf(builtin) == TFJ);
return builtin_metadata[ToInt(builtin)].data.parameter_count;
}
bool Builtins::CheckFormalParameterCount(
Builtin builtin, int function_length,
int formal_parameter_count_with_receiver) {
DCHECK_LE(0, function_length);
if (!Builtins::IsBuiltinId(builtin)) {
return true;
}
if (!HasJSLinkage(builtin)) {
return true;
}
if (builtin == Builtin::kCompileLazy) {
return true;
}
int parameter_count = Builtins::GetFormalParameterCount(builtin);
return parameter_count == formal_parameter_count_with_receiver;
}
CallInterfaceDescriptor Builtins::CallInterfaceDescriptorFor(Builtin builtin) {
CallDescriptors::Key key;
switch (builtin) {
#define CASE_OTHER(Name, ...) \
case Builtin::k##Name: { \
key = Builtin_##Name##_InterfaceDescriptor::key(); \
break; \
}
BUILTIN_LIST(IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, CASE_OTHER,
CASE_OTHER, CASE_OTHER, CASE_OTHER, IGNORE_BUILTIN,
IGNORE_BUILTIN, CASE_OTHER)
#undef CASE_OTHER
default:
Builtins::Kind kind = Builtins::KindOf(builtin);
if (kind == TFJ_TSA || kind == TFJ || kind == CPP) {
return JSTrampolineDescriptor{};
}
if (kind == BCH || kind == BCH_TSA) {
return InterpreterDispatchDescriptor{};
}
UNREACHABLE();
}
return CallInterfaceDescriptor{key};
}
Callable Builtins::CallableFor(Isolate* isolate, Builtin builtin) {
Handle<Code> code = isolate->builtins()->code_handle(builtin);
return Callable{code, CallInterfaceDescriptorFor(builtin)};
}
bool Builtins::HasJSLinkage(Builtin builtin) {
return CallInterfaceDescriptorFor(builtin) == JSTrampolineDescriptor{};
}
const char* Builtins::name(Builtin builtin) {
int index = ToInt(builtin);
DCHECK(IsBuiltinId(index));
return builtin_metadata[index].name;
}
const char* Builtins::NameForStackTrace(Isolate* isolate, Builtin builtin) {
#if V8_ENABLE_WEBASSEMBLY
switch (builtin) {
case Builtin::kDataViewPrototypeGetBigInt64:
return "DataView.prototype.getBigInt64";
case Builtin::kDataViewPrototypeGetBigUint64:
return "DataView.prototype.getBigUint64";
case Builtin::kDataViewPrototypeGetFloat16:
return "DataView.prototype.getFloat16";
case Builtin::kDataViewPrototypeGetFloat32:
return "DataView.prototype.getFloat32";
case Builtin::kDataViewPrototypeGetFloat64:
return "DataView.prototype.getFloat64";
case Builtin::kDataViewPrototypeGetInt8:
return "DataView.prototype.getInt8";
case Builtin::kDataViewPrototypeGetInt16:
return "DataView.prototype.getInt16";
case Builtin::kDataViewPrototypeGetInt32:
return "DataView.prototype.getInt32";
case Builtin::kDataViewPrototypeGetUint8:
return "DataView.prototype.getUint8";
case Builtin::kDataViewPrototypeGetUint16:
return "DataView.prototype.getUint16";
case Builtin::kDataViewPrototypeGetUint32:
return "DataView.prototype.getUint32";
case Builtin::kDataViewPrototypeSetBigInt64:
return "DataView.prototype.setBigInt64";
case Builtin::kDataViewPrototypeSetBigUint64:
return "DataView.prototype.setBigUint64";
case Builtin::kDataViewPrototypeSetFloat16:
return "DataView.prototype.setFloat16";
case Builtin::kDataViewPrototypeSetFloat32:
return "DataView.prototype.setFloat32";
case Builtin::kDataViewPrototypeSetFloat64:
return "DataView.prototype.setFloat64";
case Builtin::kDataViewPrototypeSetInt8:
return "DataView.prototype.setInt8";
case Builtin::kDataViewPrototypeSetInt16:
return "DataView.prototype.setInt16";
case Builtin::kDataViewPrototypeSetInt32:
return "DataView.prototype.setInt32";
case Builtin::kDataViewPrototypeSetUint8:
return "DataView.prototype.setUint8";
case Builtin::kDataViewPrototypeSetUint16:
return "DataView.prototype.setUint16";
case Builtin::kDataViewPrototypeSetUint32:
return "DataView.prototype.setUint32";
case Builtin::kDataViewPrototypeGetByteLength:
return "get DataView.prototype.byteLength";
case Builtin::kThrowDataViewDetachedError:
case Builtin::kThrowDataViewOutOfBounds:
case Builtin::kThrowDataViewTypeError: {
DataViewOp op = static_cast<DataViewOp>(isolate->error_message_param());
return ToString(op);
}
case Builtin::kStringPrototypeToLocaleLowerCase:
return "String.toLocaleLowerCase";
case Builtin::kStringPrototypeIndexOf:
case Builtin::kThrowIndexOfCalledOnNull:
return "String.indexOf";
#if V8_INTL_SUPPORT
case Builtin::kStringPrototypeToLowerCaseIntl:
#endif
case Builtin::kThrowToLowerCaseCalledOnNull:
return "String.toLowerCase";
case Builtin::kWasmIntToString:
return "Number.toString";
default:
return nullptr;
}
#else
return nullptr;
#endif
}
void Builtins::PrintBuiltinCode() {
DCHECK(v8_flags.print_builtin_code);
#ifdef ENABLE_DISASSEMBLER
for (Builtin builtin = Builtins::kFirst; builtin <= Builtins::kLast;
++builtin) {
const char* builtin_name = name(builtin);
if (PassesFilter(base::CStrVector(builtin_name),
base::CStrVector(v8_flags.print_builtin_code_filter))) {
CodeTracer::Scope trace_scope(isolate_->GetCodeTracer());
OFStream os(trace_scope.file());
Tagged<Code> builtin_code = code(builtin);
builtin_code->Disassemble(builtin_name, os, isolate_);
os << "\n";
}
}
#endif
}
void Builtins::PrintBuiltinSize() {
DCHECK(v8_flags.print_builtin_size);
for (Builtin builtin = Builtins::kFirst; builtin <= Builtins::kLast;
++builtin) {
const char* builtin_name = name(builtin);
const char* kind = KindNameOf(builtin);
Tagged<Code> code = Builtins::code(builtin);
PrintF(stdout, "%s Builtin, %s, %d\n", kind, builtin_name,
code->instruction_size());
}
}
Address Builtins::CppEntryOf(Builtin builtin) {
DCHECK(Builtins::IsCpp(builtin));
return builtin_metadata[ToInt(builtin)].data.cpp_entry;
}
Address Builtins::EmbeddedEntryOf(Builtin builtin) {
static_assert(Builtins::kAllBuiltinsAreIsolateIndependent);
return EmbeddedData::FromBlob().InstructionStartOf(builtin);
}
bool Builtins::IsBuiltin(const Tagged<Code> code) {
return Builtins::IsBuiltinId(code->builtin_id());
}
bool Builtins::IsBuiltinHandle(IndirectHandle<HeapObject> maybe_code,
Builtin* builtin) const {
Address* handle_location = maybe_code.location();
Address* builtins_table = isolate_->builtin_table();
if (handle_location < builtins_table) return false;
Address* builtins_table_end = &builtins_table[Builtins::kBuiltinCount];
if (handle_location >= builtins_table_end) return false;
*builtin = FromInt(static_cast<int>(handle_location - builtins_table));
return true;
}
bool Builtins::IsIsolateIndependentBuiltin(Tagged<Code> code) {
Builtin builtin = code->builtin_id();
return Builtins::IsBuiltinId(builtin) &&
Builtins::IsIsolateIndependent(builtin);
}
void Builtins::InitializeIsolateDataTables(Isolate* isolate) {
EmbeddedData embedded_data = EmbeddedData::FromBlob(isolate);
IsolateData* isolate_data = isolate->isolate_data();
for (Builtin i = Builtins::kFirst; i <= Builtins::kLast; ++i) {
DCHECK(Builtins::IsBuiltinId(isolate->builtins()->code(i)->builtin_id()));
DCHECK(!isolate->builtins()->code(i)->has_instruction_stream());
Builtin builtin_id = i;
#if V8_ENABLE_GEARBOX
builtin_id = isolate->builtins()->code(i)->builtin_id();
#endif
isolate_data->builtin_entry_table()[ToInt(i)] =
embedded_data.InstructionStartOf(builtin_id);
}
for (Builtin i = Builtins::kFirst; i <= Builtins::kLastTier0; ++i) {
const int ii = ToInt(i);
isolate_data->builtin_tier0_entry_table()[ii] =
isolate_data->builtin_entry_table()[ii];
isolate_data->builtin_tier0_table()[ii] = isolate_data->builtin_table()[ii];
}
}
void Builtins::EmitCodeCreateEvents(Isolate* isolate) {
if (!isolate->IsLoggingCodeCreation()) return;
Address* builtins = isolate->builtin_table();
int i = 0;
HandleScope scope(isolate);
for (; i < ToInt(Builtin::kFirstBytecodeHandler); i++) {
auto builtin_code = DirectHandle<Code>::FromSlot(&builtins[i]);
DirectHandle<AbstractCode> code = Cast<AbstractCode>(builtin_code);
PROFILE(isolate, CodeCreateEvent(LogEventListener::CodeTag::kBuiltin, code,
Builtins::name(FromInt(i))));
}
static_assert(kLastBytecodeHandlerPlusOne == kBuiltinCount);
for (; i < kBuiltinCount; i++) {
auto builtin_code = DirectHandle<Code>::FromSlot(&builtins[i]);
DirectHandle<AbstractCode> code = Cast<AbstractCode>(builtin_code);
interpreter::Bytecode bytecode =
builtin_metadata[i].data.bytecode_and_scale.bytecode;
interpreter::OperandScale scale =
builtin_metadata[i].data.bytecode_and_scale.scale;
PROFILE(isolate,
CodeCreateEvent(
LogEventListener::CodeTag::kBytecodeHandler, code,
interpreter::Bytecodes::ToString(bytecode, scale).c_str()));
}
}
DirectHandle<Code> Builtins::CreateInterpreterEntryTrampolineForProfiling(
Isolate* isolate) {
DCHECK_NOT_NULL(isolate->embedded_blob_code());
DCHECK_NE(0, isolate->embedded_blob_code_size());
Tagged<Code> code = isolate->builtins()->code(
Builtin::kInterpreterEntryTrampolineForProfiling);
CodeDesc desc;
desc.buffer = reinterpret_cast<uint8_t*>(code->instruction_start());
int instruction_size = code->instruction_size();
desc.buffer_size = instruction_size;
desc.instr_size = instruction_size;
DCHECK_EQ(code->safepoint_table_size(), 0);
DCHECK_EQ(code->handler_table_size(), 0);
DCHECK_EQ(code->constant_pool_size(), 0);
DCHECK_EQ(code->code_comments_size(), 0);
DCHECK_EQ(code->unwinding_info_size(), 0);
desc.safepoint_table_offset = instruction_size;
desc.handler_table_offset = instruction_size;
desc.constant_pool_offset = instruction_size;
desc.code_comments_offset = instruction_size;
desc.jump_table_info_offset = instruction_size;
CodeDesc::Verify(&desc);
return Factory::CodeBuilder(isolate, desc, CodeKind::BUILTIN)
.set_builtin(Builtin::kInterpreterEntryTrampoline)
.Build();
}
Builtins::Kind Builtins::KindOf(Builtin builtin) {
DCHECK(IsBuiltinId(builtin));
return builtin_metadata[ToInt(builtin)].kind;
}
const char* Builtins::KindNameOf(Builtin builtin) {
Kind kind = Builtins::KindOf(builtin);
switch (kind) {
case CPP: return "CPP";
case TFJ_TSA: return "TFJ_TSA";
case TFJ: return "TFJ";
case TFC_TSA: return "TFC_TSA";
case TFC: return "TFC";
case TFS: return "TFS";
case TFH: return "TFH";
case BCH_TSA: return "BCH_TSA";
case BCH: return "BCH";
case ASM: return "ASM";
}
UNREACHABLE();
}
bool Builtins::IsCpp(Builtin builtin) {
return Builtins::KindOf(builtin) == CPP;
}
CodeEntrypointTag Builtins::EntrypointTagFor(Builtin builtin) {
Kind kind = Builtins::KindOf(builtin);
switch (kind) {
case CPP:
case TFJ_TSA:
case TFJ:
return kJSEntrypointTag;
case BCH_TSA:
case BCH:
return kBytecodeHandlerEntrypointTag;
case TFC:
case TFC_TSA:
case TFS:
case TFH:
case ASM:
return CallInterfaceDescriptorFor(builtin).tag();
}
UNREACHABLE();
}
CodeSandboxingMode Builtins::SandboxingModeOf(Builtin builtin) {
Kind kind = Builtins::KindOf(builtin);
switch (kind) {
case CPP:
return CodeSandboxingMode::kSandboxed;
case TFJ_TSA:
case TFJ:
return CodeSandboxingMode::kSandboxed;
case TFH:
case BCH_TSA:
case BCH:
return CodeSandboxingMode::kSandboxed;
case TFS:
switch (builtin) {
case Builtin::kEnqueueMicrotask:
return CodeSandboxingMode::kUnsandboxed;
default:
return CodeSandboxingMode::kSandboxed;
}
case TFC_TSA:
case TFC:
case ASM:
return CallInterfaceDescriptorFor(builtin).sandboxing_mode();
}
}
bool Builtins::AllowDynamicFunction(
Isolate* isolate, DirectHandle<JSFunction> target,
DirectHandle<JSObject> target_global_proxy) {
if (v8_flags.allow_unsafe_function_constructor) return true;
HandleScopeImplementer* impl = isolate->handle_scope_implementer();
DirectHandle<NativeContext> responsible_context = impl->LastEnteredContext();
if (responsible_context.is_null()) {
return true;
}
if (*responsible_context == target->context()) return true;
return isolate->MayAccess(responsible_context, target_global_proxy);
}
Builtins::JSBuiltinStateFlags Builtins::GetJSBuiltinState(Builtin builtin) {
#ifdef DEBUG
#define CHECK_FEATURE_FLAG_IS_CONSISTENT(IS_ENABLED) \
static bool is_feature_enabled = IS_ENABLED; \
DCHECK_EQ(is_feature_enabled, IS_ENABLED);
#else
#define CHECK_FEATURE_FLAG_IS_CONSISTENT(IS_ENABLED)
#endif
#define RETURN_FLAG_DEPENDENT_BUILTIN_STATE(IS_FEATURE_ENABLED) \
{ \
CHECK_FEATURE_FLAG_IS_CONSISTENT(IS_FEATURE_ENABLED); \
return (IS_FEATURE_ENABLED) ? JSBuiltinStateFlag::kEnabledFlagDependent \
: JSBuiltinStateFlag::kDisabledFlagDependent; \
}
#define RETURN_FLAG_DEPENDENT_LAZY_BUILTIN_STATE(IS_FEATURE_ENABLED) \
{ \
CHECK_FEATURE_FLAG_IS_CONSISTENT(IS_FEATURE_ENABLED); \
return (IS_FEATURE_ENABLED) \
? JSBuiltinStateFlag::kEnabledFlagDependentLazy \
: JSBuiltinStateFlag::kDisabledFlagDependentLazy; \
}
switch (builtin) {
case Builtin::kConstructFunction:
case Builtin::kConstructBoundFunction:
case Builtin::kConstructedNonConstructable:
case Builtin::kConstructProxy:
case Builtin::kHandleApiConstruct:
case Builtin::kArrayConcat:
case Builtin::kArrayPop:
case Builtin::kArrayPush:
case Builtin::kArrayShift:
case Builtin::kArrayUnshift:
case Builtin::kFunctionPrototypeBind:
case Builtin::kInterpreterEntryTrampolineForProfiling:
case Builtin::kStartMaglevOptimizeJob:
case Builtin::kOptimizeMaglevEager:
case Builtin::kStartTurbofanOptimizeJob:
case Builtin::kOptimizeTurbofanEager:
case Builtin::kFunctionLogNextExecution:
case Builtin::kMarkReoptimizeLazyDeoptimized:
case Builtin::kMarkLazyDeoptimized:
case Builtin::kArrayEveryLoopEagerDeoptContinuation:
case Builtin::kArrayEveryLoopLazyDeoptContinuation:
case Builtin::kArrayFilterLoopEagerDeoptContinuation:
case Builtin::kArrayFilterLoopLazyDeoptContinuation:
case Builtin::kArrayFindLoopEagerDeoptContinuation:
case Builtin::kArrayFindLoopLazyDeoptContinuation:
case Builtin::kArrayFindLoopAfterCallbackLazyDeoptContinuation:
case Builtin::kArrayFindIndexLoopEagerDeoptContinuation:
case Builtin::kArrayFindIndexLoopLazyDeoptContinuation:
case Builtin::kArrayFindIndexLoopAfterCallbackLazyDeoptContinuation:
case Builtin::kArrayForEachLoopEagerDeoptContinuation:
case Builtin::kArrayForEachLoopLazyDeoptContinuation:
case Builtin::kArrayMapPreLoopLazyDeoptContinuation:
case Builtin::kArrayMapLoopEagerDeoptContinuation:
case Builtin::kArrayMapLoopLazyDeoptContinuation:
case Builtin::kArrayReduceRightPreLoopEagerDeoptContinuation:
case Builtin::kArrayReduceRightLoopEagerDeoptContinuation:
case Builtin::kArrayReduceRightLoopLazyDeoptContinuation:
case Builtin::kArrayReducePreLoopEagerDeoptContinuation:
case Builtin::kArrayReduceLoopEagerDeoptContinuation:
case Builtin::kArrayReduceLoopLazyDeoptContinuation:
case Builtin::kArraySomeLoopEagerDeoptContinuation:
case Builtin::kArraySomeLoopLazyDeoptContinuation:
case Builtin::kStringCreateLazyDeoptContinuation:
case Builtin::kGenericLazyDeoptContinuation:
case Builtin::kPromiseConstructorLazyDeoptContinuation:
return JSBuiltinStateFlag::kDisabledJSBuiltin;
case Builtin::kCompileLazy:
case Builtin::kDebugBreakTrampoline:
case Builtin::kHandleApiCallOrConstruct:
case Builtin::kInstantiateAsmJs:
case Builtin::kInterpreterEntryTrampoline:
return JSBuiltinStateFlag::kJSTrampoline;
case Builtin::kIllegal:
return JSBuiltinStateFlag::kJSTrampoline;
case Builtin::kConsoleAssert:
case Builtin::kArrayFromAsyncIterableOnFulfilled:
case Builtin::kArrayFromAsyncIterableOnRejected:
case Builtin::kArrayFromAsyncArrayLikeOnFulfilled:
case Builtin::kArrayFromAsyncArrayLikeOnRejected:
case Builtin::kAsyncFromSyncIteratorCloseSyncAndRethrow:
case Builtin::kAsyncFunctionAwaitRejectClosure:
case Builtin::kAsyncFunctionAwaitResolveClosure:
case Builtin::kAsyncDisposableStackOnFulfilled:
case Builtin::kAsyncDisposableStackOnRejected:
case Builtin::kAsyncDisposeFromSyncDispose:
case Builtin::kAsyncGeneratorAwaitResolveClosure:
case Builtin::kAsyncGeneratorAwaitRejectClosure:
case Builtin::kAsyncGeneratorYieldWithAwaitResolveClosure:
case Builtin::kAsyncGeneratorReturnClosedResolveClosure:
case Builtin::kAsyncGeneratorReturnClosedRejectClosure:
case Builtin::kAsyncGeneratorReturnResolveClosure:
case Builtin::kAsyncIteratorPrototypeAsyncDisposeResolveClosure:
case Builtin::kAsyncIteratorValueUnwrap:
case Builtin::kCallAsyncModuleFulfilled:
case Builtin::kCallAsyncModuleRejected:
case Builtin::kPromiseCapabilityDefaultReject:
case Builtin::kPromiseCapabilityDefaultResolve:
case Builtin::kPromiseGetCapabilitiesExecutor:
case Builtin::kPromiseAllResolveElementClosure:
case Builtin::kPromiseAllSettledResolveElementClosure:
case Builtin::kPromiseAllSettledRejectElementClosure:
case Builtin::kPromiseAnyRejectElementClosure:
case Builtin::kPromiseValueThunkFinally:
case Builtin::kPromiseThrowerFinally:
case Builtin::kPromiseCatchFinally:
case Builtin::kPromiseThenFinally:
case Builtin::kProxyRevoke:
return JSBuiltinStateFlag::kCoreJSLazy;
#if V8_ENABLE_WEBASSEMBLY
case Builtin::kJSToWasmWrapper:
case Builtin::kJSToJSWrapper:
case Builtin::kJSToJSWrapperInvalidSig:
case Builtin::kWasmPromising:
#if V8_ENABLE_DRUMBRAKE
case Builtin::kGenericJSToWasmInterpreterWrapper:
#endif
case Builtin::kWasmStressSwitch:
return JSBuiltinStateFlag::kJSTrampoline;
case Builtin::kWasmConstructorWrapper:
case Builtin::kWasmMethodWrapper:
case Builtin::kWasmResume:
case Builtin::kWasmReject:
case Builtin::kWebAssemblyStringCast:
case Builtin::kWebAssemblyStringTest:
case Builtin::kWebAssemblyStringFromWtf16Array:
case Builtin::kWebAssemblyStringFromUtf8Array:
case Builtin::kWebAssemblyStringIntoUtf8Array:
case Builtin::kWebAssemblyStringToUtf8Array:
case Builtin::kWebAssemblyStringToWtf16Array:
case Builtin::kWebAssemblyStringFromCharCode:
case Builtin::kWebAssemblyStringFromCodePoint:
case Builtin::kWebAssemblyStringCodePointAt:
case Builtin::kWebAssemblyStringCharCodeAt:
case Builtin::kWebAssemblyStringLength:
case Builtin::kWebAssemblyStringMeasureUtf8:
case Builtin::kWebAssemblyStringConcat:
case Builtin::kWebAssemblyStringSubstring:
case Builtin::kWebAssemblyStringEquals:
case Builtin::kWebAssemblyStringCompare:
case Builtin::kWebAssemblyConfigureAllPrototypes:
return JSBuiltinStateFlag::kCoreJSLazy;
#endif
#ifdef V8_INTL_SUPPORT
case Builtin::kCollatorInternalCompare:
case Builtin::kDateTimeFormatInternalFormat:
case Builtin::kNumberFormatInternalFormatNumber:
case Builtin::kV8BreakIteratorInternalAdoptText:
case Builtin::kV8BreakIteratorInternalBreakType:
case Builtin::kV8BreakIteratorInternalCurrent:
case Builtin::kV8BreakIteratorInternalFirst:
case Builtin::kV8BreakIteratorInternalNext:
return JSBuiltinStateFlag::kCoreJSLazy;
case Builtin::kLocalePrototypeCalendars:
case Builtin::kLocalePrototypeCollations:
case Builtin::kLocalePrototypeHourCycles:
case Builtin::kLocalePrototypeNumberingSystems:
case Builtin::kLocalePrototypeTextInfo:
case Builtin::kLocalePrototypeTimeZones:
case Builtin::kLocalePrototypeWeekInfo:
RETURN_FLAG_DEPENDENT_BUILTIN_STATE(
!v8_flags.harmony_remove_intl_locale_info_getters);
#endif
#ifdef V8_TEMPORAL_SUPPORT
#define CASE(Name, ...) case Builtin::k##Name:
BUILTIN_LIST_TEMPORAL(CASE, CASE)
#undef CASE
RETURN_FLAG_DEPENDENT_LAZY_BUILTIN_STATE(v8_flags.harmony_temporal);
#endif
#if V8_ENABLE_WEBASSEMBLY
case Builtin::kWebAssemblyFunctionPrototypeBind:
RETURN_FLAG_DEPENDENT_BUILTIN_STATE(
wasm::WasmEnabledFeatures::FromFlags().has_type_reflection());
#endif
case Builtin::kRegExpPrototypeLinearGetter:
RETURN_FLAG_DEPENDENT_BUILTIN_STATE(
v8_flags.enable_experimental_regexp_engine);
case Builtin::kIllegalInvocationThrower:
case Builtin::kAbstractModuleSourceToStringTag:
RETURN_FLAG_DEPENDENT_BUILTIN_STATE(v8_flags.js_source_phase_imports);
case Builtin::kShadowRealmConstructor:
case Builtin::kShadowRealmPrototypeEvaluate:
case Builtin::kShadowRealmPrototypeImportValue:
case Builtin::kShadowRealmImportValueRejected:
RETURN_FLAG_DEPENDENT_BUILTIN_STATE(v8_flags.harmony_shadow_realm);
case Builtin::kShadowRealmImportValueFulfilled:
RETURN_FLAG_DEPENDENT_LAZY_BUILTIN_STATE(v8_flags.harmony_shadow_realm);
case Builtin::kSharedSpaceJSObjectHasInstance:
case Builtin::kSharedStructTypeConstructor:
case Builtin::kSharedStructTypeIsSharedStruct:
case Builtin::kSharedArrayConstructor:
case Builtin::kSharedArrayIsSharedArray:
case Builtin::kAtomicsMutexConstructor:
case Builtin::kAtomicsMutexLock:
case Builtin::kAtomicsMutexLockWithTimeout:
case Builtin::kAtomicsMutexTryLock:
case Builtin::kAtomicsMutexIsMutex:
case Builtin::kAtomicsConditionConstructor:
case Builtin::kAtomicsConditionWait:
case Builtin::kAtomicsConditionNotify:
case Builtin::kAtomicsConditionIsCondition:
RETURN_FLAG_DEPENDENT_BUILTIN_STATE(v8_flags.harmony_struct);
case Builtin::kSharedStructConstructor:
RETURN_FLAG_DEPENDENT_LAZY_BUILTIN_STATE(v8_flags.harmony_struct);
case Builtin::kPromiseTry:
RETURN_FLAG_DEPENDENT_BUILTIN_STATE(v8_flags.js_promise_try);
case Builtin::kAtomicsPause:
RETURN_FLAG_DEPENDENT_BUILTIN_STATE(v8_flags.js_atomics_pause);
case Builtin::kErrorIsError:
RETURN_FLAG_DEPENDENT_BUILTIN_STATE(v8_flags.js_error_iserror);
case Builtin::kRegExpEscape:
RETURN_FLAG_DEPENDENT_BUILTIN_STATE(v8_flags.js_regexp_escape);
case Builtin::kSuppressedErrorConstructor:
case Builtin::kDisposableStackConstructor:
case Builtin::kDisposableStackPrototypeUse:
case Builtin::kDisposableStackPrototypeDispose:
case Builtin::kDisposableStackPrototypeAdopt:
case Builtin::kDisposableStackPrototypeDefer:
case Builtin::kDisposableStackPrototypeMove:
case Builtin::kDisposableStackPrototypeGetDisposed:
case Builtin::kAsyncDisposableStackConstructor:
case Builtin::kAsyncDisposableStackPrototypeUse:
case Builtin::kAsyncDisposableStackPrototypeDisposeAsync:
case Builtin::kAsyncDisposableStackPrototypeAdopt:
case Builtin::kAsyncDisposableStackPrototypeDefer:
case Builtin::kAsyncDisposableStackPrototypeMove:
case Builtin::kAsyncDisposableStackPrototypeGetDisposed:
case Builtin::kIteratorPrototypeDispose:
case Builtin::kAsyncIteratorPrototypeAsyncDispose:
RETURN_FLAG_DEPENDENT_BUILTIN_STATE(
v8_flags.js_explicit_resource_management);
case Builtin::kMathF16round:
case Builtin::kDataViewPrototypeGetFloat16:
case Builtin::kDataViewPrototypeSetFloat16:
RETURN_FLAG_DEPENDENT_BUILTIN_STATE(v8_flags.js_float16array);
case Builtin::kUint8ArrayFromBase64:
case Builtin::kUint8ArrayFromHex:
case Builtin::kUint8ArrayPrototypeToBase64:
case Builtin::kUint8ArrayPrototypeSetFromBase64:
case Builtin::kUint8ArrayPrototypeToHex:
case Builtin::kUint8ArrayPrototypeSetFromHex:
RETURN_FLAG_DEPENDENT_BUILTIN_STATE(v8_flags.js_base_64);
case Builtin::kMapPrototypeGetOrInsert:
case Builtin::kMapPrototypeGetOrInsertComputed:
case Builtin::kWeakMapPrototypeGetOrInsert:
case Builtin::kWeakMapPrototypeGetOrInsertComputed:
RETURN_FLAG_DEPENDENT_BUILTIN_STATE(v8_flags.js_upsert);
#ifdef V8_INTL_SUPPORT
case Builtin::kLocalePrototypeVariants:
RETURN_FLAG_DEPENDENT_BUILTIN_STATE(v8_flags.js_intl_locale_variants);
#endif
default: {
return HasJSLinkage(builtin) ? JSBuiltinStateFlag::kCoreJSMandatory
: JSBuiltinStateFlag::kDisabledNonJSBuiltin;
}
}
UNREACHABLE();
#undef CHECK_FEATURE_FLAG_IS_CONSISTENT
#undef RETURN_FLAG_DEPENDENT_BUILTIN_STATE
#undef RETURN_FLAG_DEPENDENT_LAZY_BUILTIN_STATE
}
#ifdef DEBUG
void Builtins::VerifyGetJSBuiltinState(bool allow_non_initial_state) {
CombinedHeapObjectIterator iterator(isolate_->heap());
std::vector<bool> used_js_builtins(
static_cast<size_t>(Builtins::kBuiltinCount));
bool js_functions_exist = false;
for (Tagged<HeapObject> obj = iterator.Next(); !obj.is_null();
obj = iterator.Next()) {
if (IsAnyHole(obj)) continue;
Tagged<JSFunction> func;
if (!TryCast(obj, &func)) continue;
js_functions_exist = true;
Builtin builtin = func->code(isolate_)->builtin_id();
size_t builtin_id = static_cast<size_t>(builtin);
if (builtin_id < Builtins::kBuiltinCount) {
used_js_builtins[builtin_id] = true;
}
}
if (!js_functions_exist) {
return;
}
size_t bad_builtins_count = 0;
for (Builtin i = Builtins::kFirst; i <= Builtins::kLast; ++i) {
JSBuiltinStateFlags state = GetJSBuiltinState(i);
bool is_enabled = state & JSBuiltinStateFlag::kEnabled;
bool is_flag_dependent = state & JSBuiltinStateFlag::kFlagDependent;
bool is_lazy = state & JSBuiltinStateFlag::kLazy;
bool is_core_JS = state & JSBuiltinStateFlag::kCoreJS;
bool has_JS_linkage = !(state & JSBuiltinStateFlag::kNonJSLinkage);
CHECK_IMPLIES(is_core_JS, is_enabled && !is_flag_dependent);
const char* error = nullptr;
bool used = used_js_builtins[static_cast<size_t>(i)];
if (has_JS_linkage != HasJSLinkage(i)) {
if (has_JS_linkage) {
error = "non-JS builtin doesn't have kNonJSLinkage flag";
} else {
error = "JS builtin has kNonJSLinkage flag";
}
} else if (is_enabled && !has_JS_linkage) {
error = "builtin with non-JS linkage must be disabled";
} else if (used) {
if (!is_enabled) {
error = "using disabled builtin";
} else if (is_lazy && !allow_non_initial_state) {
error = "unexpected usage of lazy builtin";
}
} else if (is_enabled && !allow_non_initial_state) {
if (is_flag_dependent && !is_lazy) {
error = "non-lazy optional builtin is not used while it was enabled";
} else if (is_core_JS && !is_lazy) {
error = "mandatory JS builtin is not used while it was enabled";
}
}
if (error) {
if (bad_builtins_count == 0) {
PrintF(
"#\n# Builtins::GetJSBuiltinState() predicate is wrong for "
"the following builtins:\n#\n");
}
bad_builtins_count++;
PrintF(" case Builtin::k%s: // %s\n", Builtins::name(i), error);
}
}
CHECK_WITH_MSG(bad_builtins_count == 0,
"Builtins::GetJSBuiltinState() predicate requires updating");
}
#endif
Builtin ExampleBuiltinForTorqueFunctionPointerType(
size_t function_pointer_type_id) {
switch (function_pointer_type_id) {
#define FUNCTION_POINTER_ID_CASE(id, name) \
case id: \
return Builtin::k##name;
TORQUE_FUNCTION_POINTER_TYPE_TO_BUILTIN_MAP(FUNCTION_POINTER_ID_CASE)
#undef FUNCTION_POINTER_ID_CASE
default:
UNREACHABLE();
}
}
}
}