/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
deps/v8/src/runtime/runtime.cc
390 строк
14 KB
Michaël Zasso
deps: update V8 to 14.6.202.33
24 апр 2026, 19:01
Не верифицирован
24 апр 2026, 19:01
f1e0b83
Код
Авторство
О чём код?
// Copyright 2012 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/runtime/runtime.h" #include "src/base/hashmap.h" #include "src/execution/isolate.h" #include "src/runtime/runtime-utils.h" #include "src/strings/string-hasher-inl.h" namespace v8 { namespace internal { // Header of runtime functions. #define F(name, number_of_args, result_size, ...) \ Address Runtime_##name(int args_length, Address* args_object, \ Isolate* isolate); FOR_EACH_INTRINSIC_RETURN_OBJECT(F) #undef F #define P(name, number_of_args, result_size, ...) \ ObjectPair Runtime_##name(int args_length, Address* args_object, \ Isolate* isolate); FOR_EACH_INTRINSIC_RETURN_PAIR(P) #undef P // clang-format off #define F(name, number_of_args, result_size, ...) \ { \ Runtime::k##name, Runtime::RUNTIME, \ #name, FUNCTION_ADDR(Runtime_##name), \ number_of_args, result_size}, #define I(name, number_of_args, result_size, ...) \ { \ Runtime::kInline##name, Runtime::INLINE, \ "_" #name, FUNCTION_ADDR(Runtime_##name), \ number_of_args, result_size}, // clang-format on static const Runtime::Function kIntrinsicFunctions[] = { FOR_EACH_INTRINSIC(F) FOR_EACH_INLINE_INTRINSIC(I)}; #undef I #undef F namespace { V8_DECLARE_ONCE(initialize_function_name_map_once); static const base::CustomMatcherHashMap* kRuntimeFunctionNameMap; struct IntrinsicFunctionIdentifier { IntrinsicFunctionIdentifier(const unsigned char* data, const int length) : data_(data), length_(length) {} static bool Match(void* key1, void* key2) { const IntrinsicFunctionIdentifier* lhs = static_cast<IntrinsicFunctionIdentifier*>(key1); const IntrinsicFunctionIdentifier* rhs = static_cast<IntrinsicFunctionIdentifier*>(key2); if (lhs->length_ != rhs->length_) return false; return CompareCharsEqual(lhs->data_, rhs->data_, rhs->length_); } uint32_t Hash() { return StringHasher::HashSequentialString<uint8_t>(data_, length_, HashSeed::Default()); } const unsigned char* data_; const int length_; }; void InitializeIntrinsicFunctionNames() { base::CustomMatcherHashMap* function_name_map = new base::CustomMatcherHashMap(IntrinsicFunctionIdentifier::Match); for (size_t i = 0; i < arraysize(kIntrinsicFunctions); ++i) { const Runtime::Function* function = &kIntrinsicFunctions[i]; IntrinsicFunctionIdentifier* identifier = new IntrinsicFunctionIdentifier( reinterpret_cast<const unsigned char*>(function->name), static_cast<int>(strlen(function->name))); base::HashMap::Entry* entry = function_name_map->InsertNew(identifier, identifier->Hash()); entry->value = const_cast<Runtime::Function*>(function); } kRuntimeFunctionNameMap = function_name_map; } } // namespace bool Runtime::NeedsExactContext(FunctionId id) { switch (id) { case Runtime::kInlineAsyncFunctionReject: case Runtime::kInlineAsyncFunctionResolve: // For %_AsyncFunctionReject and %_AsyncFunctionResolve we don't // really need the current context, which in particular allows // us to usually eliminate the catch context for the implicit // try-catch in async function. return false; case Runtime::kCreatePrivateAccessors: case Runtime::kCopyDataProperties: case Runtime::kCreateDataProperty: case Runtime::kCreatePrivateNameSymbol: case Runtime::kCreatePrivateBrandSymbol: case Runtime::kLoadPrivateGetter: case Runtime::kLoadPrivateSetter: case Runtime::kReThrow: case Runtime::kReThrowWithMessage: case Runtime::kThrow: case Runtime::kThrowTargetNonFunction: case Runtime::kThrowCalledNonCallable: case Runtime::kThrowConstAssignError: case Runtime::kThrowConstructorNonCallableError: case Runtime::kThrowConstructedNonConstructable: case Runtime::kThrowConstructorReturnedNonObject: case Runtime::kThrowInvalidStringLength: case Runtime::kThrowInvalidTypedArrayAlignment: case Runtime::kThrowIteratorError: case Runtime::kThrowIteratorResultNotAnObject: case Runtime::kThrowNotConstructor: case Runtime::kThrowRangeError: case Runtime::kThrowReferenceError: case Runtime::kThrowAccessedUninitializedVariable: case Runtime::kThrowStackOverflow: case Runtime::kThrowStaticPrototypeError: case Runtime::kThrowSuperAlreadyCalledError: case Runtime::kThrowSuperNotCalled: case Runtime::kThrowSymbolAsyncIteratorInvalid: case Runtime::kThrowSymbolIteratorInvalid: case Runtime::kThrowThrowMethodMissing: case Runtime::kThrowTypeError: case Runtime::kThrowUnsupportedSuperError: case Runtime::kTerminateExecution: #if V8_ENABLE_WEBASSEMBLY case Runtime::kThrowWasmError: case Runtime::kThrowWasmStackOverflow: #endif // V8_ENABLE_WEBASSEMBLY return false; default: return true; } } bool Runtime::IsNonReturning(FunctionId id) { switch (id) { case Runtime::kThrowUnsupportedSuperError: case Runtime::kThrowConstructorNonCallableError: case Runtime::kThrowStaticPrototypeError: case Runtime::kThrowSuperAlreadyCalledError: case Runtime::kThrowSuperNotCalled: case Runtime::kReThrow: case Runtime::kReThrowWithMessage: case Runtime::kThrow: case Runtime::kThrowTargetNonFunction: case Runtime::kThrowCalledNonCallable: case Runtime::kThrowConstructedNonConstructable: case Runtime::kThrowConstructorReturnedNonObject: case Runtime::kThrowInvalidStringLength: case Runtime::kThrowInvalidTypedArrayAlignment: case Runtime::kThrowIteratorError: case Runtime::kThrowIteratorResultNotAnObject: case Runtime::kThrowThrowMethodMissing: case Runtime::kThrowSymbolIteratorInvalid: case Runtime::kThrowNotConstructor: case Runtime::kThrowRangeError: case Runtime::kThrowReferenceError: case Runtime::kThrowAccessedUninitializedVariable: case Runtime::kThrowStackOverflow: case Runtime::kThrowSymbolAsyncIteratorInvalid: case Runtime::kThrowTypeError: case Runtime::kThrowConstAssignError: case Runtime::kTerminateExecution: #if V8_ENABLE_WEBASSEMBLY case Runtime::kThrowWasmError: case Runtime::kThrowWasmStackOverflow: case Runtime::kThrowWasmJSPISuspendError: case Runtime::kThrowWasmFXSuspendError: #endif // V8_ENABLE_WEBASSEMBLY return true; default: return false; } } bool Runtime::MayAllocate(FunctionId id) { switch (id) { case Runtime::kCompleteInobjectSlackTracking: case Runtime::kCompleteInobjectSlackTrackingForMap: case Runtime::kGlobalPrint: return false; default: return true; } } bool Runtime::IsEnabledForFuzzing(FunctionId id) { CHECK(v8_flags.fuzzing); // In general, all runtime functions meant for testing should also be exposed // to the fuzzers. That way, the fuzzers are able to import and mutate // regression tests that use those functions. Internal runtime functions // (which are e.g. only called from other builtins, etc.) should not directly // be exposed as they are not meant to be called directly from JavaScript. // However, exceptions exist: some test functions cannot be used for certain // types of fuzzing (e.g. differential fuzzing), or would cause false // positive crashes and therefore should not be exposed to fuzzers at all. // For differential fuzzing, only a handful of functions are allowed, // everything else is disabled. Many runtime functions are unsuited for // differential fuzzing as they for example expose internal engine state // (e.g. functions such as %HasFastProperties). To avoid having to maintain a // large denylist of such functions, we instead use an allowlist for // differential fuzzing. bool is_differential_fuzzing = v8_flags.allow_natives_for_differential_fuzzing; if (is_differential_fuzzing) { switch (id) { case Runtime::kArrayBufferDetach: case Runtime::kDeoptimizeFunction: case Runtime::kDeoptimizeNow: case Runtime::kDisableOptimizationFinalization: case Runtime::kEnableCodeLoggingForTesting: case Runtime::kFinalizeOptimization: case Runtime::kGetUndetectable: case Runtime::kNeverOptimizeFunction: case Runtime::kOptimizeFunctionOnNextCall: case Runtime::kOptimizeMaglevOnNextCall: case Runtime::kOptimizeOsr: case Runtime::kPrepareFunctionForOptimization: case Runtime::kPretenureAllocationSite: case Runtime::kSetAllocationTimeout: case Runtime::kSetForceSlowPath: case Runtime::kSimulateNewspaceFull: case Runtime::kWaitForBackgroundOptimization: case Runtime::kSetBatterySaverMode: case Runtime::kSetPriorityBestEffort: case Runtime::kSetPriorityUserVisible: case Runtime::kSetPriorityUserBlocking: case Runtime::kIsEfficiencyModeEnabled: case Runtime::kBaselineOsr: case Runtime::kCompileBaseline: #if V8_ENABLE_WEBASSEMBLY && V8_WASM_RANDOM_FUZZERS case Runtime::kWasmGenerateRandomModule: #endif // V8_ENABLE_WEBASSEMBLY && V8_WASM_RANDOM_FUZZERS #if V8_ENABLE_WEBASSEMBLY case Runtime::kWasmArray: case Runtime::kWasmStruct: case Runtime::kWasmTierUpFunction: case Runtime::kWasmTriggerTierUpForTesting: #endif // V8_ENABLE_WEBASSEMBLY return true; default: return false; } } // Runtime functions disabled for all/most types of fuzzing. // These are mainly functions that are not fuzzing-safe and therefore would // cause false-positive crashes (e.g. %AbortJS). switch (id) { case Runtime::kAbort: case Runtime::kAbortCSADcheck: case Runtime::kAbortJS: case Runtime::kSystemBreak: case Runtime::kBenchMaglev: case Runtime::kBenchTurbofan: case Runtime::kDebugPrintPtr: case Runtime::kDisassembleFunction: case Runtime::kGetFunctionForCurrentFrame: case Runtime::kGetCallable: case Runtime::kGetAbstractModuleSource: case Runtime::kTurbofanStaticAssert: case Runtime::kClearFunctionFeedback: case Runtime::kStringIsFlat: case Runtime::kGetInitializerFunction: case Runtime::kArrayBufferDetachForceWasm: #ifdef V8_ENABLE_WEBASSEMBLY case Runtime::kWasmTraceEnter: case Runtime::kWasmTraceExit: case Runtime::kWasmTraceMemory: case Runtime::kWasmTraceGlobal: case Runtime::kCheckIsOnCentralStack: case Runtime::kSetWasmInstantiateControls: case Runtime::kFreezeWasmLazyCompilation: #endif // V8_ENABLE_WEBASSEMBLY // TODO(353685107): investigate whether these should be exposed to fuzzers. case Runtime::kConstructDouble: // TODO(353971258): investigate whether this should be exposed to fuzzers. case Runtime::kSerializeDeserializeNow: // TODO(353928347): investigate whether this should be exposed to fuzzers. case Runtime::kCompleteInobjectSlackTracking: // TODO(354310130): investigate whether this should be exposed to fuzzers. case Runtime::kForceFlush: return false; case Runtime::kLeakHole: return v8_flags.hole_fuzzing; case Runtime::kGetBytecode: case Runtime::kInstallBytecode: // These are designed for sandbox fuzzing, specifically of the bytecode // verifier. They are not safe to be used during regular fuzzing as // * %GetBytecode exposes the objects in the BytecodeArray's constant // pool (which may be internal objects such as ScopeInfo) to the caller // * %InstallBytecode allows installing manipulated bytecode that has // only been checked for sandbox safety, not general correctness. return v8_flags.sandbox_testing || v8_flags.sandbox_fuzzing; default: break; } // The default case: test functions are exposed, everything else is not. switch (id) { // Functions used in testing and outside case Runtime::kArrayBufferDetach: #define F(name, nargs, ressize, ...) case k##name: #define I(name, nargs, ressize, ...) case kInline##name: FOR_EACH_INTRINSIC_TEST(F, I) IF_WASM(FOR_EACH_INTRINSIC_WASM_TEST, F, I) #undef I #undef F return true; default: return false; } } const Runtime::Function* Runtime::FunctionForName(const unsigned char* name, int length) { base::CallOnce(&initialize_function_name_map_once, &InitializeIntrinsicFunctionNames); IntrinsicFunctionIdentifier identifier(name, length); base::HashMap::Entry* entry = kRuntimeFunctionNameMap->Lookup(&identifier, identifier.Hash()); if (entry) { return reinterpret_cast<Function*>(entry->value); } return nullptr; } const Runtime::Function* Runtime::FunctionForEntry(Address entry) { for (size_t i = 0; i < arraysize(kIntrinsicFunctions); ++i) { if (entry == kIntrinsicFunctions[i].entry) { return &(kIntrinsicFunctions[i]); } } return nullptr; } const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) { return &(kIntrinsicFunctions[static_cast<int>(id)]); } const Runtime::Function* Runtime::RuntimeFunctionTable(Isolate* isolate) { #ifdef USE_SIMULATOR // When running with the simulator we need to provide a table which has // redirected runtime entry addresses. if (!isolate->runtime_state()->redirected_intrinsic_functions()) { size_t function_count = arraysize(kIntrinsicFunctions); Function* redirected_functions = new Function[function_count]; memcpy(redirected_functions, kIntrinsicFunctions, sizeof(kIntrinsicFunctions)); for (size_t i = 0; i < function_count; i++) { ExternalReference redirected_entry = ExternalReference::Create(static_cast<Runtime::FunctionId>(i)); redirected_functions[i].entry = redirected_entry.address(); } isolate->runtime_state()->set_redirected_intrinsic_functions( redirected_functions); } return isolate->runtime_state()->redirected_intrinsic_functions(); #else return kIntrinsicFunctions; #endif } std::ostream& operator<<(std::ostream& os, Runtime::FunctionId id) { return os << Runtime::FunctionForId(id)->name; } int g_num_isolates_for_testing = 1; } // namespace internal } // namespace v8