Skip to content

Commit d83195c

Browse files
schuayaduh95
andcommitted
deps: V8: backport 1a0089053443
Original commit message: [stack traces] Fall back to full walk when receiver is unboxed The lightweight OptimizedJSFrame::Summarize path added in crrev.com/c/7722138 assumed that closure and receiver are always encoded as LITERAL or TAGGED_STACK_SLOT in the deopt translation. This holds for the closure (a JSFunction reference is always tagged) but not for the receiver: the "receiver" slot in an InterpretedFrame translation is just parameter 0 of the (possibly inlined) frame and is emitted via BuildDeoptFrameSingleValue, which encodes it according to the value's representation. An inlined frame whose `this` was typed as Float64 ends up as DOUBLE_STACK_SLOT, hitting UNREACHABLE in ResolveTaggedValue. Rename ResolveTaggedValue to TryResolveTaggedValue, return std::optional, and fall back to SummarizeFull when the receiver isn't a directly-resolvable tagged value. Fixed: 499260582 Change-Id: I1f9cdd28e4b6b76a253a46e43b248d9239a4ecd8 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7748309 Auto-Submit: Jakob Linke <jgruber@chromium.org> Reviewed-by: Leszek Swirski <leszeks@chromium.org> Commit-Queue: Leszek Swirski <leszeks@chromium.org> Commit-Queue: Jakob Linke <jgruber@chromium.org> Cr-Commit-Position: refs/heads/main@{#106423} Refs: v8/v8@1a00890 Co-authored-by: Antoine du Hamel <duhamelantoine1995@gmail.com> PR-URL: #65764 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Filip Skokan <panva.ip@gmail.com>
1 parent 2f0cfb6 commit d83195c

5 files changed

Lines changed: 48 additions & 13 deletions

File tree

common.gypi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343

4444
# Reset this number to 0 on major V8 upgrades.
4545
# Increment by one for each non-official patch applied to deps/v8.
46-
'v8_embedder_string': '-node.31',
46+
'v8_embedder_string': '-node.32',
4747

4848
##### V8 defaults for Node.js #####
4949

deps/v8/src/deoptimizer/translated-state.cc

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1890,7 +1890,7 @@ Address TranslatedState::DecompressIfNeeded(intptr_t value) {
18901890
}
18911891

18921892
// static
1893-
Tagged<Object> TranslatedState::ResolveTaggedValue(
1893+
std::optional<Tagged<Object>> TranslatedState::TryResolveTaggedValue(
18941894
DeoptTranslationIterator* it, Address fp,
18951895
Tagged<DeoptimizationLiteralArray> literals) {
18961896
TranslationOpcode opcode = it->NextOpcode();
@@ -1906,7 +1906,11 @@ Tagged<Object> TranslatedState::ResolveTaggedValue(
19061906
return Tagged<Object>(DecompressIfNeeded(value));
19071907
}
19081908
default:
1909-
UNREACHABLE();
1909+
// Any other encoding (unboxed numerics, register-resident values,
1910+
// captured objects, etc.) requires the full TranslatedState path to
1911+
// materialize. Caller should fall back.
1912+
it->SkipOperands(TranslationOpcodeOperandCount(opcode));
1913+
return std::nullopt;
19101914
}
19111915
}
19121916

deps/v8/src/deoptimizer/translated-state.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -513,8 +513,10 @@ class TranslatedState {
513513

514514
// Resolves one deopt translation value opcode to a raw Tagged<Object>,
515515
// reading from the live frame if needed. Only LITERAL and
516-
// TAGGED_STACK_SLOT are expected; other opcodes are UNREACHABLE.
517-
static Tagged<Object> ResolveTaggedValue(
516+
// TAGGED_STACK_SLOT can be resolved cheaply; for any other opcode the
517+
// iterator is left positioned just past the opcode and std::nullopt is
518+
// returned so the caller can fall back to the full materialization path.
519+
static std::optional<Tagged<Object>> TryResolveTaggedValue(
518520
DeoptTranslationIterator* it, Address fp,
519521
Tagged<DeoptimizationLiteralArray> literals);
520522

deps/v8/src/execution/frames.cc

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3233,13 +3233,22 @@ FrameSummaries OptimizedJSFrame::Summarize(bool never_allocate) const {
32333233
// Skip remaining header operands to reach the values.
32343234
it.SkipOperands(TranslationOpcodeOperandCount(opcode) - 2);
32353235

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);
3236+
// Resolve closure and receiver from the live frame. The closure is
3237+
// always tagged (LITERAL or TAGGED_STACK_SLOT), but the receiver is
3238+
// just parameter 0 of the (possibly inlined) frame and may be encoded
3239+
// in any representation the optimizer chose (e.g. DOUBLE_STACK_SLOT
3240+
// for an unboxed Float64). Fall back to the full materialization path
3241+
// in that case.
3242+
std::optional<Tagged<Object>> function_obj =
3243+
TranslatedState::TryResolveTaggedValue(&it, fp(), literal_array);
3244+
DCHECK(function_obj.has_value());
3245+
DCHECK(IsJSFunction(*function_obj));
3246+
std::optional<Tagged<Object>> receiver_obj =
3247+
TranslatedState::TryResolveTaggedValue(&it, fp(), literal_array);
3248+
if (!receiver_obj.has_value()) {
3249+
needs_full_walk = true;
3250+
break;
3251+
}
32433252

32443253
Tagged<AbstractCode> abstract_code;
32453254
int code_offset;
@@ -3255,7 +3264,7 @@ FrameSummaries OptimizedJSFrame::Summarize(bool never_allocate) const {
32553264

32563265
DirectHandle<FixedArray> params = GetParameters(never_allocate);
32573266
FrameSummary::JavaScriptFrameSummary summary(
3258-
isolate(), receiver_obj, Cast<JSFunction>(function_obj),
3267+
isolate(), *receiver_obj, Cast<JSFunction>(*function_obj),
32593268
abstract_code, code_offset, is_constructor, *params);
32603269
summaries.frames.push_back(summary);
32613270
is_constructor = false;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2026 the V8 project authors. All rights reserved.
2+
// Use of this source code governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Flags: --allow-natives-syntax --jit-fuzzing --single-threaded
6+
7+
function f9(a10, a11) {
8+
'use strict';
9+
for (let v12 = 0; v12 < 5; v12++) {
10+
const v15 = ({ maxByteLength: 1073741824 }).maxByteLength;
11+
%OptimizeOsr();
12+
function F16(a18, a19, a20) {
13+
if (!new.target) { throw 'must be called with new'; }
14+
}
15+
try { F16.call(v15); } catch (e) {}
16+
}
17+
return f9;
18+
}
19+
%PrepareFunctionForOptimization(f9);
20+
f9(f9, f9);

0 commit comments

Comments
 (0)