mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 10:15:07 +08:00
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: https://github.com/v8/v8/commit/1a0089053443ae4001fd15b84f1b46f330a0b3fa
Co-authored-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65764
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
This commit is contained in:
1 parent
7a4654c501
commit
a3f0041e8f
5 files changed
+48
-13
No files matched your search
+1
-1
@@ -43,7 +43,7 @@
|
||||
|
||||
# Reset this number to 0 on major V8 upgrades.
|
||||
# Increment by one for each non-official patch applied to deps/v8.
|
||||
'v8_embedder_string': '-node.31',
|
||||
'v8_embedder_string': '-node.32',
|
||||
|
||||
##### V8 defaults for Node.js #####
|
||||
|
||||
|
||||
+6
-2
@@ -1890,7 +1890,7 @@ Address TranslatedState::DecompressIfNeeded(intptr_t value) {
|
||||
}
|
||||
|
||||
// static
|
||||
Tagged<Object> TranslatedState::ResolveTaggedValue(
|
||||
std::optional<Tagged<Object>> TranslatedState::TryResolveTaggedValue(
|
||||
DeoptTranslationIterator* it, Address fp,
|
||||
Tagged<DeoptimizationLiteralArray> literals) {
|
||||
TranslationOpcode opcode = it->NextOpcode();
|
||||
@@ -1906,7 +1906,11 @@ Tagged<Object> TranslatedState::ResolveTaggedValue(
|
||||
return Tagged<Object>(DecompressIfNeeded(value));
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
// Any other encoding (unboxed numerics, register-resident values,
|
||||
// captured objects, etc.) requires the full TranslatedState path to
|
||||
// materialize. Caller should fall back.
|
||||
it->SkipOperands(TranslationOpcodeOperandCount(opcode));
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -513,8 +513,10 @@ class TranslatedState {
|
||||
|
||||
// Resolves one deopt translation value opcode to a raw Tagged<Object>,
|
||||
// reading from the live frame if needed. Only LITERAL and
|
||||
// TAGGED_STACK_SLOT are expected; other opcodes are UNREACHABLE.
|
||||
static Tagged<Object> ResolveTaggedValue(
|
||||
// TAGGED_STACK_SLOT can be resolved cheaply; for any other opcode the
|
||||
// iterator is left positioned just past the opcode and std::nullopt is
|
||||
// returned so the caller can fall back to the full materialization path.
|
||||
static std::optional<Tagged<Object>> TryResolveTaggedValue(
|
||||
DeoptTranslationIterator* it, Address fp,
|
||||
Tagged<DeoptimizationLiteralArray> literals);
|
||||
|
||||
|
||||
Vendored
+17
-8
@@ -3233,13 +3233,22 @@ FrameSummaries OptimizedJSFrame::Summarize(bool never_allocate) const {
|
||||
// Skip remaining header operands to reach the values.
|
||||
it.SkipOperands(TranslationOpcodeOperandCount(opcode) - 2);
|
||||
|
||||
// Resolve closure and receiver from the live frame. Both are always
|
||||
// encoded as LITERAL or TAGGED_STACK_SLOT in the deopt translation.
|
||||
Tagged<Object> function_obj =
|
||||
TranslatedState::ResolveTaggedValue(&it, fp(), literal_array);
|
||||
DCHECK(IsJSFunction(function_obj));
|
||||
Tagged<Object> receiver_obj =
|
||||
TranslatedState::ResolveTaggedValue(&it, fp(), literal_array);
|
||||
// Resolve closure and receiver from the live frame. The closure is
|
||||
// always tagged (LITERAL or TAGGED_STACK_SLOT), but the receiver is
|
||||
// just parameter 0 of the (possibly inlined) frame and may be encoded
|
||||
// in any representation the optimizer chose (e.g. DOUBLE_STACK_SLOT
|
||||
// for an unboxed Float64). Fall back to the full materialization path
|
||||
// in that case.
|
||||
std::optional<Tagged<Object>> function_obj =
|
||||
TranslatedState::TryResolveTaggedValue(&it, fp(), literal_array);
|
||||
DCHECK(function_obj.has_value());
|
||||
DCHECK(IsJSFunction(*function_obj));
|
||||
std::optional<Tagged<Object>> receiver_obj =
|
||||
TranslatedState::TryResolveTaggedValue(&it, fp(), literal_array);
|
||||
if (!receiver_obj.has_value()) {
|
||||
needs_full_walk = true;
|
||||
break;
|
||||
}
|
||||
|
||||
Tagged<AbstractCode> abstract_code;
|
||||
int code_offset;
|
||||
@@ -3255,7 +3264,7 @@ FrameSummaries OptimizedJSFrame::Summarize(bool never_allocate) const {
|
||||
|
||||
DirectHandle<FixedArray> params = GetParameters(never_allocate);
|
||||
FrameSummary::JavaScriptFrameSummary summary(
|
||||
isolate(), receiver_obj, Cast<JSFunction>(function_obj),
|
||||
isolate(), *receiver_obj, Cast<JSFunction>(*function_obj),
|
||||
abstract_code, code_offset, is_constructor, *params);
|
||||
summaries.frames.push_back(summary);
|
||||
is_constructor = false;
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2026 the V8 project authors. All rights reserved.
|
||||
// Use of this source code governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax --jit-fuzzing --single-threaded
|
||||
|
||||
function f9(a10, a11) {
|
||||
'use strict';
|
||||
for (let v12 = 0; v12 < 5; v12++) {
|
||||
const v15 = ({ maxByteLength: 1073741824 }).maxByteLength;
|
||||
%OptimizeOsr();
|
||||
function F16(a18, a19, a20) {
|
||||
if (!new.target) { throw 'must be called with new'; }
|
||||
}
|
||||
try { F16.call(v15); } catch (e) {}
|
||||
}
|
||||
return f9;
|
||||
}
|
||||
%PrepareFunctionForOptimization(f9);
|
||||
f9(f9, f9);
|
||||
Reference in new issue
Block a user