From 8f625f31aed8793e720a2d98ce186e2a341dd9cd Mon Sep 17 00:00:00 2001 From: "Node.js GitHub Bot" Date: Sun, 8 Nov 2026 00:48:28 +0000 Subject: [PATCH] deps: patch V8 to 15.6.75.50 Refs: https://github.com/v8/v8/compare/15.6.75.33...15.6.75.50 --- deps/v8/include/v8-version.h | 2 +- deps/v8/src/ast/scopes.cc | 45 ++- deps/v8/src/ast/scopes.h | 1 + .../src/codegen/arm64/assembler-arm64-inl.h | 2 +- deps/v8/src/codegen/arm64/assembler-arm64.cc | 2 +- .../codegen/arm64/macro-assembler-arm64.cc | 4 +- deps/v8/src/codegen/compiler.cc | 5 +- deps/v8/src/codegen/compiler.h | 3 +- .../backend/arm64/code-generator-arm64.cc | 2 +- .../v8/src/compiler/backend/code-generator.cc | 4 +- deps/v8/src/compiler/wasm-load-elimination.cc | 65 ++-- deps/v8/src/compiler/wasm-load-elimination.h | 4 +- deps/v8/src/d8/d8.cc | 6 +- deps/v8/src/debug/debug.cc | 55 +++ deps/v8/src/debug/debug.h | 3 + deps/v8/src/execution/isolate.cc | 34 +- deps/v8/src/heap/factory.cc | 8 +- deps/v8/src/ic/accessor-assembler.cc | 31 +- deps/v8/src/ic/handler-configuration.cc | 5 - deps/v8/src/ic/handler-configuration.h | 4 - deps/v8/src/ic/ic-inl.h | 3 +- deps/v8/src/ic/ic.cc | 46 ++- .../interpreter/bytecode-flags-and-tokens.h | 17 + deps/v8/src/interpreter/bytecode-generator.cc | 15 +- deps/v8/src/maglev/maglev-graph-builder.cc | 60 +-- deps/v8/src/maglev/maglev-graph-builder.h | 4 +- deps/v8/src/maglev/maglev-graph-optimizer.cc | 24 +- deps/v8/src/maglev/maglev-graph-optimizer.h | 2 + deps/v8/src/maglev/maglev-ir.h | 8 +- .../v8/src/maglev/maglev-known-node-aspects.h | 57 ++- deps/v8/src/maglev/maglev-reducer-inl.h | 7 +- deps/v8/src/objects/deoptimization-data.h | 5 +- deps/v8/src/objects/module-inl.h | 12 + deps/v8/src/objects/module.h | 5 + deps/v8/src/objects/source-text-module.cc | 16 +- deps/v8/src/parsing/parser.cc | 11 + deps/v8/src/runtime/runtime-compiler.cc | 17 +- deps/v8/src/runtime/runtime-wasm.cc | 4 +- deps/v8/src/wasm/wasm-debug.cc | 7 +- .../cctest/compiler/test-code-generator.cc | 59 ++- deps/v8/test/cctest/test-api-interceptors.cc | 366 ++++++++++++++++++ deps/v8/test/inspector/inspector.status | 1 + .../regress/regress-577352626-expected.txt | 7 + .../inspector/regress/regress-577352626.js | 211 ++++++++++ .../regress-private-name-heritage-recalc.js | 90 +++++ ...egress-private-name-heritage-catch-eval.js | 131 +++++++ .../test/mjsunit/maglev/regress-577305517.js | 76 ++++ .../test/mjsunit/maglev/regress-578322433.js | 81 ++++ .../test/mjsunit/maglev/regress-579313083.js | 56 +++ .../test/mjsunit/regress/regress-568633429.js | 25 ++ .../test/mjsunit/regress/regress-572988453.js | 34 ++ .../test/mjsunit/regress/regress-573962535.js | 44 +++ .../test/mjsunit/regress/regress-574038247.js | 68 ++++ .../test/mjsunit/regress/regress-574222006.js | 28 ++ .../test/mjsunit/regress/regress-575524702.js | 61 +++ .../mjsunit/regress/regress-575525282-1.js | 70 ++++ .../mjsunit/regress/regress-575525282-2.js | 66 ++++ .../mjsunit/regress/regress-575525282-3.js | 66 ++++ .../test/mjsunit/regress/regress-577242082.js | 30 ++ .../test/mjsunit/regress/regress-577627207.js | 34 ++ .../mjsunit/regress/wasm/regress-579313193.js | 206 ++++++++++ 61 files changed, 2238 insertions(+), 177 deletions(-) create mode 100644 deps/v8/test/inspector/regress/regress-577352626-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-577352626.js create mode 100644 deps/v8/test/mjsunit/es6/regress-private-name-heritage-recalc.js create mode 100644 deps/v8/test/mjsunit/harmony/regress-private-name-heritage-catch-eval.js create mode 100644 deps/v8/test/mjsunit/maglev/regress-577305517.js create mode 100644 deps/v8/test/mjsunit/maglev/regress-578322433.js create mode 100644 deps/v8/test/mjsunit/maglev/regress-579313083.js create mode 100644 deps/v8/test/mjsunit/regress/regress-568633429.js create mode 100644 deps/v8/test/mjsunit/regress/regress-572988453.js create mode 100644 deps/v8/test/mjsunit/regress/regress-573962535.js create mode 100644 deps/v8/test/mjsunit/regress/regress-574038247.js create mode 100644 deps/v8/test/mjsunit/regress/regress-574222006.js create mode 100644 deps/v8/test/mjsunit/regress/regress-575524702.js create mode 100644 deps/v8/test/mjsunit/regress/regress-575525282-1.js create mode 100644 deps/v8/test/mjsunit/regress/regress-575525282-2.js create mode 100644 deps/v8/test/mjsunit/regress/regress-575525282-3.js create mode 100644 deps/v8/test/mjsunit/regress/regress-577242082.js create mode 100644 deps/v8/test/mjsunit/regress/regress-577627207.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-579313193.js diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index 11e0def9233c..0101d1257665 100644 --- a/deps/v8/include/v8-version.h +++ b/deps/v8/include/v8-version.h @@ -11,7 +11,7 @@ #define V8_MAJOR_VERSION 15 #define V8_MINOR_VERSION 6 #define V8_BUILD_NUMBER 75 -#define V8_PATCH_LEVEL 33 +#define V8_PATCH_LEVEL 50 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/src/ast/scopes.cc b/deps/v8/src/ast/scopes.cc index 725f007719d4..67e319c1e1d7 100644 --- a/deps/v8/src/ast/scopes.cc +++ b/deps/v8/src/ast/scopes.cc @@ -118,9 +118,11 @@ Scope::Scope(Zone* zone, Scope* outer_scope, ScopeType scope_type) DCHECK(!is_script_scope()); SetDefaults(); set_language_mode(outer_scope->language_mode()); - set_private_name_lookup_skips_outer_class( - outer_scope->is_class_scope() && - outer_scope->AsClassScope()->IsParsingHeritage()); + if (outer_scope->is_class_scope() && + outer_scope->AsClassScope()->IsParsingHeritage()) { + set_private_name_lookup_skips_outer_class(true); + outer_scope->GetClosureScope()->RecordNeedsPrivateNameContextChainRecalc(); + } outer_scope_->AddInnerScope(this); } @@ -180,6 +182,9 @@ DeclarationScope::DeclarationScope(Zone* zone, Scope* outer_scope, params_(4, zone) { DCHECK(!is_script_scope()); SetDefaults(); + if (V8_UNLIKELY(private_name_lookup_skips_outer_class())) { + RecordNeedsPrivateNameContextChainRecalc(); + } } ModuleScope::ModuleScope(DeclarationScope* script_scope, @@ -305,18 +310,14 @@ DeclarationScope::DeclarationScope(Zone* zone, ScopeType scope_type, DCHECK(IsClassConstructor(function_kind())); set_class_scope_has_private_brand(true); } + if (V8_UNLIKELY(private_name_lookup_skips_outer_class())) { + RecordNeedsPrivateNameContextChainRecalc(); + } } Scope::Scope(Zone* zone, const AstRawString* catch_variable_name, MaybeAssignedFlag maybe_assigned, Handle scope_info) - : outer_scope_(nullptr), - variables_(zone), - scope_info_(scope_info), - scope_type_(CATCH_SCOPE) { - SetDefaults(); -#ifdef DEBUG - already_resolved_ = true; -#endif + : Scope(zone, CATCH_SCOPE, nullptr, scope_info) { // Cache the catch variable, even though it's also available via the // scope_info, as the parser expects that a catch scope always has the catch // variable as first and only variable. @@ -326,7 +327,6 @@ Scope::Scope(Zone* zone, const AstRawString* catch_variable_name, kCreatedInitialized, maybe_assigned, &was_added); DCHECK(was_added); AllocateHeapSlot(variable); - set_is_hoisted_in_context(scope_info->is_hoisted_in_context()); } void DeclarationScope::SetDefaults() { @@ -454,9 +454,14 @@ Scope* Scope::DeserializeScopeChain( eval_scope->set_start_position(position); eval_scope->set_end_position(position); eval_scope->set_eval_position(position); - if (current_scope != nullptr) { + eval_scope->set_private_name_lookup_skips_outer_class( + current_scope->private_name_lookup_skips_outer_class()); + current_scope->set_private_name_lookup_skips_outer_class(false); eval_scope->AddInnerScope(current_scope); + } else if (parse_info != nullptr) { + eval_scope->set_private_name_lookup_skips_outer_class( + parse_info->flags().private_name_lookup_skips_outer_class()); } current_scope = eval_scope; if (innermost_scope == nullptr) innermost_scope = current_scope; @@ -940,6 +945,7 @@ Scope* Scope::FinalizeBlockScope() { scope->outer_scope_ = outer_scope(); if (private_name_lookup_skips_outer_class()) { scope->set_private_name_lookup_skips_outer_class(true); + scope->GetClosureScope()->RecordNeedsPrivateNameContextChainRecalc(); } if (scope->is_function_scope()) { scope->set_is_hoisted_in_context(false); @@ -997,12 +1003,14 @@ void Scope::Snapshot::Reparent(DeclarationScope* new_parent) { for (; inner_scope->sibling() != top_inner_scope_; inner_scope = inner_scope->sibling()) { inner_scope->outer_scope_ = new_parent; + inner_scope->set_private_name_lookup_skips_outer_class(false); if (inner_scope->inner_scope_calls_eval()) { new_parent->set_inner_scope_calls_eval(true); } DCHECK_NE(inner_scope, new_parent); } inner_scope->outer_scope_ = new_parent; + inner_scope->set_private_name_lookup_skips_outer_class(false); if (inner_scope->inner_scope_calls_eval()) { new_parent->set_inner_scope_calls_eval(true); } @@ -1454,7 +1462,12 @@ bool DeclarationScope::AllocateVariables(ParseInfo* info) { } // Don't allocate variables of preparsed scopes. - if (!was_lazily_parsed()) AllocateVariablesRecursively(); + if (!was_lazily_parsed()) { + AllocateVariablesRecursively(); + if (needs_private_name_context_chain_recalc()) { + RecalcPrivateNameContextChain(); + } + } return true; } @@ -2924,10 +2937,6 @@ void DeclarationScope::AllocateScopeInfos(ParseInfo* parse_info, } } - if (scope->needs_private_name_context_chain_recalc()) { - scope->RecalcPrivateNameContextChain(); - } - Tagged infos = script->infos(); std::unordered_map> scope_infos_to_reuse; if (infos->ulength().value() != 0) { diff --git a/deps/v8/src/ast/scopes.h b/deps/v8/src/ast/scopes.h index fa13cc9a176c..183700b6a1b2 100644 --- a/deps/v8/src/ast/scopes.h +++ b/deps/v8/src/ast/scopes.h @@ -1512,6 +1512,7 @@ void Scope::RecordEvalCall() { GetDeclarationScope()->RecordDeclarationScopeEvalCall(); } RecordInnerScopeEvalCall(); + GetClosureScope()->RecordNeedsPrivateNameContextChainRecalc(); // The eval contents might access "super" (if it's inside a function that // binds super). DeclarationScope* receiver_scope = GetReceiverScope(); diff --git a/deps/v8/src/codegen/arm64/assembler-arm64-inl.h b/deps/v8/src/codegen/arm64/assembler-arm64-inl.h index fc8b4c83ff8f..abd4c5e63e8f 100644 --- a/deps/v8/src/codegen/arm64/assembler-arm64-inl.h +++ b/deps/v8/src/codegen/arm64/assembler-arm64-inl.h @@ -983,7 +983,7 @@ Instr Assembler::SF(Register rd) { } Instr Assembler::ImmAddSub(int imm) { - DCHECK(IsImmAddSub(imm)); + CHECK(IsImmAddSub(imm)); if (is_uint12(imm)) { // No shift required. imm <<= ImmAddSub_offset; } else { diff --git a/deps/v8/src/codegen/arm64/assembler-arm64.cc b/deps/v8/src/codegen/arm64/assembler-arm64.cc index e3a6685ede1b..af1c92fca71b 100644 --- a/deps/v8/src/codegen/arm64/assembler-arm64.cc +++ b/deps/v8/src/codegen/arm64/assembler-arm64.cc @@ -4043,7 +4043,7 @@ void Assembler::AddSub(const Register& rd, const Register& rn, DCHECK(!operand.NeedsRelocation(this)); if (operand.IsImmediate()) { int64_t immediate = operand.ImmediateValue(); - DCHECK(IsImmAddSub(immediate)); + CHECK(IsImmAddSub(immediate)); Instr dest_reg = (S == SetFlags) ? Rd(rd) : RdSP(rd); Emit(SF(rd) | AddSubImmediateFixed | op | Flags(S) | ImmAddSub(static_cast(immediate)) | dest_reg | RnSP(rn)); diff --git a/deps/v8/src/codegen/arm64/macro-assembler-arm64.cc b/deps/v8/src/codegen/arm64/macro-assembler-arm64.cc index a79bd6d3186d..26a3110f8f0a 100644 --- a/deps/v8/src/codegen/arm64/macro-assembler-arm64.cc +++ b/deps/v8/src/codegen/arm64/macro-assembler-arm64.cc @@ -979,11 +979,11 @@ void MacroAssembler::LoadStoreMacroComplex(const CPURegister& rt, // Post-index beyond unscaled addressing range. DCHECK(!is_imm_unscaled); LoadStore(rt, MemOperand(addr.base()), op); - add(addr.base(), addr.base(), offset); + Add(addr.base(), addr.base(), offset); } else { // Pre-index beyond unscaled addressing range. DCHECK(!is_imm_unscaled && addr.IsPreIndex()); - add(addr.base(), addr.base(), offset); + Add(addr.base(), addr.base(), offset); LoadStore(rt, MemOperand(addr.base()), op); } } diff --git a/deps/v8/src/codegen/compiler.cc b/deps/v8/src/codegen/compiler.cc index 0a3599ee41c4..7a965c17292a 100644 --- a/deps/v8/src/codegen/compiler.cc +++ b/deps/v8/src/codegen/compiler.cc @@ -3320,7 +3320,8 @@ MaybeDirectHandle Compiler::GetFunctionFromEval( DirectHandle outer_info, DirectHandle context, LanguageMode language_mode, ParseRestriction restriction, int parameters_end_pos, int eval_position, - ParsingWhileDebugging parsing_while_debugging) { + ParsingWhileDebugging parsing_while_debugging, + bool private_name_lookup_skips_outer_class) { // The cache lookup key needs to be aware of the separation between the // parameters and the body to prevent this valid invocation: // Function("", "function anonymous(\n/**/) {\n}"); @@ -3376,6 +3377,8 @@ MaybeDirectHandle Compiler::GetFunctionFromEval( v8_flags.lazy_eval); flags.set_is_eval(true); flags.set_parsing_while_debugging(parsing_while_debugging); + flags.set_private_name_lookup_skips_outer_class( + private_name_lookup_skips_outer_class); DCHECK(!flags.is_module()); flags.set_parse_restriction(restriction); diff --git a/deps/v8/src/codegen/compiler.h b/deps/v8/src/codegen/compiler.h index cfa6af01010b..bab8d7068849 100644 --- a/deps/v8/src/codegen/compiler.h +++ b/deps/v8/src/codegen/compiler.h @@ -166,7 +166,8 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic { ParseRestriction restriction, int parameters_end_pos, int eval_position, ParsingWhileDebugging parsing_while_debugging = - ParsingWhileDebugging::kNo); + ParsingWhileDebugging::kNo, + bool private_name_lookup_skips_outer_class = false); // Create a function that results from wrapping |source| in a function, // with |arguments| being a list of parameters for that function. diff --git a/deps/v8/src/compiler/backend/arm64/code-generator-arm64.cc b/deps/v8/src/compiler/backend/arm64/code-generator-arm64.cc index f4efe50f64d1..a1fda89d75d8 100644 --- a/deps/v8/src/compiler/backend/arm64/code-generator-arm64.cc +++ b/deps/v8/src/compiler/backend/arm64/code-generator-arm64.cc @@ -4674,7 +4674,7 @@ void CodeGenerator::Pop(InstructionOperand* dest, MachineRepresentation rep) { void CodeGenerator::PopTempStackSlots() { if (temp_slots_ > 0) { frame_access_state()->IncreaseSPDelta(-temp_slots_); - __ add(sp, sp, Operand(temp_slots_ * kSystemPointerSize)); + __ Add(sp, sp, Operand(temp_slots_ * kSystemPointerSize)); temp_slots_ = 0; } } diff --git a/deps/v8/src/compiler/backend/code-generator.cc b/deps/v8/src/compiler/backend/code-generator.cc index 28faaf109510..97678a75401e 100644 --- a/deps/v8/src/compiler/backend/code-generator.cc +++ b/deps/v8/src/compiler/backend/code-generator.cc @@ -1695,8 +1695,8 @@ void CodeGenerator::AddTranslationForOperand(Instruction* instr, default: UNREACHABLE(); } - if (literal.object().equals(info()->closure()) && - info()->function_context_specializing()) { + if (info()->function_context_specializing() && + literal.IsObject(info()->closure())) { translations_.StoreJSFrameFunction(); } else { int literal_id = DefineDeoptimizationLiteral(literal); diff --git a/deps/v8/src/compiler/wasm-load-elimination.cc b/deps/v8/src/compiler/wasm-load-elimination.cc index 3ab300bb0e1b..75d7f83f08af 100644 --- a/deps/v8/src/compiler/wasm-load-elimination.cc +++ b/deps/v8/src/compiler/wasm-load-elimination.cc @@ -84,7 +84,40 @@ Reduction WasmLoadElimination::UpdateState(Node* node, std::tuple WasmLoadElimination::TruncateAndExtendOrType( Node* value, Node* effect, Node* control, wasm::ValueType field_type, bool is_signed) { + if (value->opcode() == IrOpcode::kDead || + value->opcode() == IrOpcode::kDeadValue) { + return {dead(), dead()}; + } + + // The value might be untyped or have a non-Wasm type (e.g. Type::None() from + // DeadCodeElimination, or a JS node in case of Wasm inlined into JS). Without + // a concrete Wasm type we cannot verify representation compatibility. + if (!NodeProperties::IsTyped(value)) { + return {nullptr, nullptr}; + } + + Type value_type = NodeProperties::GetType(value); + if (!value_type.IsWasm()) { + return {nullptr, nullptr}; + } + + wasm::TypeInModule node_type = value_type.AsWasm(); + if (node_type.type.is_top()) { + return {nullptr, nullptr}; + } + + wasm::ValueType unpacked_field_type = field_type.Unpacked(); + if (node_type.type.is_uninhabited() || + TypesUnrelated(node_type.type, unpacked_field_type, node_type.module)) { + // Uninhabited or unrelated types can occur as a result of unreachable code. + // Example: Storing a value x of type A in a struct, then casting the struct + // to a different struct type to then load type B from the same offset + // results in trying to replace the load with value x. + return {dead(), dead()}; + } + if (field_type == wasm::kWasmI8 || field_type == wasm::kWasmI16) { + DCHECK_EQ(node_type.type, wasm::kWasmI32); Node* ret = nullptr; if (is_signed) { int shift = 32 - 8 * field_type.value_kind_size(); @@ -98,30 +131,10 @@ std::tuple WasmLoadElimination::TruncateAndExtendOrType( jsgraph()->Int32Constant(mask)); } - NodeProperties::SetType(ret, NodeProperties::GetType(value)); + NodeProperties::SetType(ret, value_type); return {ret, effect}; } - // The value might be untyped in case of wasm inlined into JS if the value - // comes from a JS node. - if (!NodeProperties::IsTyped(value)) { - return {value, effect}; - } - - Type value_type = NodeProperties::GetType(value); - if (!value_type.IsWasm()) { - return {value, effect}; - } - - wasm::TypeInModule node_type = value_type.AsWasm(); - - if (TypesUnrelated(node_type.type, field_type, node_type.module)) { - // Unrelated types can occur as a result of unreachable code. - // Example: Storing a value x of type A in a struct, then casting the struct - // to a different struct type to then load type B from the same offset - // results in trying to replace the load with value x. - return {dead(), dead()}; - } if (!wasm::IsSubtypeOf(node_type.type, field_type, node_type.module)) { Type type = Type::Wasm({field_type, node_type.module}, graph()->zone()); Node* ret = @@ -233,10 +246,12 @@ Reduction WasmLoadElimination::ReduceWasmStructGet(Node* node) { node->Kill(); return Replace(dead()); } - ReplaceWithValue(node, std::get<0>(replacement), std::get<1>(replacement), - control); - node->Kill(); - return Replace(std::get<0>(replacement)); + if (std::get<0>(replacement) != nullptr) { + ReplaceWithValue(node, std::get<0>(replacement), std::get<1>(replacement), + control); + node->Kill(); + return Replace(std::get<0>(replacement)); + } } half_state = half_state->AddField(field_info.field_index, object, node); diff --git a/deps/v8/src/compiler/wasm-load-elimination.h b/deps/v8/src/compiler/wasm-load-elimination.h index fe404181f3b8..204af4f23a4c 100644 --- a/deps/v8/src/compiler/wasm-load-elimination.h +++ b/deps/v8/src/compiler/wasm-load-elimination.h @@ -138,7 +138,9 @@ class V8_EXPORT_PRIVATE WasmLoadElimination final AbstractState const* ComputeLoopState(Node* node, AbstractState const* state) const; // Returns the replacement value and effect for a load given an initial value - // node, after optional {TypeGuard}ing and i8/i16 adaptation to i32. + // node, after optional {TypeGuard}ing and i8/i16 adaptation to i32. Returns + // {dead(), dead()} if the types prove the load is unreachable, or + // {nullptr, nullptr} if replacement must be skipped. std::tuple TruncateAndExtendOrType(Node* value, Node* effect, Node* control, wasm::ValueType field_type, diff --git a/deps/v8/src/d8/d8.cc b/deps/v8/src/d8/d8.cc index 8d325f418e38..2f7517743e81 100644 --- a/deps/v8/src/d8/d8.cc +++ b/deps/v8/src/d8/d8.cc @@ -4768,8 +4768,10 @@ Local Shell::CreateGlobalTemplate(Isolate* isolate) { global_template->Set(Symbol::GetToStringTag(isolate), String::NewFromUtf8Literal(isolate, "global")); global_template->Set(isolate, "onerror", v8::Null(isolate)); - global_template->Set(isolate, "version", - FunctionTemplate::New(isolate, Version)); + Local version_func_template = + FunctionTemplate::New(isolate, Version); + version_func_template->SetAcceptAnyReceiver(false); + global_template->Set(isolate, "version", version_func_template); global_template->Set(isolate, "print", FunctionTemplate::New(isolate, Print)); global_template->Set(isolate, "printErr", diff --git a/deps/v8/src/debug/debug.cc b/deps/v8/src/debug/debug.cc index def10a51cd7f..62b24a590e62 100644 --- a/deps/v8/src/debug/debug.cc +++ b/deps/v8/src/debug/debug.cc @@ -40,6 +40,7 @@ #include "src/snapshot/embedded/embedded-data.h" #if V8_ENABLE_WEBASSEMBLY +#include "src/wasm/wasm-code-manager.h" #include "src/wasm/wasm-debug.h" #include "src/wasm/wasm-objects-inl.h" #endif // V8_ENABLE_WEBASSEMBLY @@ -2973,6 +2974,60 @@ void Debug::HandleDebugBreak(IgnoreBreakMode ignore_break_mode, return; } } +#if V8_ENABLE_WEBASSEMBLY + } else if (!it.done() && it.frame()->is_wasm()) { +#if V8_ENABLE_DRUMBRAKE + if (!it.frame()->is_wasm_interpreter_entry()) +#endif // V8_ENABLE_DRUMBRAKE + { + WasmFrame* wasm_frame = WasmFrame::cast(it.frame()); + wasm::WasmCodeRefScope code_ref_scope; + // Optimized Wasm frames cannot be deoptimized on-stack at loop stack + // checks. Defer the pause to the next function call (or return to a + // debuggable caller frame) so that JavaScript executed during the + // pause cannot invalidate load-eliminated state in the optimized Wasm + // frame. + if (!wasm_frame->wasm_code()->is_liftoff()) { + if (ignore_events()) return; + thread_local_.scheduled_break_on_next_function_call_.Add( + break_reasons); + SetBreakOnNextFunctionCall(); + for (it.Advance(); !it.done(); it.Advance()) { + if (it.frame()->is_wasm()) { +#if V8_ENABLE_DRUMBRAKE + if (it.frame()->is_wasm_interpreter_entry()) continue; +#endif // V8_ENABLE_DRUMBRAKE + WasmFrame* caller_wasm = WasmFrame::cast(it.frame()); + if (!caller_wasm->wasm_code()->is_inspectable()) continue; + wasm::DebugInfo* debug_info = + caller_wasm->native_module()->GetDebugInfo(); + if (debug_info->IsFrameBlackboxed(caller_wasm)) continue; + debug_info->PrepareStepOutTo(caller_wasm); + break; + } + JavaScriptFrame* js_frame = JavaScriptFrame::cast(it.frame()); + if (js_frame->is_optimized()) { + Deoptimizer::DeoptimizeFunction(js_frame->function(), + LazyDeoptimizeReason::kDebugger, + js_frame->LookupCode()); + } + HandleScope inner_scope(isolate_); + std::vector> infos; + js_frame->GetFunctions(&infos); + bool flooded = false; + for (; !infos.empty(); infos.pop_back()) { + Handle info = infos.back(); + if (IsBlackboxed(info)) continue; + FloodWithOneShot(info); + flooded = true; + break; + } + if (flooded) break; + } + return; + } + } +#endif // V8_ENABLE_WEBASSEMBLY } } diff --git a/deps/v8/src/debug/debug.h b/deps/v8/src/debug/debug.h index 4a093800e6d0..1c8f80db04d6 100644 --- a/deps/v8/src/debug/debug.h +++ b/deps/v8/src/debug/debug.h @@ -460,6 +460,9 @@ class V8_EXPORT_PRIVATE Debug { bool scheduled_break_on_function_call() const { return !thread_local_.scheduled_break_on_next_function_call_.empty(); } + v8::debug::BreakReasons scheduled_break_on_next_function_call() const { + return thread_local_.scheduled_break_on_next_function_call_; + } bool IsRestartFrameScheduled() const { return thread_local_.restart_frame_id_ != StackFrameId::NO_ID; diff --git a/deps/v8/src/execution/isolate.cc b/deps/v8/src/execution/isolate.cc index 7ef444669c8e..e6f2f3506d3a 100644 --- a/deps/v8/src/execution/isolate.cc +++ b/deps/v8/src/execution/isolate.cc @@ -3299,6 +3299,7 @@ Tagged Isolate::UnwindAndFindHandler() { break; } case StackFrame::INTERNAL: { + if (!catchable_by_js) break; auto code = frame->GcSafeLookupCode(); if (code->builtin_id() == Builtin::kDeoptimizationEntry_LazyAfterFastCall) { @@ -4629,8 +4630,7 @@ void Isolate::SwitchStacks(wasm::StackMemory* from, wasm::StackMemory* to, stack_guard()->SetStackLimitForStackSwitching(limit); // Update the central stack info. - if (!thread_local_top()->is_on_central_stack_flag_ && - to->jmpbuf()->is_on_central_stack) { + if (to->jmpbuf()->is_on_central_stack) { DCHECK(is_suspend || is_return); DCHECK_EQ(expected_target_state, wasm::JumpBuffer::Inactive); thread_local_top()->is_on_central_stack_flag_ = true; @@ -4640,8 +4640,7 @@ void Isolate::SwitchStacks(wasm::StackMemory* from, wasm::StackMemory* to, #endif thread_local_top()->central_stack_limit_ = reinterpret_cast
(to->jmpbuf()->stack_limit); - } else if (thread_local_top()->is_on_central_stack_flag_ && - !to->jmpbuf()->is_on_central_stack) { + } else if (thread_local_top()->is_on_central_stack_flag_) { thread_local_top()->is_on_central_stack_flag_ = false; if (is_resume) { // Record the current central stack SP, we will switch back to it for @@ -5543,9 +5542,23 @@ void Isolate::NotifyExceptionPropagationCallback() { // "C++ -> JS" or "C++ -> Api callback" boundary. return; } - if (it.done() || - (ext_callback_scope && - ext_callback_scope->JSStackComparableAddress() < it.frame()->fp())) { + bool is_direct_api_throw = it.done(); + if (!is_direct_api_throw && ext_callback_scope != nullptr) { + Address comparable_fp = it.frame()->fp(); +#if V8_ENABLE_WEBASSEMBLY + if (!IsOnCentralStack(comparable_fp)) { + // The topmost frame is on a Wasm secondary stack, whereas + // |ext_callback_scope| is always on the central stack. Compare against + // the central-stack SP saved when switching to the secondary stack. + comparable_fp = thread_local_top()->central_stack_sp_; + DCHECK_NE(comparable_fp, kNullAddress); + DCHECK(IsOnCentralStack(comparable_fp)); + } +#endif // V8_ENABLE_WEBASSEMBLY + is_direct_api_throw = + ext_callback_scope->JSStackComparableAddress() < comparable_fp; + } + if (is_direct_api_throw) { // There were no crossings of "C++ -> JS" boundary at all or they happened // earlier than the last crossing of the "C++ -> Api callback" boundary. // In this case all the data about Api callback is available in the @@ -5656,6 +5669,9 @@ void Isolate::NotifyExceptionPropagationCallback() { // These frames are not created yet. UNREACHABLE(); case StackFrame::TURBOFAN_JS: +#if V8_ENABLE_WEBASSEMBLY + case StackFrame::WASM_TO_JS: +#endif // V8_ENABLE_WEBASSEMBLY // This must be a fast Api call. CHECK(it.frame()->InFastCCall()); // TODO(ishell): support fast Api calls. @@ -5666,6 +5682,7 @@ void Isolate::NotifyExceptionPropagationCallback() { return; #if V8_ENABLE_WEBASSEMBLY case StackFrame::WASM: + case StackFrame::WASM_EXIT: case StackFrame::WASM_SEGMENT_START: // No more info. return; @@ -8055,6 +8072,9 @@ void Isolate::DetachGlobal(DirectHandle env) { // Set security token back to default (unique) state making sure that only // accesses from the same native context are allowed. env->set_security_token(env->global_object()); + // Invalidate LoadGlobalIC/StoreGlobalIC handlers to enforce access checks + // for the rewired global proxy from the detached context. + JSObject::InvalidatePrototypeValidityCell(env->global_object()); } void Isolate::SetIsLoading(bool is_loading) { diff --git a/deps/v8/src/heap/factory.cc b/deps/v8/src/heap/factory.cc index d2a5f284e01f..acaf95db3abd 100644 --- a/deps/v8/src/heap/factory.cc +++ b/deps/v8/src/heap/factory.cc @@ -4005,15 +4005,15 @@ DirectHandle Factory::NewSourceTextModule( New(source_text_module_map(), AllocationType::kOld)); DisallowGarbageCollection no_gc; module->set_code(*sfi); + module->set_status(Module::kUnlinked); + module->set_module_namespace(roots.undefined_value(), SKIP_WRITE_BARRIER); + module->set_deferred_module_namespace(roots.undefined_value(), + SKIP_WRITE_BARRIER); module->set_exports(*exports); module->set_regular_exports(*regular_exports); module->set_regular_imports(*regular_imports); module->set_hash(isolate()->GenerateIdentityHash(Smi::kMaxValue)); - module->set_module_namespace(roots.undefined_value(), SKIP_WRITE_BARRIER); - module->set_deferred_module_namespace(roots.undefined_value(), - SKIP_WRITE_BARRIER); module->set_requested_modules(*requested_modules); - module->set_status(Module::kUnlinked); module->set_exception(roots.the_hole_value(), SKIP_WRITE_BARRIER); module->set_top_level_capability(roots.undefined_value(), SKIP_WRITE_BARRIER); module->set_import_meta(roots.the_hole_value(), kReleaseStore, diff --git a/deps/v8/src/ic/accessor-assembler.cc b/deps/v8/src/ic/accessor-assembler.cc index c262e24e75fe..0dfd75a46494 100644 --- a/deps/v8/src/ic/accessor-assembler.cc +++ b/deps/v8/src/ic/accessor-assembler.cc @@ -1554,7 +1554,7 @@ void AccessorAssembler::HandleStoreICHandlerCase( ICMode ic_mode, ElementSupport support_elements) { Label if_smi_handler(this), if_nonsmi_handler(this); Label if_proto_handler(this), call_handler(this), - store_transition_or_global_or_accessor(this); + store_transition_or_accessor(this); Branch(TaggedIsSmi(handler), &if_smi_handler, &if_nonsmi_handler); @@ -1685,8 +1685,7 @@ void AccessorAssembler::HandleStoreICHandlerCase( BIND(&if_nonsmi_handler); { TNode ref_handler = CAST(handler); - GotoIf(IsWeakOrCleared(ref_handler), - &store_transition_or_global_or_accessor); + GotoIf(IsWeakOrCleared(ref_handler), &store_transition_or_accessor); TNode strong_handler = CAST(handler); TNode handler_map = LoadMap(strong_handler); Branch(IsCodeMap(handler_map), &call_handler, &if_proto_handler); @@ -1711,39 +1710,17 @@ void AccessorAssembler::HandleStoreICHandlerCase( } } - BIND(&store_transition_or_global_or_accessor); + BIND(&store_transition_or_accessor); { // Load value or miss if the {handler} weak cell is cleared. CSA_DCHECK(this, IsWeakOrCleared(handler)); TNode strong_handler = GetHeapObjectAssumeWeak(handler, miss); - Label store_global(this), store_transition(this), store_accessor(this); + Label store_transition(this), store_accessor(this); TNode strong_handler_map = LoadMap(strong_handler); - GotoIf(IsPropertyCellMap(strong_handler_map), &store_global); Branch(IsAccessorPairMap(strong_handler_map), &store_accessor, &store_transition); - BIND(&store_global); - { - if (p->IsDefineNamedOwn()) { - // The global proxy has its attributes set in the global object, - // which can't be handled by StoreGlobalIC_PropertyCellCase when - // defining public fields. Handle it in runtime. - GotoIf(IsJSGlobalProxy(CAST(p->receiver())), &if_slow); - } else if (p->IsDefineKeyedOwn()) { - Label proceed_defining(this); - // StoreGlobalIC_PropertyCellCase doesn't support definition - // of private fields, so handle them in runtime. - GotoIfNot(IsSymbol(CAST(p->name())), &proceed_defining); - Branch(IsAnyPrivateName(CAST(p->name())), &if_slow, &proceed_defining); - BIND(&proceed_defining); - } - - TNode property_cell = CAST(strong_handler); - ExitPoint direct_exit(this); - StoreGlobalIC_PropertyCellCase(property_cell, p->value(), &direct_exit, - miss); - } BIND(&store_accessor); { TNode pair = CAST(strong_handler); diff --git a/deps/v8/src/ic/handler-configuration.cc b/deps/v8/src/ic/handler-configuration.cc index 63dbf68c790e..9b12fe2aec96 100644 --- a/deps/v8/src/ic/handler-configuration.cc +++ b/deps/v8/src/ic/handler-configuration.cc @@ -508,11 +508,6 @@ Handle StoreHandler::StoreInterceptorHolderIsReceiver( return handler; } -// static -MaybeObjectHandle StoreHandler::StoreGlobal(Handle cell) { - return MaybeObjectHandle::Weak(cell); -} - // static Handle StoreHandler::StoreProxy(Isolate* isolate, DirectHandle receiver_map, diff --git a/deps/v8/src/ic/handler-configuration.h b/deps/v8/src/ic/handler-configuration.h index 6e85b8f06f6e..5883a357073a 100644 --- a/deps/v8/src/ic/handler-configuration.h +++ b/deps/v8/src/ic/handler-configuration.h @@ -369,10 +369,6 @@ V8_OBJECT class StoreHandler final : public DataHandler { Handle proxy, DirectHandle receiver); - // Creates a handler for storing a property to the property cell of a global - // object. - static MaybeObjectHandle StoreGlobal(Handle cell); - // Creates a Smi-handler for storing a property to a global proxy object. static inline DirectHandle StoreGlobalProxy(Isolate* isolate); diff --git a/deps/v8/src/ic/ic-inl.h b/deps/v8/src/ic/ic-inl.h index e19ce57f2e9e..842a94128979 100644 --- a/deps/v8/src/ic/ic-inl.h +++ b/deps/v8/src/ic/ic-inl.h @@ -30,8 +30,7 @@ bool IC::IsHandler(Tagged object) { Tagged heap_object; return (IsSmi(object) && (object.ptr() != kNullAddress)) || (object.GetHeapObjectIfWeak(&heap_object) && - (IsMap(heap_object) || IsPropertyCell(heap_object) || - IsAccessorPair(heap_object))) || + (IsMap(heap_object) || IsAccessorPair(heap_object))) || (object.GetHeapObjectIfStrong(&heap_object) && (IsDataHandler(heap_object) || IsCode(heap_object))); } diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc index 681dac659f1f..f6e7d6422a27 100644 --- a/deps/v8/src/ic/ic.cc +++ b/deps/v8/src/ic/ic.cc @@ -1098,6 +1098,18 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) { TraceIC("LoadGlobalIC", lookup->name()); return; } + // Own DATA properties above are accessed directly via PropertyCell on the + // JSGlobalObject and don't involve the JSGlobalProxy. For anything else + // (e.g. prototype accessors), the handler would substitute global_proxy + // as the receiver without performing an access check on it, and + // LookupIterator didn't fail an access check because JSGlobalObject + // belongs to the current (detached) native context while its global_proxy + // may have been rebound to a new cross-origin context. + if (Cast(*lookup->GetReceiver())->IsDetached()) { + SetCache(lookup->GetName(), LoadHandler::LoadSlow(isolate())); + TraceIC("LoadGlobalIC", lookup->GetName()); + return; + } } handler = ComputeHandler(lookup); CHECK(lookup->state() == LookupIterator::STRING_LOOKUP_START_OBJECT || @@ -2416,6 +2428,16 @@ void StoreIC::UpdateCaches(LookupIterator* lookup, DirectHandle value, TraceIC("StoreGlobalIC", lookup->GetName()); return; } + // See comment in LoadIC::UpdateCaches: own DATA properties above use + // PropertyCell on the JSGlobalObject directly, whereas other handlers + // (e.g. prototype accessors) substitute global_proxy as the receiver, + // which may have been rebound to a cross-origin context upon detachment. + if (Cast(*lookup->GetReceiver())->IsDetached()) { + set_slow_stub_reason("detached global object"); + SetCache(lookup->GetName(), StoreHandler::StoreSlow(isolate())); + TraceIC("StoreGlobalIC", lookup->GetName()); + return; + } } handler = ComputeHandler(lookup); } else { @@ -2436,16 +2458,6 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { if (IsJSGlobalObject(*store_target)) { TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransitionDH); - if (IsJSGlobalObject(*lookup_start_object_map())) { - DCHECK(IsStoreGlobalIC()); -#ifdef DEBUG - DirectHandle holder = lookup->GetHolder(); - DCHECK_EQ(*lookup->GetReceiver(), *holder); - DCHECK_EQ(*store_target, *holder); -#endif - return StoreHandler::StoreGlobal( - indirect_handle(lookup->transition_cell(), isolate())); - } if (IsDefineKeyedOwnIC()) { // Private field can't be deleted from this global object and can't // be overwritten, so install slow handler in order to make store IC @@ -2662,9 +2674,19 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { } if (lookup->is_dictionary_holder()) { if (IsJSGlobalObject(*holder)) { + DCHECK(!IsStoreGlobalIC()); + DCHECK(IsJSGlobalProxy(*receiver)); + if (IsAnyDefineOwn()) { + TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); + return MaybeObjectHandle(StoreHandler::StoreSlow(isolate())); + } TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalDH); - return MaybeObjectHandle(StoreHandler::StoreGlobal( - indirect_handle(lookup->GetPropertyCell(), isolate()))); + DirectHandle smi_handler = + StoreHandler::StoreGlobalProxy(isolate()); + Handle handler = StoreHandler::StoreThroughPrototype( + isolate(), lookup_start_object_map(), holder, *smi_handler, + MaybeObjectDirectHandle::Weak(lookup->GetPropertyCell())); + return MaybeObjectHandle(handler); } TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNormalDH); DCHECK(holder.is_identical_to(receiver)); diff --git a/deps/v8/src/interpreter/bytecode-flags-and-tokens.h b/deps/v8/src/interpreter/bytecode-flags-and-tokens.h index 0adacdcd93d9..d9956be2e8b3 100644 --- a/deps/v8/src/interpreter/bytecode-flags-and-tokens.h +++ b/deps/v8/src/interpreter/bytecode-flags-and-tokens.h @@ -97,6 +97,23 @@ class StoreLookupSlotFlags { DISALLOW_IMPLICIT_CONSTRUCTORS(StoreLookupSlotFlags); }; +class ResolveEvalFlags { + public: + using LanguageModeBit = base::BitField; + using PrivateNameLookupSkipsOuterClassBit = LanguageModeBit::Next; + static_assert(LanguageModeSize <= LanguageModeBit::kNumValues); + + static int Encode(LanguageMode language_mode, + bool private_name_lookup_skips_outer_class) { + return LanguageModeBit::encode(language_mode) | + PrivateNameLookupSkipsOuterClassBit::encode( + private_name_lookup_skips_outer_class); + } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ResolveEvalFlags); +}; + enum class TryFinallyContinuationToken: int { // Fixed value tokens for paths we know we need. // Fallthrough is set to -1 to make it the fallthrough case of the jump table, diff --git a/deps/v8/src/interpreter/bytecode-generator.cc b/deps/v8/src/interpreter/bytecode-generator.cc index b6b593263013..f6651020361a 100644 --- a/deps/v8/src/interpreter/bytecode-generator.cc +++ b/deps/v8/src/interpreter/bytecode-generator.cc @@ -3691,7 +3691,10 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) { DCHECK_EQ(ClassBoilerplate::kFirstDynamicArgumentIndex, args.register_count()); - VisitForAccumulatorValueOrTheHole(expr->extends()); + { + ClassScope::HeritageParsingScope heritage(expr->scope()); + VisitForAccumulatorValueOrTheHole(expr->extends()); + } builder()->StoreAccumulatorInRegister(super_class); VisitFunctionLiteral(expr->constructor()); @@ -7061,16 +7064,24 @@ void BytecodeGenerator::VisitCall(Call* expr) { builder()->MoveRegister(args[receiver_arg_count], runtime_call_args[1]); } Scope* scope_with_context = current_scope(); + bool private_name_lookup_skips_outer_class = false; if (!scope_with_context->NeedsContext()) { + private_name_lookup_skips_outer_class = + scope_with_context->private_name_lookup_skips_outer_class(); scope_with_context = scope_with_context->GetOuterScopeWithContext(); + } else if (scope_with_context->is_class_scope()) { + private_name_lookup_skips_outer_class = + scope_with_context->AsClassScope()->IsParsingHeritage(); } if (scope_with_context) { eval_calls_.emplace_back(expr, scope_with_context); } + int eval_flags = ResolveEvalFlags::Encode( + language_mode(), private_name_lookup_skips_outer_class); builder() ->MoveRegister(callee, runtime_call_args[0]) .MoveRegister(Register::function_closure(), runtime_call_args[2]) - .LoadLiteral(Smi::FromEnum(language_mode())) + .LoadLiteral(Smi::FromInt(eval_flags)) .StoreAccumulatorInRegister(runtime_call_args[3]) .LoadLiteral(Smi::FromInt(expr->eval_scope_info_index())) .StoreAccumulatorInRegister(runtime_call_args[4]) diff --git a/deps/v8/src/maglev/maglev-graph-builder.cc b/deps/v8/src/maglev/maglev-graph-builder.cc index d9ed8b2c9fbd..05a3fa8fcb50 100644 --- a/deps/v8/src/maglev/maglev-graph-builder.cc +++ b/deps/v8/src/maglev/maglev-graph-builder.cc @@ -278,14 +278,31 @@ MaglevGraphBuilder::LazyDeoptResultLocationScope:: builder_->lazy_deopt_result_location_scope_ = previous_; } -class MaglevGraphBuilder::MaglevSubGraphBuilder::LoopLabel { +class V8_NODISCARD MaglevGraphBuilder::MaglevSubGraphBuilder::LoopLabel { public: + LoopLabel(const LoopLabel&) = delete; + LoopLabel(LoopLabel&&) = delete; + LoopLabel& operator=(const LoopLabel&) = delete; + LoopLabel& operator=(LoopLabel&&) = delete; + + ~LoopLabel() { + if (merge_state_ != nullptr) { + // An early abort exited the subgraph before EndLoop was reached. + DCHECK_NULL(sub_builder_->builder_->current_block()); + merge_state_->MergeDeadLoop(*sub_builder_->dummy_unit_); + } + } + private: - explicit LoopLabel(LoopMergePointInterpreterFrameState* merge_state, - BasicBlock* loop_header) - : merge_state_(merge_state), loop_header_(loop_header) {} + LoopLabel(MaglevSubGraphBuilder* sub_builder, + LoopMergePointInterpreterFrameState* merge_state, + BasicBlock* loop_header) + : sub_builder_(sub_builder), + merge_state_(merge_state), + loop_header_(loop_header) {} friend class MaglevSubGraphBuilder; + MaglevSubGraphBuilder* sub_builder_; LoopMergePointInterpreterFrameState* merge_state_ = nullptr; BasicBlock* loop_header_; }; @@ -420,7 +437,7 @@ MaglevGraphBuilder::MaglevSubGraphBuilder::BeginLoop( builder_->ProcessMergePointPredecessors(*loop_state, loop_header_ref); builder_->StartNewBlock(nullptr, loop_state, loop_header_ref); - return LoopLabel{loop_state, loop_header_ref.block_ptr()}; + return LoopLabel{this, loop_state, loop_header_ref.block_ptr()}; } template @@ -477,8 +494,12 @@ void MaglevGraphBuilder::MaglevSubGraphBuilder::MergeDeadInterpreterFrameState( } void MaglevGraphBuilder::MaglevSubGraphBuilder::EndLoop(LoopLabel* loop_label) { + // Ensure EndLoop is called only once and disarm ~LoopLabel(). + LoopMergePointInterpreterFrameState* merge_state = loop_label->merge_state_; + DCHECK_NOT_NULL(merge_state); + loop_label->merge_state_ = nullptr; if (builder_->current_block() == nullptr) { - loop_label->merge_state_->MergeDeadLoop(*dummy_unit_); + merge_state->MergeDeadLoop(*dummy_unit_); return; } @@ -486,11 +507,11 @@ void MaglevGraphBuilder::MaglevSubGraphBuilder::EndLoop(LoopLabel* loop_label) { builder_->FinishBlockNoAbort({}, loop_label->loop_header_); { BorrowParentKnownNodeAspectsAndVOs borrow(this); - loop_label->merge_state_->MergeLoop( - builder_->graph(), builder_->is_tracing(), *dummy_unit_, - variable_frame_, block, builder_->GetLatestCheckpointedFrame()); + merge_state->MergeLoop(builder_->graph(), builder_->is_tracing(), + *dummy_unit_, variable_frame_, block, + builder_->GetLatestCheckpointedFrame()); } - block->set_predecessor_id(loop_label->merge_state_->predecessor_count() - 1); + block->set_predecessor_id(merge_state->predecessor_count() - 1); } void MaglevGraphBuilder::MaglevSubGraphBuilder::Bind(Label* label) { @@ -9011,19 +9032,12 @@ MaybeReduceResult MaglevGraphBuilder::TryReduceFunctionPrototypeCall( MaybeReduceResult MaglevGraphBuilder::TryReduceFunctionPrototypeApply( compiler::JSFunctionRef target, CallArguments& args) { - compiler::OptionalHeapObjectRef maybe_receiver; - if (current_speculation_feedback().IsValid()) { - const compiler::ProcessedFeedback& processed_feedback = - broker()->GetFeedbackForCall(current_speculation_feedback()); - DCHECK_EQ(processed_feedback.kind(), compiler::ProcessedFeedback::kCall); - const compiler::CallFeedback& call_feedback = processed_feedback.AsCall(); - if (call_feedback.call_feedback_content() == - CallFeedbackContent::kReceiver) { - maybe_receiver = call_feedback.target(); - } - } + // We should have taken the `BuildCallWithFeedback` path for the typical + // Function.prototype.apply speculation-based optimization. If we are on this + // code path, we must be inside an apply inside another inlining and shouldn't + // use the feedback receiver. return TryReduceFunctionPrototypeApplyCallWithReceiver( - maybe_receiver, args, current_speculation_feedback()); + {}, args, current_speculation_feedback()); } namespace { @@ -11533,7 +11547,7 @@ MaybeReduceResult MaglevGraphBuilder::TryReduceCallForNewClosure( MaybeReduceResult MaglevGraphBuilder::TryReduceFunctionPrototypeApplyCallWithReceiver( - compiler::OptionalHeapObjectRef maybe_receiver, CallArguments& args, + compiler::OptionalJSFunctionRef maybe_receiver, CallArguments& args, const compiler::FeedbackSource& feedback_source) { if (args.mode() != CallArguments::kDefault) return {}; diff --git a/deps/v8/src/maglev/maglev-graph-builder.h b/deps/v8/src/maglev/maglev-graph-builder.h index a439094bb6d8..f3d9c57f1895 100644 --- a/deps/v8/src/maglev/maglev-graph-builder.h +++ b/deps/v8/src/maglev/maglev-graph-builder.h @@ -309,7 +309,7 @@ class MaglevGraphBuilder { using Label = Base::Label; using LabelForTrackingInterpreterFrameState = Base::LabelForTrackingInterpreterFrameState; - class LoopLabel; + class V8_NODISCARD LoopLabel; MaglevSubGraphBuilder(MaglevGraphBuilder* builder, int variable_count); LoopLabel BeginLoop(std::initializer_list loop_vars); @@ -1072,7 +1072,7 @@ class MaglevGraphBuilder { compiler::OptionalSharedFunctionInfoRef maybe_shared, CallArguments& args); MaybeReduceResult TryReduceFunctionPrototypeApplyCallWithReceiver( - compiler::OptionalHeapObjectRef maybe_receiver, CallArguments& args, + compiler::OptionalJSFunctionRef maybe_receiver, CallArguments& args, const compiler::FeedbackSource& feedback_source); template diff --git a/deps/v8/src/maglev/maglev-graph-optimizer.cc b/deps/v8/src/maglev/maglev-graph-optimizer.cc index a78420a1338a..e0e64964a520 100644 --- a/deps/v8/src/maglev/maglev-graph-optimizer.cc +++ b/deps/v8/src/maglev/maglev-graph-optimizer.cc @@ -591,6 +591,20 @@ bool MaglevGraphOptimizer::IsRangeLessEqual(ValueNode* lhs, ValueNode* rhs) { return ranges_->IsLessEqualConstraint(reducer_.current_block(), lhs, rhs); } +ProcessResult MaglevGraphOptimizer::OverwriteWith(Opcode opcode) { + TRACE(TraceColor::kDarkGreen << "Overwriting " + << PrintNodeLabel(current_node()) << " with " + << opcode); + + current_node()->OverwriteWith(opcode); + + // Since we've changed the type of the node, we need to trigger a revisit, + // otherwise the next processors would see a stale static type for this node + // and will thus wrongly treat it as a node of the old type instead of the new + // one. + return ProcessResult::kRevisit; +} + ProcessResult MaglevGraphOptimizer::ReplaceWith(ValueNode* node) { // If current node is not a value node, we shouldn't try to replace it. CHECK(current_node()->Cast()); @@ -2697,7 +2711,7 @@ UNTAGGING_CASE(UnsafeNumberOrOddballToHoleyFloat64, HoleyFloat64, REPLACE_AND_RETURN_IF_DONE(GetUntaggedValueWithRepresentation( \ node->input_node(0), UseRepresentation::k##Repr, ConvType)); \ if (reducer_.CheckType(node->input_node(0), ConvType)) { \ - node->OverwriteWith(Opcode::k##UnsafeNode); \ + return OverwriteWith(Opcode::k##UnsafeNode); \ } \ return ProcessResult::kContinue; \ } @@ -2749,7 +2763,7 @@ ProcessResult MaglevGraphOptimizer::VisitCheckedSmiUntag( // } // DCHECK(maybe_input.IsFail()); if (reducer_.CheckType(node->input_node(0), NodeType::kSmi)) { - node->OverwriteWith(Opcode::kUnsafeSmiUntag); + return OverwriteWith(Opcode::kUnsafeSmiUntag); } return ProcessResult::kContinue; } @@ -2771,7 +2785,7 @@ ProcessResult MaglevGraphOptimizer::VisitCheckedNumberToFloat64( return ProcessResult::kTruncateBlock; } if (reducer_.CheckType(node->input_node(0), NodeType::kNumber)) { - node->OverwriteWith(Opcode::kUnsafeNumberToFloat64); + return OverwriteWith(Opcode::kUnsafeNumberToFloat64); } return ProcessResult::kContinue; } @@ -2795,7 +2809,7 @@ ProcessResult MaglevGraphOptimizer::VisitUnsafeFloat64ToHoleyFloat64( // undefined NaN since the widen was chosen, and widening those would give // them back their meaning. if (node->ValueInput().node()->MayBeHoleOrUndefinedNan()) { - node->OverwriteWith(Opcode::kChangeFloat64ToHoleyFloat64); + return OverwriteWith(Opcode::kChangeFloat64ToHoleyFloat64); } return ProcessResult::kContinue; } @@ -3975,7 +3989,7 @@ ProcessResult MaglevGraphOptimizer::VisitTruncateCheckedNumberAsSafeIntToInt32( return ReplaceWith(node->input_node(0)->input_node(0)); } if (reducer_.CheckType(node->input_node(0), NodeType::kNumber)) { - node->OverwriteWith(Opcode::kTruncateUnsafeNumberAsSafeIntToInt32); + return OverwriteWith(Opcode::kTruncateUnsafeNumberAsSafeIntToInt32); } return ProcessResult::kContinue; } diff --git a/deps/v8/src/maglev/maglev-graph-optimizer.h b/deps/v8/src/maglev/maglev-graph-optimizer.h index 7e98d1059f26..56b77b7055ac 100644 --- a/deps/v8/src/maglev/maglev-graph-optimizer.h +++ b/deps/v8/src/maglev/maglev-graph-optimizer.h @@ -179,6 +179,8 @@ class V8_EXPORT_PRIVATE MaglevGraphOptimizer { template MaybeReduceResult AbortIfInvalidFixedArrayIndex(NodeT* node); + ProcessResult OverwriteWith(Opcode opcode); + ProcessResult ReplaceWith(ValueNode* node); template diff --git a/deps/v8/src/maglev/maglev-ir.h b/deps/v8/src/maglev/maglev-ir.h index c9adf3113aed..a2badf6c94ce 100644 --- a/deps/v8/src/maglev/maglev-ir.h +++ b/deps/v8/src/maglev/maglev-ir.h @@ -5420,7 +5420,9 @@ class CreateArrayLiteral : public FixedInputValueNodeT<0, CreateArrayLiteral> { static constexpr OpProperties kProperties = OpProperties::Call() | OpProperties::CanAllocate() | OpProperties::CanThrow() | OpProperties::LazyDeopt() | - OpProperties::NotIdempotent(); + OpProperties::NotIdempotent() | + // The runtime call may make prototype maps fast. + OpProperties::CanWrite(); int MaxCallStackArgs() const; void SetValueLocationConstraints(); @@ -5488,7 +5490,9 @@ class CreateObjectLiteral static constexpr OpProperties kProperties = OpProperties::Call() | OpProperties::CanAllocate() | OpProperties::CanThrow() | OpProperties::LazyDeopt() | - OpProperties::NotIdempotent(); + OpProperties::NotIdempotent() | + // The runtime call may make prototype maps fast. + OpProperties::CanWrite(); int MaxCallStackArgs() const; void SetValueLocationConstraints(); diff --git a/deps/v8/src/maglev/maglev-known-node-aspects.h b/deps/v8/src/maglev/maglev-known-node-aspects.h index dd1ce8cc3858..7b64d3b57c09 100644 --- a/deps/v8/src/maglev/maglev-known-node-aspects.h +++ b/deps/v8/src/maglev/maglev-known-node-aspects.h @@ -460,12 +460,10 @@ class KnownNodeAspects { } const NodeInfo* TryGetInfoFor(ValueNode* node) const { - node = node->Unwrap(); return const_cast(this)->TryGetInfoFor(node); } NodeInfo* TryGetInfoFor(ValueNode* node) { - node = node->Unwrap(); auto info_it = FindInfo(node); if (!IsValid(info_it)) return nullptr; return &info_it->second; @@ -481,8 +479,8 @@ class KnownNodeAspects { NodeInfo* GetOrCreateInfoFor(compiler::JSHeapBroker* broker, ValueNode* node) { - node = node->Unwrap(); - auto info_it = FindInfo(node); + node = UnwrapNode(node); + auto info_it = node_infos_.find(node); if (IsValid(info_it)) return &info_it->second; auto res = &node_infos_.emplace(node, NodeInfo()).first->second; res->IntersectType(node->GetStaticType(broker)); @@ -490,7 +488,6 @@ class KnownNodeAspects { } ValueNode* TryGetAlternativeFor(ValueNode* node, UseRepresentation repr) { - node = node->Unwrap(); auto info_it = FindInfo(node); if (!IsValid(info_it)) return nullptr; return info_it->second.alternative().get(repr); @@ -1018,12 +1015,58 @@ class KnownNodeAspects { return it->second->UnwrapIdentities(); } + // Only unwrap conversions that preserve `NodeType` invariants across + // representations (e.g. `kSmi` means Smi-tagged for tagged values, but only + // Smi-sized for untagged values). + // TODO(496266449): Remove once `kTagged` is split into `kSmi` and + // `kTaggedPointer` representations. + static ValueNode* UnwrapNode(ValueNode* node) { + while (true) { + if (node->Is() || node->Is()) { + node = node->input_node(0); + continue; + } + if (!node->is_conversion()) break; + switch (node->opcode()) { + case Opcode::kCheckedNumberToInt32: + case Opcode::kCheckedNumberToFloat64: + case Opcode::kUnsafeNumberToFloat64: + case Opcode::kCheckedObjectToIndex: + case Opcode::kUnsafeInt32ToUint32: + return node; + // kForceHeapNumber allocates a HeapNumber even for Smi-sized inputs. + case Opcode::kInt32ToNumber: + if (node->Cast()->conversion_mode() == + NumberConversionMode::kForceHeapNumber) { + return node; + } + break; + case Opcode::kFloat64ToTagged: + if (node->Cast()->conversion_mode() == + NumberConversionMode::kForceHeapNumber) { + return node; + } + break; + case Opcode::kHoleyFloat64ToTagged: + if (node->Cast()->conversion_mode() == + NumberConversionMode::kForceHeapNumber) { + return node; + } + break; + default: + break; + } + node = node->input_node(0); + } + return node; + } + NodeInfos::iterator FindInfo(ValueNode* node) { - node = node->Unwrap(); + node = UnwrapNode(node); return node_infos_.find(node); } NodeInfos::const_iterator FindInfo(ValueNode* node) const { - node = node->Unwrap(); + node = UnwrapNode(node); return node_infos_.find(node); } bool IsValid(NodeInfos::iterator& it) { return it != node_infos_.end(); } diff --git a/deps/v8/src/maglev/maglev-reducer-inl.h b/deps/v8/src/maglev/maglev-reducer-inl.h index 413713365738..50d7d2263784 100644 --- a/deps/v8/src/maglev/maglev-reducer-inl.h +++ b/deps/v8/src/maglev/maglev-reducer-inl.h @@ -836,6 +836,8 @@ ReduceResult MaglevReducer::BuildInitializeStore_Tagged( } DCHECK(value->is_tagged()); + RETURN_IF_ABORT(BuildStoreTaggedField(object, value, desc.offset, store_mode, + PropertyKey::None(), maybe_assigned)); if (InlinedAllocation* inlined_value = value->TryCast()) { // Add to the escape set. auto escape_deps = graph()->allocations_escape_map().find(object); @@ -845,11 +847,10 @@ ReduceResult MaglevReducer::BuildInitializeStore_Tagged( auto& elided_map = graph()->allocations_elide_map(); auto elided_deps = elided_map.try_emplace(inlined_value, zone()).first; elided_deps->second.push_back(object); - inlined_value->AddNonEscapingUses(); + AddNonEscapingUses(inlined_value, 1); } - return BuildStoreTaggedField(object, value, desc.offset, store_mode, - PropertyKey::None(), maybe_assigned); + return ReduceResult::Done(); } template diff --git a/deps/v8/src/objects/deoptimization-data.h b/deps/v8/src/objects/deoptimization-data.h index bd9560282440..b63f4e4a6d5e 100644 --- a/deps/v8/src/objects/deoptimization-data.h +++ b/deps/v8/src/objects/deoptimization-data.h @@ -92,7 +92,10 @@ class DeoptimizationLiteral { return literal; } - IndirectHandle object() const { return object_; } + bool IsObject(IndirectHandle object) const { + return kind_ == DeoptimizationLiteralKind::kObject && + object_.equals(object); + } bool operator==(const DeoptimizationLiteral& other) const { if (kind_ != other.kind_) { diff --git a/deps/v8/src/objects/module-inl.h b/deps/v8/src/objects/module-inl.h index fb9d42c9ba85..e7097827097d 100644 --- a/deps/v8/src/objects/module-inl.h +++ b/deps/v8/src/objects/module-inl.h @@ -8,6 +8,7 @@ #include "src/objects/module.h" // Include the non-inl header before the rest of the headers. +#include "src/objects/cell-inl.h" #include "src/objects/js-promise-inl.h" #include "src/objects/oddball-predicates-inl.h" #include "src/objects/scope-info.h" @@ -172,6 +173,7 @@ void SourceTextModule::DecrementPendingAsyncDependencies() { Tagged Module::exports() const { return exports_.load(); } void Module::set_exports(Tagged value, WriteBarrierMode mode) { + CHECK(!ExportsFinalized()); exports_.store(this, value, mode); } @@ -197,6 +199,16 @@ void Module::set_deferred_module_namespace( deferred_module_namespace_.store(this, value, mode); } +bool Module::ExportsFinalized() const { + bool res = + (!IsUndefined(module_namespace()) && + IsJSModuleNamespace(Cast(module_namespace())->value())) || + (!IsUndefined(deferred_module_namespace()) && + IsJSModuleNamespace(Cast(deferred_module_namespace())->value())); + DCHECK_IMPLIES(res, status() >= kLinking); + return res; +} + Tagged JSModuleNamespace::module() const { return module_.load(); } void JSModuleNamespace::set_module(Tagged value, diff --git a/deps/v8/src/objects/module.h b/deps/v8/src/objects/module.h index 925b7d361666..43118f6e11af 100644 --- a/deps/v8/src/objects/module.h +++ b/deps/v8/src/objects/module.h @@ -110,6 +110,11 @@ V8_OBJECT class Module : public HeapObject { inline void set_exception(Tagged value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + // Once a module namespace (normal or deferred) has been created in + // GetModuleNamespace, all star exports have been fetched and {exports} is + // finalized (must not be mutated or rehashed as ICs index into it). + inline bool ExportsFinalized() const; + inline Tagged> top_level_capability() const; inline void set_top_level_capability( Tagged> value, diff --git a/deps/v8/src/objects/source-text-module.cc b/deps/v8/src/objects/source-text-module.cc index 0c50a5139d6c..8a9cb6cda8a9 100644 --- a/deps/v8/src/objects/source-text-module.cc +++ b/deps/v8/src/objects/source-text-module.cc @@ -371,11 +371,14 @@ MaybeHandle SourceTextModule::ResolveExportUsingStarExports( if (!unique_cell.is_null()) { // Found a unique star export for this name. - Handle exports(module->exports(), isolate); - DCHECK(IsTheHole(exports->Lookup(export_name))); - exports = - ObjectHashTable::Put(isolate, exports, export_name, unique_cell); - module->set_exports(*exports); + if (module->status() <= kLinking) { + DCHECK(!module->ExportsFinalized()); + Handle exports(module->exports(), isolate); + DCHECK(IsTheHole(exports->Lookup(export_name))); + exports = + ObjectHashTable::Put(isolate, exports, export_name, unique_cell); + module->set_exports(*exports); + } return unique_cell; } } @@ -773,8 +776,7 @@ void SourceTextModule::FetchStarExports(Isolate* isolate, DCHECK_GE(module->status(), Module::kLinking); // Shortcut. - if (!IsUndefined(module->module_namespace()) && - IsJSModuleNamespace(Cast(module->module_namespace())->value())) { + if (module->ExportsFinalized()) { return; } diff --git a/deps/v8/src/parsing/parser.cc b/deps/v8/src/parsing/parser.cc index 388e4f1c96e7..c853b24dc73e 100644 --- a/deps/v8/src/parsing/parser.cc +++ b/deps/v8/src/parsing/parser.cc @@ -744,12 +744,20 @@ void Parser::ParseProgram(Isolate* isolate, DirectHandle