@@ -3179,7 +3179,109 @@ FrameSummaries OptimizedJSFrame::Summarize(bool never_allocate) const {
31793179 " Missing deoptimization information for OptimizedJSFrame::Summarize." );
31803180 }
31813181
3182- // Prepare iteration over translation. We must not materialize values here
3182+ // Lightweight walk: iterate frame headers only, resolving just the
3183+ // function and receiver from the live frame via ResolveTaggedValue.
3184+ // This avoids the expensive TranslatedState::Init + Prepare path that
3185+ // would parse every value in every inlined frame.
3186+
3187+ Tagged<DeoptimizationLiteralArray> literal_array = data->LiteralArray ();
3188+
3189+ // Lightweight walk: resolve function and receiver from live frame headers
3190+ // and build JavaScriptFrameSummary objects directly.
3191+ bool needs_full_walk = false ;
3192+ {
3193+ DisallowGarbageCollection no_gc;
3194+ DeoptimizationFrameTranslation::Iterator it (
3195+ data->FrameTranslation (), data->TranslationIndex (deopt_index).value ());
3196+ bool is_constructor = IsConstructor ();
3197+ int remaining = it.EnterBeginOpcode ().total_frame_count ;
3198+
3199+ while (remaining > 0 ) {
3200+ TranslationOpcode opcode = it.SeekNextFrame ();
3201+ remaining--;
3202+
3203+ if (opcode == TranslationOpcode::CONSTRUCT_CREATE_STUB_FRAME ||
3204+ opcode == TranslationOpcode::CONSTRUCT_INVOKE_STUB_FRAME ) {
3205+ is_constructor = true ;
3206+ it.SkipOperands (TranslationOpcodeOperandCount (opcode));
3207+ continue ;
3208+ }
3209+
3210+ if (!IsTranslationJsFrameOpcode (opcode)) {
3211+ #if V8_ENABLE_WEBASSEMBLY
3212+ // Wasm-inlined-into-JS frames need the full TranslatedState
3213+ // machinery to produce WasmFrameSummary entries.
3214+ if (opcode == TranslationOpcode::WASM_INLINED_INTO_JS_FRAME ) {
3215+ needs_full_walk = true ;
3216+ break ;
3217+ }
3218+ #endif
3219+ it.SkipOperands (TranslationOpcodeOperandCount (opcode));
3220+ continue ;
3221+ }
3222+
3223+ bool is_builtin_cont =
3224+ (opcode == TranslationOpcode::JAVASCRIPT_BUILTIN_CONTINUATION_FRAME ||
3225+ opcode == TranslationOpcode::
3226+ JAVASCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME );
3227+
3228+ int bytecode_offset = it.NextOperand ();
3229+ int sfi_id = it.NextOperand ();
3230+ Tagged<SharedFunctionInfo> sfi =
3231+ Cast<SharedFunctionInfo>(literal_array->get (sfi_id));
3232+
3233+ // Skip remaining header operands to reach the values.
3234+ it.SkipOperands (TranslationOpcodeOperandCount (opcode) - 2 );
3235+
3236+ // Resolve closure and receiver from the live frame. Both are always
3237+ // encoded as LITERAL or TAGGED_STACK_SLOT in the deopt translation.
3238+ Tagged<Object> function_obj =
3239+ TranslatedState::ResolveTaggedValue (&it, fp (), literal_array);
3240+ DCHECK (IsJSFunction (function_obj));
3241+ Tagged<Object> receiver_obj =
3242+ TranslatedState::ResolveTaggedValue (&it, fp (), literal_array);
3243+
3244+ Tagged<AbstractCode> abstract_code;
3245+ int code_offset;
3246+ if (is_builtin_cont) {
3247+ code_offset = 0 ;
3248+ abstract_code = Cast<AbstractCode>(
3249+ isolate ()->builtins ()->code (Builtins::GetBuiltinFromBytecodeOffset (
3250+ BytecodeOffset (bytecode_offset))));
3251+ } else {
3252+ code_offset = bytecode_offset;
3253+ abstract_code = Cast<AbstractCode>(sfi->GetBytecodeArray (isolate ()));
3254+ }
3255+
3256+ DirectHandle<FixedArray> params = GetParameters (never_allocate);
3257+ FrameSummary::JavaScriptFrameSummary summary (
3258+ isolate (), receiver_obj, Cast<JSFunction>(function_obj),
3259+ abstract_code, code_offset, is_constructor, *params);
3260+ summaries.frames .push_back (summary);
3261+ is_constructor = false ;
3262+ }
3263+
3264+ if (!needs_full_walk && is_constructor) {
3265+ summaries.top_frame_is_construct_call = true ;
3266+ }
3267+ } // no_gc scope ends.
3268+
3269+ if (needs_full_walk) {
3270+ return SummarizeFull (data, deopt_index, never_allocate);
3271+ }
3272+
3273+ return summaries;
3274+ }
3275+
3276+ FrameSummaries OptimizedJSFrame::SummarizeFull (Tagged<DeoptimizationData> data,
3277+ int deopt_index,
3278+ bool never_allocate) const {
3279+ FrameSummaries summaries;
3280+
3281+ DCHECK_NE (deopt_index, SafepointEntry::kNoDeoptIndex );
3282+ DCHECK (!data.is_null ());
3283+
3284+ // Prepare iteration over translation. We must not materialize values here
31833285 // because we do not deoptimize the function.
31843286 TranslatedState translated (this );
31853287 translated.Prepare (fp ());
@@ -3204,7 +3306,21 @@ FrameSummaries OptimizedJSFrame::Summarize(bool never_allocate) const {
32043306 // Get the correct receiver in the optimized frame.
32053307 static_assert (TranslatedFrame::kReceiverIsFirstParameterInJSFrames );
32063308 CHECK (!translated_values->IsMaterializedObject ());
3207- DirectHandle<Object> receiver = translated_values->GetValue ();
3309+ // Check GetRawValue() against arguments_marker() first to see whether
3310+ // calling GetValue() allocates.
3311+ Tagged<Object> receiver_obj = translated_values->GetRawValue ();
3312+ DirectHandle<Object> receiver;
3313+ if (receiver_obj == ReadOnlyRoots (isolate ()).arguments_marker () &&
3314+ never_allocate) {
3315+ // Calling GetValue() would definitely trigger allocation but with
3316+ // `never_allocate` allocations are not allowed. Simply pick `undefined`
3317+ // as receiver instead even though it is off. `never_allocate` is
3318+ // currently only used for OOM stacks, where we don't even emit the
3319+ // receiver but want to see as many stack frames as possible.
3320+ receiver = isolate ()->factory ()->undefined_value ();
3321+ } else {
3322+ receiver = translated_values->GetValue ();
3323+ }
32083324 translated_values++;
32093325
32103326 // Determine the underlying code object and the position within it from
@@ -3311,24 +3427,20 @@ int TurbofanJSFrame::FindReturnPCForTrampoline(Tagged<Code> code,
33113427 return safepoints.find_return_pc (trampoline_pc);
33123428}
33133429
3314- Tagged<DeoptimizationData> OptimizedJSFrame::GetDeoptimizationData (
3315- Tagged<Code> code, int * deopt_index) const {
3316- DCHECK (is_optimized ());
3317-
3318- Address pc = maybe_unauthenticated_pc ();
3319-
3320- DCHECK (code->contains (isolate (), pc));
3430+ // static
3431+ Tagged<DeoptimizationData> OptimizedJSFrame::GetDeoptimizationDataForPC (
3432+ Isolate* isolate, Tagged<Code> code, Address pc, int * deopt_index) {
3433+ DCHECK (code->contains (isolate, pc));
33213434 DCHECK (CodeKindCanDeoptimize (code->kind ()));
3322-
33233435 if (code->is_maglevved ()) {
33243436 MaglevSafepointEntry safepoint_entry =
3325- code->GetMaglevSafepointEntry (isolate () , pc);
3437+ code->GetMaglevSafepointEntry (isolate, pc);
33263438 if (safepoint_entry.has_deoptimization_index ()) {
33273439 *deopt_index = safepoint_entry.deoptimization_index ();
33283440 return code->deoptimization_data ();
33293441 }
33303442 } else {
3331- SafepointEntry safepoint_entry = code->GetSafepointEntry (isolate () , pc);
3443+ SafepointEntry safepoint_entry = code->GetSafepointEntry (isolate, pc);
33323444 if (safepoint_entry.has_deoptimization_index ()) {
33333445 *deopt_index = safepoint_entry.deoptimization_index ();
33343446 return code->deoptimization_data ();
@@ -3338,6 +3450,14 @@ Tagged<DeoptimizationData> OptimizedJSFrame::GetDeoptimizationData(
33383450 return {};
33393451}
33403452
3453+ Tagged<DeoptimizationData> OptimizedJSFrame::GetDeoptimizationData (
3454+ Tagged<Code> code, int * deopt_index) const {
3455+ DCHECK (is_optimized ());
3456+ Address pc = maybe_unauthenticated_pc ();
3457+ DCHECK (code->contains (isolate (), pc));
3458+ return GetDeoptimizationDataForPC (isolate (), code, pc, deopt_index);
3459+ }
3460+
33413461void OptimizedJSFrame::GetFunctions (
33423462 std::vector<Tagged<SharedFunctionInfo>>* functions) const {
33433463 DCHECK (functions->empty ());
0 commit comments