From dc896813e305510a32066d1c2bab4217d2d2ac4a Mon Sep 17 00:00:00 2001 From: Victor Gomes Date: Mon, 10 Nov 2025 10:04:42 +0100 Subject: [PATCH 1/5] deps: V8: cherry-pick 853553fe755c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Original commit message: [trace] Don't add 'new' to Wasm call site When constructors builtins are inlined in Maglev, but the constructor itself is not, we need to mark the call site flag kIsConstructor. This allows the stack trace builder to add the 'new' string. However, this should not be done if the target is Wasm. This creates the same stack trace string as Ignition. Fixed: 450308355 Change-Id: I5c21eba3b46f97ddca9c51c21a66aa8169c0293c Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7136920 Reviewed-by: Marja Hölttä Auto-Submit: Victor Gomes Commit-Queue: Victor Gomes Cr-Commit-Position: refs/heads/main@{#103617} Refs: https://github.com/v8/v8/commit/853553fe755c6534fa8168aef1e46c67aa9e1ff7 --- common.gypi | 2 +- deps/v8/src/execution/isolate.cc | 3 ++ deps/v8/test/mjsunit/regress-450308355.js | 41 +++++++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 deps/v8/test/mjsunit/regress-450308355.js diff --git a/common.gypi b/common.gypi index 1effebe59bd4..59eb8582cb69 100644 --- a/common.gypi +++ b/common.gypi @@ -42,7 +42,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.53', + 'v8_embedder_string': '-node.54', ##### V8 defaults for Node.js ##### diff --git a/deps/v8/src/execution/isolate.cc b/deps/v8/src/execution/isolate.cc index 960132fe5532..0d59bffe5611 100644 --- a/deps/v8/src/execution/isolate.cc +++ b/deps/v8/src/execution/isolate.cc @@ -867,6 +867,9 @@ class CallSiteBuilder { DCHECK_GT(index_, 0); Tagged info = Tagged::cast(elements_->get(index_ - 1)); +#if V8_ENABLE_WEBASSEMBLY + if (info->IsWasm()) return; +#endif info->set_flags(info->flags() | CallSiteInfo::kIsConstructor); } diff --git a/deps/v8/test/mjsunit/regress-450308355.js b/deps/v8/test/mjsunit/regress-450308355.js new file mode 100644 index 000000000000..683068ff2014 --- /dev/null +++ b/deps/v8/test/mjsunit/regress-450308355.js @@ -0,0 +1,41 @@ +// Copyright 2025 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. + +// Flags: --allow-natives-syntax + +let captured; + +function J_C() { + let obj = {}; + Error.captureStackTrace(obj); + captured = obj.stack; +} + +function AsmModule(stdlib, foreign, heap) { + "use asm"; + var callback = foreign.callback; + function W() { + callback(); + } + return { W: W }; +} + +let exports = AsmModule(this, { callback: J_C }, new ArrayBuffer(65536)); +let W = exports.W; + +function B() { + new W(); +} + +%PrepareFunctionForOptimization(B); +B(); +// Stack minus last call. +let from_ignition = captured.replace(/\n.*$/, ''); +%OptimizeMaglevOnNextCall(B); +B(); +// Stack minus last call. +let from_optimized = captured.replace(/\n.*$/, ''); + +// Ignition and optimized code agrees with the stack trace. +assertEquals(from_ignition, from_optimized); From fcecf09a6d4a615f27964c3549e32bd6f61c5560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marja=20H=C3=B6ltt=C3=A4?= Date: Mon, 30 Mar 2026 09:55:56 +0200 Subject: [PATCH 2/5] deps: V8: backport ebd15783b7ba MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Original commit message: [objects]: Defer CallSiteInfo creation Store the raw data in a FixedArray and create the CallSiteInfo objects only on demand. This can be further optimized to omit CallSiteInfo creation altogether in some code paths, but currently those code paths are not critically important. Change-Id: I6480862caf6b64020737527c571e3e3eac704ed3 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7673818 Commit-Queue: Marja Hölttä Reviewed-by: Leszek Swirski Cr-Commit-Position: refs/heads/main@{#106127} Refs: https://github.com/v8/v8/commit/ebd15783b7ba67a135212cf7418ca2f85ebb7502 Co-authored-by: Antoine du Hamel PR-URL: https://github.com/nodejs/node/pull/65764 Reviewed-By: Matteo Collina Reviewed-By: Filip Skokan --- common.gypi | 2 +- deps/v8/src/execution/isolate.cc | 118 +++++++++++++++++------- deps/v8/src/execution/messages.cc | 39 +++++--- deps/v8/src/heap/factory.cc | 7 +- deps/v8/src/heap/factory.h | 2 +- deps/v8/src/objects/call-site-info.cc | 32 +++++++ deps/v8/src/objects/call-site-info.h | 16 ++++ deps/v8/src/objects/debug-objects-inl.h | 14 +-- deps/v8/src/objects/debug-objects.h | 4 +- deps/v8/src/objects/debug-objects.tq | 8 +- deps/v8/src/objects/fixed-array.cc | 36 +++++++- deps/v8/src/objects/fixed-array.h | 13 +++ 12 files changed, 222 insertions(+), 69 deletions(-) diff --git a/common.gypi b/common.gypi index 59eb8582cb69..46ae0a4d4b93 100644 --- a/common.gypi +++ b/common.gypi @@ -42,7 +42,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.54', + 'v8_embedder_string': '-node.55', ##### V8 defaults for Node.js ##### diff --git a/deps/v8/src/execution/isolate.cc b/deps/v8/src/execution/isolate.cc index 0d59bffe5611..98bba511f234 100644 --- a/deps/v8/src/execution/isolate.cc +++ b/deps/v8/src/execution/isolate.cc @@ -859,18 +859,21 @@ class CallSiteBuilder { // framework and library code, and stack depth tends to be more than // a dozen frames, so we over-allocate a bit here to avoid growing // the elements array in the common case. - elements_ = isolate->factory()->NewFixedArray(std::min(64, limit)); + elements_ = isolate->factory()->NewFixedArray(CallSiteInfo::Fields::kCount * + std::min(64, limit)); } void SetPrevFrameAsConstructCall() { if (skipped_prev_frame_) return; DCHECK_GT(index_, 0); - Tagged info = - Tagged::cast(elements_->get(index_ - 1)); + int base_index = (index_ - 1) * CallSiteInfo::Fields::kCount; + int flags = + Smi::ToInt(elements_->get(base_index + CallSiteInfo::Fields::kFlags)); #if V8_ENABLE_WEBASSEMBLY - if (info->IsWasm()) return; + if (flags & CallSiteInfo::kIsWasm) return; #endif - info->set_flags(info->flags() | CallSiteInfo::kIsConstructor); + elements_->set(base_index + CallSiteInfo::Fields::kFlags, + Smi::FromInt(flags | CallSiteInfo::kIsConstructor)); } bool Visit(FrameSummary const& summary) { @@ -1032,7 +1035,8 @@ class CallSiteBuilder { bool Full() { return index_ >= limit_; } Handle Build() { - return FixedArray::RightTrimOrEmpty(isolate_, elements_, index_); + return FixedArray::RightTrimOrEmpty(isolate_, elements_, + CallSiteInfo::Fields::kCount * index_); } private: @@ -1097,17 +1101,42 @@ class CallSiteBuilder { void AppendFrame(DirectHandle> receiver_or_instance, DirectHandle> function, - DirectHandle code, int offset, int flags, + DirectHandle code_obj, int offset, int flags, DirectHandle parameters) { if (IsTheHole(*receiver_or_instance, isolate_)) { // TODO(jgruber): Fix all cases in which frames give us a hole value // (e.g. the receiver in RegExp constructor frames). receiver_or_instance = isolate_->factory()->undefined_value(); } - auto info = isolate_->factory()->NewCallSiteInfo( - Cast(receiver_or_instance), function, code, offset, flags, - parameters); - elements_ = FixedArray::SetAndGrow(isolate_, elements_, index_++, info); + + int base_index = index_ * CallSiteInfo::Fields::kCount; + + // Set the last field first and grow the array if needed. + static_assert(CallSiteInfo::Fields::kFlags == + CallSiteInfo::Fields::kCount - 1); + elements_ = FixedArray::SetAndGrow( + isolate_, elements_, base_index + CallSiteInfo::Fields::kFlags, + Smi::FromInt(flags)); + + elements_->set(base_index + CallSiteInfo::Fields::kReceiver, + *receiver_or_instance); + elements_->set(base_index + CallSiteInfo::Fields::kFunction, *function); + + if (DirectHandle code; TryCast(code_obj, &code)) { + elements_->set(base_index + CallSiteInfo::Fields::kCode, code->wrapper()); + } else if (DirectHandle bytecode; + TryCast(code_obj, &bytecode)) { + elements_->set(base_index + CallSiteInfo::Fields::kCode, + bytecode->wrapper()); + } else { + elements_->set(base_index + CallSiteInfo::Fields::kCode, + *isolate_->factory()->undefined_value()); + } + + elements_->set(base_index + CallSiteInfo::Fields::kOffset, + Smi::FromInt(offset)); + + index_++; skipped_prev_frame_ = false; } @@ -1412,13 +1441,18 @@ Handle CaptureSimpleStackTrace(Isolate* isolate, int limit, } DirectHandle GetDetailedStackTraceFromCallSiteInfos( - Isolate* isolate, DirectHandle call_site_infos, int limit) { - auto frames = isolate->factory()->NewFixedArray( - std::min(limit, call_site_infos->length())); - int index = 0; - for (int i = 0; i < call_site_infos->length() && index < limit; ++i) { - DirectHandle call_site_info( - Cast(call_site_infos->get(i)), isolate); + Isolate* isolate, DirectHandle raw_data_for_call_site_infos, + uint32_t limit) { + uint32_t call_site_infos_len = + raw_data_for_call_site_infos->length() / + CallSiteInfo::Fields::kCount; + auto frames = + isolate->factory()->NewFixedArray(std::min(limit, call_site_infos_len)); + uint32_t index = 0; + for (uint32_t i = 0; i < call_site_infos_len && index < limit; ++i) { + DirectHandle call_site_info = + CallSiteInfo::ConstructFromRawData(isolate, + raw_data_for_call_site_infos, i); if (call_site_info->IsAsync()) { break; } @@ -1489,14 +1523,19 @@ MaybeDirectHandle Isolate::CaptureAndSetErrorStack( stack_trace_for_uncaught_exceptions_frame_limit_, stack_trace_for_uncaught_exceptions_options_); } else { - auto call_site_infos = + auto raw_data_for_call_site_infos = Cast(call_site_infos_or_formatted_stack); stack_trace = GetDetailedStackTraceFromCallSiteInfos( - this, call_site_infos, - stack_trace_for_uncaught_exceptions_frame_limit_); - if (stack_trace_limit < call_site_infos->length()) { + this, raw_data_for_call_site_infos, + static_cast( + stack_trace_for_uncaught_exceptions_frame_limit_)); + DCHECK_GE(stack_trace_limit, 0); + if (static_cast(stack_trace_limit) * + CallSiteInfo::Fields::kCount < + raw_data_for_call_site_infos->length()) { call_site_infos_or_formatted_stack = FixedArray::RightTrimOrEmpty( - this, call_site_infos, stack_trace_limit); + this, raw_data_for_call_site_infos, + stack_trace_limit * CallSiteInfo::Fields::kCount); } // Notify the debugger. OnStackTraceCaptured(stack_trace); @@ -1526,17 +1565,27 @@ Handle Isolate::GetSimpleStackTrace( ErrorUtils::StackPropertyLookupResult lookup = ErrorUtils::GetErrorStackProperty(this, maybe_error_object); + Handle raw_data; if (IsFixedArray(*lookup.error_stack)) { - return Cast(lookup.error_stack); - } - if (!IsErrorStackData(*lookup.error_stack)) { + raw_data = Cast(lookup.error_stack); + } else if (IsErrorStackData(*lookup.error_stack)) { + auto error_stack_data = Cast(lookup.error_stack); + if (!error_stack_data->HasRawDataForCallSiteInfos()) { + return factory()->empty_fixed_array(); + } + raw_data = handle(error_stack_data->raw_data_for_call_site_infos(), this); + } else { return factory()->empty_fixed_array(); } - auto error_stack_data = Cast(lookup.error_stack); - if (!error_stack_data->HasCallSiteInfos()) { - return factory()->empty_fixed_array(); + + int frame_count = raw_data->length() / CallSiteInfo::Fields::kCount; + Handle call_site_infos = factory()->NewFixedArray(frame_count); + for (int i = 0; i < frame_count; ++i) { + DirectHandle call_site_info = + CallSiteInfo::ConstructFromRawData(this, raw_data, i); + call_site_infos->set(i, *call_site_info); } - return handle(error_stack_data->call_site_infos(), this); + return call_site_infos; } Address Isolate::GetAbstractPC(int* line, int* column) { @@ -2868,8 +2917,11 @@ void Isolate::PrintCurrentStackTrace( this, FixedArray::kMaxLength, SKIP_NONE, factory()->undefined_value()); IncrementalStringBuilder builder(this); - for (int i = 0; i < frames->length(); ++i) { - DirectHandle frame(Cast(frames->get(i)), this); + uint32_t frame_count = + frames->length() / CallSiteInfo::Fields::kCount; + for (uint32_t i = 0; i < frame_count; ++i) { + DirectHandle frame = + CallSiteInfo::ConstructFromRawData(this, frames, i); if (should_include_frame_callback) { Tagged raw_script_name = frame->GetScriptNameOrSourceURL(); @@ -2893,7 +2945,7 @@ void Isolate::PrintCurrentStackTrace( SerializeCallSiteInfo(this, frame, &builder); } - if (i != frames->length() - 1) builder.AppendCharacter('\n'); + if (i != frame_count - 1) builder.AppendCharacter('\n'); } DirectHandle stack_trace = builder.Finish().ToHandleChecked(); diff --git a/deps/v8/src/execution/messages.cc b/deps/v8/src/execution/messages.cc index de64c5d75e01..d0a5b1ac88b9 100644 --- a/deps/v8/src/execution/messages.cc +++ b/deps/v8/src/execution/messages.cc @@ -24,6 +24,7 @@ #include "src/parsing/parse-info.h" #include "src/parsing/parsing.h" #include "src/roots/roots.h" +#include "src/sandbox/indirect-pointer-inl.h" #include "src/strings/string-builder-inl.h" namespace v8 { @@ -201,15 +202,16 @@ namespace { // Convert the raw frames as written by Isolate::CaptureSimpleStackTrace into // a JSArray of JSCallSite objects. -MaybeDirectHandle GetStackFrames(Isolate* isolate, - DirectHandle frames) { - int frame_count = frames->length(); +MaybeDirectHandle GetStackFrames( + Isolate* isolate, DirectHandle raw_data_for_call_site_infos) { + uint32_t frame_count = raw_data_for_call_site_infos->length() / + CallSiteInfo::Fields::kCount; DirectHandle constructor = isolate->callsite_function(); DirectHandle sites = isolate->factory()->NewFixedArray(frame_count); - for (int i = 0; i < frame_count; ++i) { - DirectHandle frame(Cast(frames->get(i)), - isolate); + for (uint32_t i = 0; i < frame_count; ++i) { + DirectHandle frame = CallSiteInfo::ConstructFromRawData( + isolate, raw_data_for_call_site_infos, i); DirectHandle site; ASSIGN_RETURN_ON_EXCEPTION(isolate, site, JSObject::New(constructor, constructor, @@ -291,7 +293,7 @@ MaybeDirectHandle ErrorUtils::FormatStackTrace( return isolate->factory()->empty_string(); } DCHECK(IsFixedArray(*raw_stack)); - auto elems = Cast(raw_stack); + auto raw_data_for_call_site_infos = Cast(raw_stack); const bool in_recursion = isolate->formatting_stack_trace(); const bool has_overflowed = i::StackLimitCheck{isolate}.HasOverflowed(); @@ -302,8 +304,9 @@ MaybeDirectHandle ErrorUtils::FormatStackTrace( PrepareStackTraceScope scope(isolate); DirectHandle sites; - ASSIGN_RETURN_ON_EXCEPTION(isolate, sites, - GetStackFrames(isolate, elems)); + ASSIGN_RETURN_ON_EXCEPTION( + isolate, sites, + GetStackFrames(isolate, raw_data_for_call_site_infos)); DirectHandle result; ASSIGN_RETURN_ON_EXCEPTION( @@ -328,8 +331,9 @@ MaybeDirectHandle ErrorUtils::FormatStackTrace( isolate->CountUsage(v8::Isolate::kErrorPrepareStackTrace); DirectHandle sites; - ASSIGN_RETURN_ON_EXCEPTION(isolate, sites, - GetStackFrames(isolate, elems)); + ASSIGN_RETURN_ON_EXCEPTION( + isolate, sites, + GetStackFrames(isolate, raw_data_for_call_site_infos)); constexpr int argc = 2; std::array, argc> args; @@ -358,12 +362,16 @@ MaybeDirectHandle ErrorUtils::FormatStackTrace( RETURN_ON_EXCEPTION(isolate, AppendErrorString(isolate, error, &builder)); - for (int i = 0; i < elems->length(); ++i) { + int elems_len = raw_data_for_call_site_infos->length() / + CallSiteInfo::Fields::kCount; + for (int i = 0; i < elems_len; ++i) { builder.AppendCStringLiteral("\n at "); - DirectHandle frame(Cast(elems->get(i)), - isolate); + DirectHandle frame = CallSiteInfo::ConstructFromRawData( + isolate, raw_data_for_call_site_infos, i); + // TODO(marja): Avoid CallSiteInfo creation since we serialize it right + // away. v8::TryCatch try_catch(reinterpret_cast(isolate)); SerializeCallSiteInfo(isolate, frame, &builder); @@ -1164,7 +1172,8 @@ MaybeDirectHandle ErrorUtils::GetFormattedStack( isolate, formatted_stack, FormatStackTrace( isolate, error_object, - direct_handle(error_stack_data->call_site_infos(), isolate))); + direct_handle(error_stack_data->raw_data_for_call_site_infos(), + isolate))); error_stack_data->set_formatted_stack(*formatted_stack); return formatted_stack; } diff --git a/deps/v8/src/heap/factory.cc b/deps/v8/src/heap/factory.cc index 0c258d0290d2..09e4d4f33f1a 100644 --- a/deps/v8/src/heap/factory.cc +++ b/deps/v8/src/heap/factory.cc @@ -1527,13 +1527,14 @@ DirectHandle Factory::NewAccessorInfo() { } DirectHandle Factory::NewErrorStackData( - DirectHandle> call_site_infos_or_formatted_stack, + DirectHandle> + raw_data_for_call_site_infos_or_formatted_stack, DirectHandle stack_trace) { Tagged error_stack_data = NewStructInternal( ERROR_STACK_DATA_TYPE, AllocationType::kYoung); DisallowGarbageCollection no_gc; - error_stack_data->set_call_site_infos_or_formatted_stack( - *call_site_infos_or_formatted_stack, SKIP_WRITE_BARRIER); + error_stack_data->set_raw_data_for_call_site_infos_or_formatted_stack( + *raw_data_for_call_site_infos_or_formatted_stack, SKIP_WRITE_BARRIER); error_stack_data->set_stack_trace(*stack_trace, SKIP_WRITE_BARRIER); return direct_handle(error_stack_data, isolate()); } diff --git a/deps/v8/src/heap/factory.h b/deps/v8/src/heap/factory.h index b282f3893fc5..343b7b41a081 100644 --- a/deps/v8/src/heap/factory.h +++ b/deps/v8/src/heap/factory.h @@ -452,7 +452,7 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase { DirectHandle NewErrorStackData( DirectHandle> - call_site_infos_or_formatted_stack, + raw_data_for_call_site_infos_or_formatted_stack, DirectHandle stack_trace); Handle