%PDF- %PDF-
Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/debug/ |
Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/debug/debug-evaluate.cc |
// Copyright 2015 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/debug/debug-evaluate.h" #include "src/builtins/accessors.h" #include "src/codegen/assembler-inl.h" #include "src/codegen/compiler.h" #include "src/codegen/reloc-info.h" #include "src/codegen/script-details.h" #include "src/common/globals.h" #include "src/debug/debug-frames.h" #include "src/debug/debug-scopes.h" #include "src/debug/debug.h" #include "src/execution/frames-inl.h" #include "src/execution/isolate-inl.h" #include "src/interpreter/bytecode-array-iterator.h" #include "src/interpreter/bytecodes.h" #include "src/objects/code-inl.h" #include "src/objects/contexts.h" #include "src/objects/string-set-inl.h" #if V8_ENABLE_WEBASSEMBLY #include "src/debug/debug-wasm-objects.h" #endif // V8_ENABLE_WEBASSEMBLY namespace v8 { namespace internal { namespace { static MaybeHandle<SharedFunctionInfo> GetFunctionInfo(Isolate* isolate, Handle<String> source, REPLMode repl_mode) { ScriptDetails script_details(isolate->factory()->empty_string(), ScriptOriginOptions(true, true)); script_details.repl_mode = repl_mode; return Compiler::GetSharedFunctionInfoForScript( isolate, source, script_details, ScriptCompiler::kNoCompileOptions, ScriptCompiler::kNoCacheNoReason, NOT_NATIVES_CODE); } } // namespace MaybeHandle<Object> DebugEvaluate::Global(Isolate* isolate, Handle<String> source, debug::EvaluateGlobalMode mode, REPLMode repl_mode) { Handle<SharedFunctionInfo> shared_info; if (!GetFunctionInfo(isolate, source, repl_mode).ToHandle(&shared_info)) { return MaybeHandle<Object>(); } Handle<NativeContext> context = isolate->native_context(); Handle<JSFunction> fun = Factory::JSFunctionBuilder{isolate, shared_info, context}.Build(); return Global(isolate, fun, mode, repl_mode); } MaybeHandle<Object> DebugEvaluate::Global(Isolate* isolate, Handle<JSFunction> function, debug::EvaluateGlobalMode mode, REPLMode repl_mode) { // Disable breaks in side-effect free mode. DisableBreak disable_break_scope( isolate->debug(), mode == debug::EvaluateGlobalMode::kDisableBreaks || mode == debug::EvaluateGlobalMode::kDisableBreaksAndThrowOnSideEffect); Handle<NativeContext> context = isolate->native_context(); CHECK_EQ(function->native_context(), *context); if (mode == debug::EvaluateGlobalMode::kDisableBreaksAndThrowOnSideEffect) { isolate->debug()->StartSideEffectCheckMode(); } // TODO(cbruni, 1244145): Use host-defined options from script context. Handle<FixedArray> host_defined_options( Script::cast(function->shared()->script())->host_defined_options(), isolate); MaybeHandle<Object> result = Execution::CallScript( isolate, function, Handle<JSObject>(context->global_proxy(), isolate), host_defined_options); if (mode == debug::EvaluateGlobalMode::kDisableBreaksAndThrowOnSideEffect) { isolate->debug()->StopSideEffectCheckMode(); } return result; } MaybeHandle<Object> DebugEvaluate::Local(Isolate* isolate, StackFrameId frame_id, int inlined_jsframe_index, Handle<String> source, bool throw_on_side_effect) { // Handle the processing of break. DisableBreak disable_break_scope(isolate->debug()); // Get the frame where the debugging is performed. DebuggableStackFrameIterator it(isolate, frame_id); #if V8_ENABLE_WEBASSEMBLY if (it.is_wasm()) { WasmFrame* frame = WasmFrame::cast(it.frame()); Handle<SharedFunctionInfo> outer_info( isolate->native_context()->empty_function()->shared(), isolate); Handle<JSObject> context_extension = GetWasmDebugProxy(frame); Handle<ScopeInfo> scope_info = ScopeInfo::CreateForWithScope(isolate, Handle<ScopeInfo>::null()); Handle<Context> context = isolate->factory()->NewWithContext( isolate->native_context(), scope_info, context_extension); return Evaluate(isolate, outer_info, context, context_extension, source, throw_on_side_effect); } #endif // V8_ENABLE_WEBASSEMBLY CHECK(it.is_javascript()); JavaScriptFrame* frame = it.javascript_frame(); // This is not a lot different than DebugEvaluate::Global, except that // variables accessible by the function we are evaluating from are // materialized and included on top of the native context. Changes to // the materialized object are written back afterwards. // Note that the native context is taken from the original context chain, // which may not be the current native context of the isolate. ContextBuilder context_builder(isolate, frame, inlined_jsframe_index); if (isolate->has_pending_exception()) return {}; Handle<Context> context = context_builder.evaluation_context(); Handle<JSObject> receiver(context->global_proxy(), isolate); MaybeHandle<Object> maybe_result = Evaluate(isolate, context_builder.outer_info(), context, receiver, source, throw_on_side_effect); if (!maybe_result.is_null()) context_builder.UpdateValues(); return maybe_result; } MaybeHandle<Object> DebugEvaluate::WithTopmostArguments(Isolate* isolate, Handle<String> source) { // Handle the processing of break. DisableBreak disable_break_scope(isolate->debug()); Factory* factory = isolate->factory(); JavaScriptStackFrameIterator it(isolate); // Get context and receiver. Handle<Context> native_context( Context::cast(it.frame()->context())->native_context(), isolate); // Materialize arguments as property on an extension object. Handle<JSObject> materialized = factory->NewSlowJSObjectWithNullProto(); Handle<String> arguments_str = factory->arguments_string(); JSObject::SetOwnPropertyIgnoreAttributes( materialized, arguments_str, Accessors::FunctionGetArguments(it.frame(), 0), NONE) .Check(); // Materialize receiver. Handle<Object> this_value(it.frame()->receiver(), isolate); DCHECK_EQ(it.frame()->IsConstructor(), IsTheHole(*this_value, isolate)); if (!IsTheHole(*this_value, isolate)) { Handle<String> this_str = factory->this_string(); JSObject::SetOwnPropertyIgnoreAttributes(materialized, this_str, this_value, NONE) .Check(); } // Use extension object in a debug-evaluate scope. Handle<ScopeInfo> scope_info = ScopeInfo::CreateForWithScope(isolate, Handle<ScopeInfo>::null()); scope_info->SetIsDebugEvaluateScope(); Handle<Context> evaluation_context = factory->NewDebugEvaluateContext( native_context, scope_info, materialized, Handle<Context>()); Handle<SharedFunctionInfo> outer_info( native_context->empty_function()->shared(), isolate); Handle<JSObject> receiver(native_context->global_proxy(), isolate); const bool throw_on_side_effect = false; MaybeHandle<Object> maybe_result = Evaluate(isolate, outer_info, evaluation_context, receiver, source, throw_on_side_effect); return maybe_result; } // Compile and evaluate source for the given context. MaybeHandle<Object> DebugEvaluate::Evaluate( Isolate* isolate, Handle<SharedFunctionInfo> outer_info, Handle<Context> context, Handle<Object> receiver, Handle<String> source, bool throw_on_side_effect) { Handle<JSFunction> eval_fun; ASSIGN_RETURN_ON_EXCEPTION( isolate, eval_fun, Compiler::GetFunctionFromEval( source, outer_info, context, LanguageMode::kSloppy, NO_PARSE_RESTRICTION, kNoSourcePosition, kNoSourcePosition, kNoSourcePosition, ParsingWhileDebugging::kYes), Object); Handle<Object> result; bool success = false; if (throw_on_side_effect) isolate->debug()->StartSideEffectCheckMode(); success = Execution::Call(isolate, eval_fun, receiver, 0, nullptr) .ToHandle(&result); if (throw_on_side_effect) isolate->debug()->StopSideEffectCheckMode(); if (!success) DCHECK(isolate->has_pending_exception()); return success ? result : MaybeHandle<Object>(); } Handle<SharedFunctionInfo> DebugEvaluate::ContextBuilder::outer_info() const { return handle(frame_inspector_.GetFunction()->shared(), isolate_); } DebugEvaluate::ContextBuilder::ContextBuilder(Isolate* isolate, JavaScriptFrame* frame, int inlined_jsframe_index) : isolate_(isolate), frame_inspector_(frame, inlined_jsframe_index, isolate), scope_iterator_(isolate, &frame_inspector_, ScopeIterator::ReparseStrategy::kScriptIfNeeded) { Handle<Context> outer_context(frame_inspector_.GetFunction()->context(), isolate); evaluation_context_ = outer_context; Factory* factory = isolate->factory(); if (scope_iterator_.Done()) return; // To evaluate as if we were running eval at the point of the debug break, // we reconstruct the context chain as follows: // - To make stack-allocated variables visible, we materialize them and // use a debug-evaluate context to wrap both the materialized object and // the original context. // - Each scope from the break position up to the function scope is wrapped // in a debug-evaluate context. // - Between the function scope and the native context, we only resolve // variable names that are guaranteed to not be shadowed by stack-allocated // variables. ScopeInfos between the function scope and the native // context have a blocklist attached to implement that. // - The various block lists are calculated by the ScopeIterator during // iteration. // Context::Lookup has special handling for debug-evaluate contexts: // - Look up in the materialized stack variables. // - Look up in the original context. // - Once we have seen a debug-evaluate context we start to take the // block lists into account before moving up the context chain. for (; scope_iterator_.InInnerScope(); scope_iterator_.Next()) { ScopeIterator::ScopeType scope_type = scope_iterator_.Type(); if (scope_type == ScopeIterator::ScopeTypeScript) break; ContextChainElement context_chain_element; if (scope_type == ScopeIterator::ScopeTypeLocal || scope_iterator_.DeclaresLocals(ScopeIterator::Mode::STACK)) { context_chain_element.materialized_object = scope_iterator_.ScopeObject(ScopeIterator::Mode::STACK); } if (scope_iterator_.HasContext()) { context_chain_element.wrapped_context = scope_iterator_.CurrentContext(); } context_chain_.push_back(context_chain_element); } Handle<ScopeInfo> scope_info = IsNativeContext(*evaluation_context_) ? Handle<ScopeInfo>::null() : handle(evaluation_context_->scope_info(), isolate); for (auto rit = context_chain_.rbegin(); rit != context_chain_.rend(); rit++) { ContextChainElement element = *rit; scope_info = ScopeInfo::CreateForWithScope(isolate, scope_info); scope_info->SetIsDebugEvaluateScope(); // In the case where the "paused function scope" is the script scope // itself, we don't need (and don't have) a blocklist. const bool paused_scope_is_script_scope = scope_iterator_.Done() || scope_iterator_.InInnerScope(); if (rit == context_chain_.rbegin() && !paused_scope_is_script_scope) { // The DebugEvaluateContext we create for the closure scope is the only // DebugEvaluateContext with a block list. This means we'll retrieve // the existing block list from the paused function scope // and also associate the temporary scope_info we create here with that // blocklist. Handle<ScopeInfo> function_scope_info = handle( frame_inspector_.GetFunction()->shared()->scope_info(), isolate_); Handle<Object> block_list = handle( isolate_->LocalsBlockListCacheGet(function_scope_info), isolate_); CHECK(IsStringSet(*block_list)); isolate_->LocalsBlockListCacheSet(scope_info, Handle<ScopeInfo>::null(), Handle<StringSet>::cast(block_list)); } evaluation_context_ = factory->NewDebugEvaluateContext( evaluation_context_, scope_info, element.materialized_object, element.wrapped_context); } } void DebugEvaluate::ContextBuilder::UpdateValues() { scope_iterator_.Restart(); for (ContextChainElement& element : context_chain_) { if (!element.materialized_object.is_null()) { Handle<FixedArray> keys = KeyAccumulator::GetKeys(isolate_, element.materialized_object, KeyCollectionMode::kOwnOnly, ENUMERABLE_STRINGS) .ToHandleChecked(); for (int i = 0; i < keys->length(); i++) { DCHECK(IsString(keys->get(i))); Handle<String> key(String::cast(keys->get(i)), isolate_); Handle<Object> value = JSReceiver::GetDataProperty( isolate_, element.materialized_object, key); scope_iterator_.SetVariableValue(key, value); } } scope_iterator_.Next(); } } // static bool DebugEvaluate::IsSideEffectFreeIntrinsic(Runtime::FunctionId id) { // Use macro to include only the non-inlined version of an intrinsic. #define INTRINSIC_ALLOWLIST(V) \ /* Conversions */ \ V(NumberToStringSlow) \ V(ToBigInt) \ V(ToLength) \ V(ToNumber) \ V(ToObject) \ V(ToString) \ /* Type checks */ \ V(IsArray) \ V(IsFunction) \ V(IsJSProxy) \ V(IsJSReceiver) \ V(IsRegExp) \ V(IsSmi) \ /* Loads */ \ V(LoadLookupSlotForCall) \ V(GetProperty) \ /* Arrays */ \ V(ArraySpeciesConstructor) \ V(HasFastPackedElements) \ V(NewArray) \ V(NormalizeElements) \ V(TypedArrayGetBuffer) \ /* Errors */ \ V(NewTypeError) \ V(ReThrow) \ V(ThrowCalledNonCallable) \ V(ThrowInvalidStringLength) \ V(ThrowIteratorError) \ V(ThrowIteratorResultNotAnObject) \ V(ThrowPatternAssignmentNonCoercible) \ V(ThrowReferenceError) \ V(ThrowSymbolIteratorInvalid) \ /* Strings */ \ V(StringReplaceOneCharWithString) \ V(StringSubstring) \ V(StringToNumber) \ /* BigInts */ \ V(BigIntEqualToBigInt) \ V(BigIntToBoolean) \ V(BigIntToNumber) \ /* Literals */ \ V(CreateArrayLiteral) \ V(CreateObjectLiteral) \ V(CreateRegExpLiteral) \ V(DefineClass) \ /* Called from builtins */ \ V(AllocateInYoungGeneration) \ V(AllocateInOldGeneration) \ V(AllocateSeqOneByteString) \ V(AllocateSeqTwoByteString) \ V(ArrayIncludes_Slow) \ V(ArrayIndexOf) \ V(ArrayIsArray) \ V(GetFunctionName) \ V(GetOwnPropertyDescriptor) \ V(GlobalPrint) \ V(HasProperty) \ V(ObjectCreate) \ V(ObjectEntries) \ V(ObjectEntriesSkipFastPath) \ V(ObjectHasOwnProperty) \ V(ObjectKeys) \ V(ObjectValues) \ V(ObjectValuesSkipFastPath) \ V(ObjectGetOwnPropertyNames) \ V(ObjectGetOwnPropertyNamesTryFast) \ V(ObjectIsExtensible) \ V(RegExpInitializeAndCompile) \ V(StackGuard) \ V(HandleNoHeapWritesInterrupts) \ V(StringAdd) \ V(StringCharCodeAt) \ V(StringEqual) \ V(StringParseFloat) \ V(StringParseInt) \ V(SymbolDescriptiveString) \ V(ThrowRangeError) \ V(ThrowTypeError) \ V(ToName) \ V(TransitionElementsKind) \ /* Misc. */ \ V(Call) \ V(CompleteInobjectSlackTrackingForMap) \ V(HasInPrototypeChain) \ V(IncrementUseCounter) \ V(MaxSmi) \ V(NewObject) \ V(StringMaxLength) \ V(StringToArray) \ V(AsyncFunctionEnter) \ V(AsyncFunctionResolve) \ /* Test */ \ V(GetOptimizationStatus) \ V(OptimizeFunctionOnNextCall) \ V(OptimizeOsr) // Intrinsics with inline versions have to be allowlisted here a second time. #define INLINE_INTRINSIC_ALLOWLIST(V) \ V(AsyncFunctionEnter) \ V(AsyncFunctionResolve) #define CASE(Name) case Runtime::k##Name: #define INLINE_CASE(Name) case Runtime::kInline##Name: switch (id) { INTRINSIC_ALLOWLIST(CASE) INLINE_INTRINSIC_ALLOWLIST(INLINE_CASE) return true; default: if (v8_flags.trace_side_effect_free_debug_evaluate) { PrintF("[debug-evaluate] intrinsic %s may cause side effect.\n", Runtime::FunctionForId(id)->name); } return false; } #undef CASE #undef INLINE_CASE #undef INTRINSIC_ALLOWLIST #undef INLINE_INTRINSIC_ALLOWLIST } namespace { bool BytecodeHasNoSideEffect(interpreter::Bytecode bytecode) { using interpreter::Bytecode; using interpreter::Bytecodes; if (Bytecodes::IsWithoutExternalSideEffects(bytecode)) return true; if (Bytecodes::IsCallOrConstruct(bytecode)) return true; if (Bytecodes::IsJumpIfToBoolean(bytecode)) return true; if (Bytecodes::IsPrefixScalingBytecode(bytecode)) return true; switch (bytecode) { // Allowlist for bytecodes. // Loads. case Bytecode::kLdaLookupSlot: case Bytecode::kLdaGlobal: case Bytecode::kGetNamedProperty: case Bytecode::kGetKeyedProperty: case Bytecode::kLdaGlobalInsideTypeof: case Bytecode::kLdaLookupSlotInsideTypeof: case Bytecode::kGetIterator: // Arithmetics. case Bytecode::kAdd: case Bytecode::kAddSmi: case Bytecode::kSub: case Bytecode::kSubSmi: case Bytecode::kMul: case Bytecode::kMulSmi: case Bytecode::kDiv: case Bytecode::kDivSmi: case Bytecode::kMod: case Bytecode::kModSmi: case Bytecode::kExp: case Bytecode::kExpSmi: case Bytecode::kNegate: case Bytecode::kBitwiseAnd: case Bytecode::kBitwiseAndSmi: case Bytecode::kBitwiseNot: case Bytecode::kBitwiseOr: case Bytecode::kBitwiseOrSmi: case Bytecode::kBitwiseXor: case Bytecode::kBitwiseXorSmi: case Bytecode::kShiftLeft: case Bytecode::kShiftLeftSmi: case Bytecode::kShiftRight: case Bytecode::kShiftRightSmi: case Bytecode::kShiftRightLogical: case Bytecode::kShiftRightLogicalSmi: case Bytecode::kInc: case Bytecode::kDec: case Bytecode::kLogicalNot: case Bytecode::kToBooleanLogicalNot: case Bytecode::kTypeOf: // Contexts. case Bytecode::kCreateBlockContext: case Bytecode::kCreateCatchContext: case Bytecode::kCreateFunctionContext: case Bytecode::kCreateEvalContext: case Bytecode::kCreateWithContext: // Literals. case Bytecode::kCreateArrayLiteral: case Bytecode::kCreateEmptyArrayLiteral: case Bytecode::kCreateArrayFromIterable: case Bytecode::kCreateObjectLiteral: case Bytecode::kCreateEmptyObjectLiteral: case Bytecode::kCreateRegExpLiteral: // Allocations. case Bytecode::kCreateClosure: case Bytecode::kCreateUnmappedArguments: case Bytecode::kCreateRestParameter: // Comparisons. case Bytecode::kTestEqual: case Bytecode::kTestEqualStrict: case Bytecode::kTestLessThan: case Bytecode::kTestLessThanOrEqual: case Bytecode::kTestGreaterThan: case Bytecode::kTestGreaterThanOrEqual: case Bytecode::kTestInstanceOf: case Bytecode::kTestIn: case Bytecode::kTestReferenceEqual: case Bytecode::kTestUndetectable: case Bytecode::kTestTypeOf: case Bytecode::kTestUndefined: case Bytecode::kTestNull: // Conversions. case Bytecode::kToObject: case Bytecode::kToName: case Bytecode::kToNumber: case Bytecode::kToNumeric: case Bytecode::kToString: case Bytecode::kToBoolean: // Misc. case Bytecode::kIncBlockCounter: // Coverage counters. case Bytecode::kForInEnumerate: case Bytecode::kForInPrepare: case Bytecode::kForInContinue: case Bytecode::kForInNext: case Bytecode::kForInStep: case Bytecode::kJumpLoop: case Bytecode::kThrow: case Bytecode::kReThrow: case Bytecode::kThrowReferenceErrorIfHole: case Bytecode::kThrowSuperNotCalledIfHole: case Bytecode::kThrowSuperAlreadyCalledIfNotHole: case Bytecode::kIllegal: case Bytecode::kCallJSRuntime: case Bytecode::kReturn: case Bytecode::kSetPendingMessage: return true; default: return false; } } DebugInfo::SideEffectState BuiltinGetSideEffectState(Builtin id) { switch (id) { // Allowlist for builtins. // Object builtins. case Builtin::kObjectConstructor: case Builtin::kObjectCreate: case Builtin::kObjectEntries: case Builtin::kObjectGetOwnPropertyDescriptor: case Builtin::kObjectGetOwnPropertyDescriptors: case Builtin::kObjectGetOwnPropertyNames: case Builtin::kObjectGetOwnPropertySymbols: case Builtin::kObjectGetPrototypeOf: case Builtin::kObjectGroupBy: case Builtin::kObjectHasOwn: case Builtin::kObjectIs: case Builtin::kObjectIsExtensible: case Builtin::kObjectIsFrozen: case Builtin::kObjectIsSealed: case Builtin::kObjectKeys: case Builtin::kObjectPrototypeValueOf: case Builtin::kObjectValues: case Builtin::kObjectPrototypeHasOwnProperty: case Builtin::kObjectPrototypeIsPrototypeOf: case Builtin::kObjectPrototypePropertyIsEnumerable: case Builtin::kObjectPrototypeToString: case Builtin::kObjectPrototypeToLocaleString: // Array builtins. case Builtin::kArrayIsArray: case Builtin::kArrayConstructor: case Builtin::kArrayIndexOf: case Builtin::kArrayPrototypeValues: case Builtin::kArrayIncludes: case Builtin::kArrayPrototypeAt: case Builtin::kArrayPrototypeConcat: case Builtin::kArrayPrototypeEntries: case Builtin::kArrayPrototypeFind: case Builtin::kArrayPrototypeFindIndex: case Builtin::kArrayPrototypeFindLast: case Builtin::kArrayPrototypeFindLastIndex: case Builtin::kArrayPrototypeFlat: case Builtin::kArrayPrototypeFlatMap: case Builtin::kArrayPrototypeJoin: case Builtin::kArrayPrototypeKeys: case Builtin::kArrayPrototypeLastIndexOf: case Builtin::kArrayPrototypeSlice: case Builtin::kArrayPrototypeToLocaleString: case Builtin::kArrayPrototypeToReversed: case Builtin::kArrayPrototypeToSorted: case Builtin::kArrayPrototypeToSpliced: case Builtin::kArrayPrototypeToString: case Builtin::kArrayPrototypeWith: case Builtin::kArrayForEach: case Builtin::kArrayEvery: case Builtin::kArraySome: case Builtin::kArrayConcat: case Builtin::kArrayFilter: case Builtin::kArrayMap: case Builtin::kArrayReduce: case Builtin::kArrayReduceRight: // Trace builtins. case Builtin::kIsTraceCategoryEnabled: case Builtin::kTrace: // TypedArray builtins. case Builtin::kTypedArrayConstructor: case Builtin::kTypedArrayOf: case Builtin::kTypedArrayPrototypeAt: case Builtin::kTypedArrayPrototypeBuffer: case Builtin::kTypedArrayPrototypeByteLength: case Builtin::kTypedArrayPrototypeByteOffset: case Builtin::kTypedArrayPrototypeLength: case Builtin::kTypedArrayPrototypeEntries: case Builtin::kTypedArrayPrototypeKeys: case Builtin::kTypedArrayPrototypeValues: case Builtin::kTypedArrayPrototypeFind: case Builtin::kTypedArrayPrototypeFindIndex: case Builtin::kTypedArrayPrototypeFindLast: case Builtin::kTypedArrayPrototypeFindLastIndex: case Builtin::kTypedArrayPrototypeIncludes: case Builtin::kTypedArrayPrototypeJoin: case Builtin::kTypedArrayPrototypeIndexOf: case Builtin::kTypedArrayPrototypeLastIndexOf: case Builtin::kTypedArrayPrototypeSlice: case Builtin::kTypedArrayPrototypeSubArray: case Builtin::kTypedArrayPrototypeEvery: case Builtin::kTypedArrayPrototypeSome: case Builtin::kTypedArrayPrototypeToLocaleString: case Builtin::kTypedArrayPrototypeFilter: case Builtin::kTypedArrayPrototypeMap: case Builtin::kTypedArrayPrototypeReduce: case Builtin::kTypedArrayPrototypeReduceRight: case Builtin::kTypedArrayPrototypeForEach: case Builtin::kTypedArrayPrototypeToReversed: case Builtin::kTypedArrayPrototypeToSorted: case Builtin::kTypedArrayPrototypeWith: // ArrayBuffer builtins. case Builtin::kArrayBufferConstructor: case Builtin::kArrayBufferPrototypeGetByteLength: case Builtin::kArrayBufferIsView: case Builtin::kArrayBufferPrototypeSlice: case Builtin::kReturnReceiver: // DataView builtins. case Builtin::kDataViewConstructor: case Builtin::kDataViewPrototypeGetBuffer: case Builtin::kDataViewPrototypeGetByteLength: case Builtin::kDataViewPrototypeGetByteOffset: case Builtin::kDataViewPrototypeGetInt8: case Builtin::kDataViewPrototypeGetUint8: case Builtin::kDataViewPrototypeGetInt16: case Builtin::kDataViewPrototypeGetUint16: case Builtin::kDataViewPrototypeGetInt32: case Builtin::kDataViewPrototypeGetUint32: case Builtin::kDataViewPrototypeGetFloat32: case Builtin::kDataViewPrototypeGetFloat64: case Builtin::kDataViewPrototypeGetBigInt64: case Builtin::kDataViewPrototypeGetBigUint64: // Boolean bulitins. case Builtin::kBooleanConstructor: case Builtin::kBooleanPrototypeToString: case Builtin::kBooleanPrototypeValueOf: // Date builtins. case Builtin::kDateConstructor: case Builtin::kDateNow: case Builtin::kDateParse: case Builtin::kDatePrototypeGetDate: case Builtin::kDatePrototypeGetDay: case Builtin::kDatePrototypeGetFullYear: case Builtin::kDatePrototypeGetHours: case Builtin::kDatePrototypeGetMilliseconds: case Builtin::kDatePrototypeGetMinutes: case Builtin::kDatePrototypeGetMonth: case Builtin::kDatePrototypeGetSeconds: case Builtin::kDatePrototypeGetTime: case Builtin::kDatePrototypeGetTimezoneOffset: case Builtin::kDatePrototypeGetUTCDate: case Builtin::kDatePrototypeGetUTCDay: case Builtin::kDatePrototypeGetUTCFullYear: case Builtin::kDatePrototypeGetUTCHours: case Builtin::kDatePrototypeGetUTCMilliseconds: case Builtin::kDatePrototypeGetUTCMinutes: case Builtin::kDatePrototypeGetUTCMonth: case Builtin::kDatePrototypeGetUTCSeconds: case Builtin::kDatePrototypeGetYear: case Builtin::kDatePrototypeToDateString: case Builtin::kDatePrototypeToISOString: case Builtin::kDatePrototypeToUTCString: case Builtin::kDatePrototypeToString: #ifdef V8_INTL_SUPPORT case Builtin::kDatePrototypeToLocaleString: case Builtin::kDatePrototypeToLocaleDateString: case Builtin::kDatePrototypeToLocaleTimeString: #endif case Builtin::kDatePrototypeToTimeString: case Builtin::kDatePrototypeToJson: case Builtin::kDatePrototypeToPrimitive: case Builtin::kDatePrototypeValueOf: // Map builtins. case Builtin::kMapConstructor: case Builtin::kMapGroupBy: case Builtin::kMapPrototypeForEach: case Builtin::kMapPrototypeGet: case Builtin::kMapPrototypeHas: case Builtin::kMapPrototypeEntries: case Builtin::kMapPrototypeGetSize: case Builtin::kMapPrototypeKeys: case Builtin::kMapPrototypeValues: // WeakMap builtins. case Builtin::kWeakMapConstructor: case Builtin::kWeakMapGet: case Builtin::kWeakMapPrototypeHas: // Math builtins. case Builtin::kMathAbs: case Builtin::kMathAcos: case Builtin::kMathAcosh: case Builtin::kMathAsin: case Builtin::kMathAsinh: case Builtin::kMathAtan: case Builtin::kMathAtanh: case Builtin::kMathAtan2: case Builtin::kMathCeil: case Builtin::kMathCbrt: case Builtin::kMathExpm1: case Builtin::kMathClz32: case Builtin::kMathCos: case Builtin::kMathCosh: case Builtin::kMathExp: case Builtin::kMathFloor: case Builtin::kMathFround: case Builtin::kMathHypot: case Builtin::kMathImul: case Builtin::kMathLog: case Builtin::kMathLog1p: case Builtin::kMathLog2: case Builtin::kMathLog10: case Builtin::kMathMax: case Builtin::kMathMin: case Builtin::kMathPow: case Builtin::kMathRound: case Builtin::kMathSign: case Builtin::kMathSin: case Builtin::kMathSinh: case Builtin::kMathSqrt: case Builtin::kMathTan: case Builtin::kMathTanh: case Builtin::kMathTrunc: // Number builtins. case Builtin::kNumberConstructor: case Builtin::kNumberIsFinite: case Builtin::kNumberIsInteger: case Builtin::kNumberIsNaN: case Builtin::kNumberIsSafeInteger: case Builtin::kNumberParseFloat: case Builtin::kNumberParseInt: case Builtin::kNumberPrototypeToExponential: case Builtin::kNumberPrototypeToFixed: case Builtin::kNumberPrototypeToPrecision: case Builtin::kNumberPrototypeToString: case Builtin::kNumberPrototypeToLocaleString: case Builtin::kNumberPrototypeValueOf: // BigInt builtins. case Builtin::kBigIntConstructor: case Builtin::kBigIntAsIntN: case Builtin::kBigIntAsUintN: case Builtin::kBigIntPrototypeToString: case Builtin::kBigIntPrototypeValueOf: // Set builtins. case Builtin::kSetConstructor: case Builtin::kSetPrototypeEntries: case Builtin::kSetPrototypeForEach: case Builtin::kSetPrototypeGetSize: case Builtin::kSetPrototypeHas: case Builtin::kSetPrototypeValues: // WeakSet builtins. case Builtin::kWeakSetConstructor: case Builtin::kWeakSetPrototypeHas: // String builtins. Strings are immutable. case Builtin::kStringFromCharCode: case Builtin::kStringFromCodePoint: case Builtin::kStringConstructor: case Builtin::kStringListFromIterable: case Builtin::kStringPrototypeAnchor: case Builtin::kStringPrototypeAt: case Builtin::kStringPrototypeBig: case Builtin::kStringPrototypeBlink: case Builtin::kStringPrototypeBold: case Builtin::kStringPrototypeCharAt: case Builtin::kStringPrototypeCharCodeAt: case Builtin::kStringPrototypeCodePointAt: case Builtin::kStringPrototypeConcat: case Builtin::kStringPrototypeEndsWith: case Builtin::kStringPrototypeFixed: case Builtin::kStringPrototypeFontcolor: case Builtin::kStringPrototypeFontsize: case Builtin::kStringPrototypeIncludes: case Builtin::kStringPrototypeIndexOf: case Builtin::kStringPrototypeIsWellFormed: case Builtin::kStringPrototypeItalics: case Builtin::kStringPrototypeLastIndexOf: case Builtin::kStringPrototypeLink: case Builtin::kStringPrototypeMatchAll: case Builtin::kStringPrototypePadEnd: case Builtin::kStringPrototypePadStart: case Builtin::kStringPrototypeRepeat: case Builtin::kStringPrototypeSlice: case Builtin::kStringPrototypeSmall: case Builtin::kStringPrototypeStartsWith: case Builtin::kStringSlowFlatten: case Builtin::kStringPrototypeStrike: case Builtin::kStringPrototypeSub: case Builtin::kStringPrototypeSubstr: case Builtin::kStringPrototypeSubstring: case Builtin::kStringPrototypeSup: case Builtin::kStringPrototypeToString: #ifndef V8_INTL_SUPPORT case Builtin::kStringPrototypeToLowerCase: case Builtin::kStringPrototypeToUpperCase: #endif case Builtin::kStringPrototypeToWellFormed: case Builtin::kStringPrototypeTrim: case Builtin::kStringPrototypeTrimEnd: case Builtin::kStringPrototypeTrimStart: case Builtin::kStringPrototypeValueOf: case Builtin::kStringToNumber: case Builtin::kStringSubstring: // Symbol builtins. case Builtin::kSymbolConstructor: case Builtin::kSymbolKeyFor: case Builtin::kSymbolPrototypeToString: case Builtin::kSymbolPrototypeValueOf: case Builtin::kSymbolPrototypeToPrimitive: // JSON builtins. case Builtin::kJsonParse: case Builtin::kJsonStringify: // Global function builtins. case Builtin::kGlobalDecodeURI: case Builtin::kGlobalDecodeURIComponent: case Builtin::kGlobalEncodeURI: case Builtin::kGlobalEncodeURIComponent: case Builtin::kGlobalEscape: case Builtin::kGlobalUnescape: case Builtin::kGlobalIsFinite: case Builtin::kGlobalIsNaN: // Function builtins. case Builtin::kFunctionPrototypeToString: case Builtin::kFunctionPrototypeBind: case Builtin::kFastFunctionPrototypeBind: case Builtin::kFunctionPrototypeCall: case Builtin::kFunctionPrototypeApply: // Error builtins. case Builtin::kErrorConstructor: // RegExp builtins. case Builtin::kRegExpConstructor: // Reflect builtins. case Builtin::kReflectApply: case Builtin::kReflectConstruct: case Builtin::kReflectGetOwnPropertyDescriptor: case Builtin::kReflectGetPrototypeOf: case Builtin::kReflectHas: case Builtin::kReflectIsExtensible: case Builtin::kReflectOwnKeys: // Internal. case Builtin::kStrictPoisonPillThrower: case Builtin::kAllocateInYoungGeneration: case Builtin::kAllocateInOldGeneration: case Builtin::kConstructVarargs: case Builtin::kConstructWithArrayLike: case Builtin::kGetOwnPropertyDescriptor: case Builtin::kOrdinaryGetOwnPropertyDescriptor: return DebugInfo::kHasNoSideEffect; #ifdef V8_INTL_SUPPORT // Intl builtins. case Builtin::kIntlGetCanonicalLocales: // Intl.Collator builtins. case Builtin::kCollatorConstructor: case Builtin::kCollatorInternalCompare: case Builtin::kCollatorPrototypeCompare: case Builtin::kCollatorPrototypeResolvedOptions: case Builtin::kCollatorSupportedLocalesOf: // Intl.DateTimeFormat builtins. case Builtin::kDateTimeFormatConstructor: case Builtin::kDateTimeFormatInternalFormat: case Builtin::kDateTimeFormatPrototypeFormat: case Builtin::kDateTimeFormatPrototypeFormatRange: case Builtin::kDateTimeFormatPrototypeFormatRangeToParts: case Builtin::kDateTimeFormatPrototypeFormatToParts: case Builtin::kDateTimeFormatPrototypeResolvedOptions: case Builtin::kDateTimeFormatSupportedLocalesOf: // Intl.DisplayNames builtins. case Builtin::kDisplayNamesConstructor: case Builtin::kDisplayNamesPrototypeOf: case Builtin::kDisplayNamesPrototypeResolvedOptions: case Builtin::kDisplayNamesSupportedLocalesOf: // Intl.ListFormat builtins. case Builtin::kListFormatConstructor: case Builtin::kListFormatPrototypeFormat: case Builtin::kListFormatPrototypeFormatToParts: case Builtin::kListFormatPrototypeResolvedOptions: case Builtin::kListFormatSupportedLocalesOf: // Intl.Locale builtins. case Builtin::kLocaleConstructor: case Builtin::kLocalePrototypeBaseName: case Builtin::kLocalePrototypeCalendar: case Builtin::kLocalePrototypeCalendars: case Builtin::kLocalePrototypeCaseFirst: case Builtin::kLocalePrototypeCollation: case Builtin::kLocalePrototypeCollations: case Builtin::kLocalePrototypeGetCalendars: case Builtin::kLocalePrototypeGetCollations: case Builtin::kLocalePrototypeGetHourCycles: case Builtin::kLocalePrototypeGetNumberingSystems: case Builtin::kLocalePrototypeGetTextInfo: case Builtin::kLocalePrototypeGetTimeZones: case Builtin::kLocalePrototypeGetWeekInfo: case Builtin::kLocalePrototypeHourCycle: case Builtin::kLocalePrototypeHourCycles: case Builtin::kLocalePrototypeLanguage: case Builtin::kLocalePrototypeMaximize: case Builtin::kLocalePrototypeMinimize: case Builtin::kLocalePrototypeNumeric: case Builtin::kLocalePrototypeNumberingSystem: case Builtin::kLocalePrototypeNumberingSystems: case Builtin::kLocalePrototypeRegion: case Builtin::kLocalePrototypeScript: case Builtin::kLocalePrototypeTextInfo: case Builtin::kLocalePrototypeTimeZones: case Builtin::kLocalePrototypeToString: case Builtin::kLocalePrototypeWeekInfo: // Intl.NumberFormat builtins. case Builtin::kNumberFormatConstructor: case Builtin::kNumberFormatInternalFormatNumber: case Builtin::kNumberFormatPrototypeFormatNumber: case Builtin::kNumberFormatPrototypeFormatToParts: case Builtin::kNumberFormatPrototypeResolvedOptions: case Builtin::kNumberFormatSupportedLocalesOf: // Intl.PluralRules builtins. case Builtin::kPluralRulesConstructor: case Builtin::kPluralRulesPrototypeResolvedOptions: case Builtin::kPluralRulesPrototypeSelect: case Builtin::kPluralRulesSupportedLocalesOf: // Intl.RelativeTimeFormat builtins. case Builtin::kRelativeTimeFormatConstructor: case Builtin::kRelativeTimeFormatPrototypeFormat: case Builtin::kRelativeTimeFormatPrototypeFormatToParts: case Builtin::kRelativeTimeFormatPrototypeResolvedOptions: case Builtin::kRelativeTimeFormatSupportedLocalesOf: return DebugInfo::kHasNoSideEffect; #endif // V8_INTL_SUPPORT // Set builtins. case Builtin::kSetIteratorPrototypeNext: case Builtin::kSetPrototypeAdd: case Builtin::kSetPrototypeClear: case Builtin::kSetPrototypeDelete: // Array builtins. case Builtin::kArrayIteratorPrototypeNext: case Builtin::kArrayPrototypeFill: case Builtin::kArrayPrototypePop: case Builtin::kArrayPrototypePush: case Builtin::kArrayPrototypeReverse: case Builtin::kArrayPrototypeShift: case Builtin::kArrayPrototypeUnshift: case Builtin::kArrayPrototypeSort: case Builtin::kArrayPrototypeSplice: case Builtin::kArrayUnshift: // Map builtins. case Builtin::kMapIteratorPrototypeNext: case Builtin::kMapPrototypeClear: case Builtin::kMapPrototypeDelete: case Builtin::kMapPrototypeSet: // Date builtins. case Builtin::kDatePrototypeSetDate: case Builtin::kDatePrototypeSetFullYear: case Builtin::kDatePrototypeSetHours: case Builtin::kDatePrototypeSetMilliseconds: case Builtin::kDatePrototypeSetMinutes: case Builtin::kDatePrototypeSetMonth: case Builtin::kDatePrototypeSetSeconds: case Builtin::kDatePrototypeSetTime: case Builtin::kDatePrototypeSetUTCDate: case Builtin::kDatePrototypeSetUTCFullYear: case Builtin::kDatePrototypeSetUTCHours: case Builtin::kDatePrototypeSetUTCMilliseconds: case Builtin::kDatePrototypeSetUTCMinutes: case Builtin::kDatePrototypeSetUTCMonth: case Builtin::kDatePrototypeSetUTCSeconds: case Builtin::kDatePrototypeSetYear: // RegExp builtins. case Builtin::kRegExpPrototypeTest: case Builtin::kRegExpPrototypeExec: case Builtin::kRegExpPrototypeSplit: case Builtin::kRegExpPrototypeFlagsGetter: case Builtin::kRegExpPrototypeGlobalGetter: case Builtin::kRegExpPrototypeHasIndicesGetter: case Builtin::kRegExpPrototypeIgnoreCaseGetter: case Builtin::kRegExpPrototypeMatchAll: case Builtin::kRegExpPrototypeMultilineGetter: case Builtin::kRegExpPrototypeDotAllGetter: case Builtin::kRegExpPrototypeUnicodeGetter: case Builtin::kRegExpPrototypeStickyGetter: return DebugInfo::kRequiresRuntimeChecks; default: if (v8_flags.trace_side_effect_free_debug_evaluate) { PrintF("[debug-evaluate] built-in %s may cause side effect.\n", Builtins::name(id)); } return DebugInfo::kHasSideEffects; } } bool BytecodeRequiresRuntimeCheck(interpreter::Bytecode bytecode) { using interpreter::Bytecode; switch (bytecode) { case Bytecode::kSetNamedProperty: case Bytecode::kDefineNamedOwnProperty: case Bytecode::kSetKeyedProperty: case Bytecode::kStaInArrayLiteral: case Bytecode::kDefineKeyedOwnPropertyInLiteral: case Bytecode::kStaCurrentContextSlot: return true; default: return interpreter::Bytecodes::IsCallRuntime(bytecode); } } } // anonymous namespace // static DebugInfo::SideEffectState DebugEvaluate::FunctionGetSideEffectState( Isolate* isolate, Handle<SharedFunctionInfo> info) { if (v8_flags.trace_side_effect_free_debug_evaluate) { PrintF("[debug-evaluate] Checking function %s for side effect.\n", info->DebugNameCStr().get()); } DCHECK(info->is_compiled()); DCHECK(!info->needs_script_context()); if (info->HasBytecodeArray()) { // Check bytecodes against allowlist. Handle<BytecodeArray> bytecode_array(info->GetBytecodeArray(isolate), isolate); if (v8_flags.trace_side_effect_free_debug_evaluate) { Print(*bytecode_array); } bool requires_runtime_checks = false; for (interpreter::BytecodeArrayIterator it(bytecode_array); !it.done(); it.Advance()) { interpreter::Bytecode bytecode = it.current_bytecode(); if (BytecodeHasNoSideEffect(bytecode)) continue; if (BytecodeRequiresRuntimeCheck(bytecode)) { requires_runtime_checks = true; continue; } if (v8_flags.trace_side_effect_free_debug_evaluate) { PrintF("[debug-evaluate] bytecode %s may cause side effect.\n", interpreter::Bytecodes::ToString(bytecode)); } // Did not match allowlist. return DebugInfo::kHasSideEffects; } return requires_runtime_checks ? DebugInfo::kRequiresRuntimeChecks : DebugInfo::kHasNoSideEffect; } else if (info->IsApiFunction()) { Tagged<Code> code = info->GetCode(isolate); if (code->is_builtin()) { return code->builtin_id() == Builtin::kHandleApiCallOrConstruct ? DebugInfo::kHasNoSideEffect : DebugInfo::kHasSideEffects; } } else { // Check built-ins against allowlist. Builtin builtin = info->HasBuiltinId() ? info->builtin_id() : Builtin::kNoBuiltinId; if (!Builtins::IsBuiltinId(builtin)) return DebugInfo::kHasSideEffects; DebugInfo::SideEffectState state = BuiltinGetSideEffectState(builtin); return state; } return DebugInfo::kHasSideEffects; } #ifdef DEBUG static bool TransitivelyCalledBuiltinHasNoSideEffect(Builtin caller, Builtin callee) { switch (callee) { // Transitively called Builtins: case Builtin::kAbort: case Builtin::kAbortCSADcheck: case Builtin::kAdaptorWithBuiltinExitFrame: case Builtin::kArrayConstructorImpl: case Builtin::kArrayEveryLoopContinuation: case Builtin::kArrayFilterLoopContinuation: case Builtin::kArrayFindIndexLoopContinuation: case Builtin::kArrayFindLoopContinuation: case Builtin::kArrayFindLastIndexLoopContinuation: case Builtin::kArrayFindLastLoopContinuation: case Builtin::kArrayForEachLoopContinuation: case Builtin::kArrayIncludesHoleyDoubles: case Builtin::kArrayIncludesPackedDoubles: case Builtin::kArrayIncludesSmi: case Builtin::kArrayIncludesSmiOrObject: case Builtin::kArrayIndexOfHoleyDoubles: case Builtin::kArrayIndexOfPackedDoubles: case Builtin::kArrayIndexOfSmi: case Builtin::kArrayIndexOfSmiOrObject: case Builtin::kArrayMapLoopContinuation: case Builtin::kArrayReduceLoopContinuation: case Builtin::kArrayReduceRightLoopContinuation: case Builtin::kArraySomeLoopContinuation: case Builtin::kArrayTimSort: case Builtin::kArrayTimSortIntoCopy: case Builtin::kCall_ReceiverIsAny: case Builtin::kCall_ReceiverIsNotNullOrUndefined: case Builtin::kCall_ReceiverIsNullOrUndefined: case Builtin::kCallWithArrayLike: case Builtin::kCEntry_Return1_ArgvOnStack_NoBuiltinExit: case Builtin::kCEntry_Return1_ArgvOnStack_BuiltinExit: case Builtin::kCEntry_Return1_ArgvInRegister_NoBuiltinExit: case Builtin::kCEntry_Return2_ArgvOnStack_NoBuiltinExit: case Builtin::kCEntry_Return2_ArgvOnStack_BuiltinExit: case Builtin::kCEntry_Return2_ArgvInRegister_NoBuiltinExit: case Builtin::kWasmCEntry: case Builtin::kCloneFastJSArray: case Builtin::kConstruct: case Builtin::kConvertToLocaleString: case Builtin::kCreateTypedArray: case Builtin::kDirectCEntry: case Builtin::kDoubleToI: case Builtin::kExtractFastJSArray: case Builtin::kFastNewObject: case Builtin::kFindOrderedHashMapEntry: case Builtin::kFindOrderedHashSetEntry: case Builtin::kFlatMapIntoArray: case Builtin::kFlattenIntoArray: case Builtin::kGenericArrayToReversed: case Builtin::kGenericArrayWith: case Builtin::kGetProperty: case Builtin::kGetPropertyWithReceiver: case Builtin::kGroupByGeneric: case Builtin::kHasProperty: case Builtin::kCreateHTML: case Builtin::kNonNumberToNumber: case Builtin::kNonPrimitiveToPrimitive_Number: case Builtin::kNumberToString: case Builtin::kObjectToString: case Builtin::kOrderedHashTableHealIndex: case Builtin::kOrdinaryToPrimitive_Number: case Builtin::kOrdinaryToPrimitive_String: case Builtin::kParseInt: case Builtin::kProxyHasProperty: case Builtin::kProxyIsExtensible: case Builtin::kProxyGetPrototypeOf: case Builtin::kRecordWriteSaveFP: case Builtin::kRecordWriteIgnoreFP: case Builtin::kStringAdd_CheckNone: case Builtin::kStringEqual: case Builtin::kStringIndexOf: case Builtin::kStringRepeat: case Builtin::kBigIntEqual: case Builtin::kToInteger: case Builtin::kToLength: case Builtin::kToName: case Builtin::kToObject: case Builtin::kToString: case Builtin::kTypedArrayMergeSort: #ifdef V8_IS_TSAN case Builtin::kTSANRelaxedStore8IgnoreFP: case Builtin::kTSANRelaxedStore8SaveFP: case Builtin::kTSANRelaxedStore16IgnoreFP: case Builtin::kTSANRelaxedStore16SaveFP: case Builtin::kTSANRelaxedStore32IgnoreFP: case Builtin::kTSANRelaxedStore32SaveFP: case Builtin::kTSANRelaxedStore64IgnoreFP: case Builtin::kTSANRelaxedStore64SaveFP: case Builtin::kTSANSeqCstStore8IgnoreFP: case Builtin::kTSANSeqCstStore8SaveFP: case Builtin::kTSANSeqCstStore16IgnoreFP: case Builtin::kTSANSeqCstStore16SaveFP: case Builtin::kTSANSeqCstStore32IgnoreFP: case Builtin::kTSANSeqCstStore32SaveFP: case Builtin::kTSANSeqCstStore64IgnoreFP: case Builtin::kTSANSeqCstStore64SaveFP: case Builtin::kTSANRelaxedLoad32IgnoreFP: case Builtin::kTSANRelaxedLoad32SaveFP: case Builtin::kTSANRelaxedLoad64IgnoreFP: case Builtin::kTSANRelaxedLoad64SaveFP: #endif // V8_IS_TSAN case Builtin::kWeakMapLookupHashIndex: return true; case Builtin::kJoinStackPop: case Builtin::kJoinStackPush: switch (caller) { case Builtin::kArrayPrototypeJoin: case Builtin::kArrayPrototypeToLocaleString: case Builtin::kTypedArrayPrototypeJoin: case Builtin::kTypedArrayPrototypeToLocaleString: return true; default: return false; } case Builtin::kFastCreateDataProperty: switch (caller) { case Builtin::kArrayPrototypeSlice: case Builtin::kArrayPrototypeToSpliced: case Builtin::kArrayPrototypeWith: case Builtin::kArrayFilter: return true; default: return false; } case Builtin::kSetProperty: switch (caller) { case Builtin::kArrayPrototypeSlice: case Builtin::kArrayPrototypeToSorted: case Builtin::kTypedArrayPrototypeMap: case Builtin::kStringPrototypeMatchAll: return true; default: return false; } default: return false; } } // static void DebugEvaluate::VerifyTransitiveBuiltins(Isolate* isolate) { // TODO(yangguo): also check runtime calls. bool failed = false; bool sanity_check = false; for (Builtin caller = Builtins::kFirst; caller <= Builtins::kLast; ++caller) { DebugInfo::SideEffectState state = BuiltinGetSideEffectState(caller); if (state != DebugInfo::kHasNoSideEffect) continue; Tagged<Code> code = isolate->builtins()->code(caller); int mode = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) | RelocInfo::ModeMask(RelocInfo::RELATIVE_CODE_TARGET); for (RelocIterator it(code, mode); !it.done(); it.next()) { RelocInfo* rinfo = it.rinfo(); DCHECK(RelocInfo::IsCodeTargetMode(rinfo->rmode())); Tagged<Code> lookup_result = isolate->heap()->FindCodeForInnerPointer(rinfo->target_address()); Builtin callee = lookup_result->builtin_id(); if (BuiltinGetSideEffectState(callee) == DebugInfo::kHasNoSideEffect) { continue; } if (TransitivelyCalledBuiltinHasNoSideEffect(caller, callee)) { sanity_check = true; continue; } PrintF("Allowlisted builtin %s calls non-allowlisted builtin %s\n", Builtins::name(caller), Builtins::name(callee)); failed = true; } } CHECK(!failed); #if defined(V8_TARGET_ARCH_PPC) || defined(V8_TARGET_ARCH_PPC64) || \ defined(V8_TARGET_ARCH_MIPS64) || defined(V8_TARGET_ARCH_RISCV32) || \ defined(V8_TARGET_ARCH_RISCV64) // Isolate-independent builtin calls and jumps do not emit reloc infos // on PPC. We try to avoid using PC relative code due to performance // issue with especially older hardwares. // MIPS64 doesn't have PC relative code currently. // TODO(mips): Add PC relative code to MIPS64. USE(sanity_check); #else CHECK(sanity_check); #endif } #endif // DEBUG // static void DebugEvaluate::ApplySideEffectChecks( Handle<BytecodeArray> bytecode_array) { for (interpreter::BytecodeArrayIterator it(bytecode_array); !it.done(); it.Advance()) { interpreter::Bytecode bytecode = it.current_bytecode(); if (BytecodeRequiresRuntimeCheck(bytecode)) it.ApplyDebugBreak(); } } } // namespace internal } // namespace v8