diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index d47b8f7f5c8b..784ce8992332 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 13 +#define V8_PATCH_LEVEL 22 // 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 7713cd8103dd..725f007719d4 100644 --- a/deps/v8/src/ast/scopes.cc +++ b/deps/v8/src/ast/scopes.cc @@ -345,6 +345,7 @@ void DeclarationScope::SetDefaults() { is_module_scope()); set_needs_private_name_context_chain_recalc(false); set_class_scope_has_private_brand(false); + set_class_initializer_allows_await(false); receiver_ = nullptr; new_target_ = nullptr; function_ = nullptr; @@ -1575,7 +1576,8 @@ bool Scope::NeedsScopeInfo() const { } bool Scope::ShouldBanArguments() { - return GetReceiverScope()->should_ban_arguments(); + return GetReceiverScope()->should_ban_arguments() && + !GetClosureScope()->from_scope_info(); } DeclarationScope* Scope::GetReceiverScope() { diff --git a/deps/v8/src/ast/scopes.h b/deps/v8/src/ast/scopes.h index f85e7420968f..fa13cc9a176c 100644 --- a/deps/v8/src/ast/scopes.h +++ b/deps/v8/src/ast/scopes.h @@ -1387,6 +1387,13 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { return ClassScopeHasPrivateBrandField::decode(flags_); } + bool class_initializer_allows_await() const { + return ClassInitializerAllowsAwaitField::decode(flags_); + } + void set_class_initializer_allows_await(bool value) { + flags_ = ClassInitializerAllowsAwaitField::update(flags_, value); + } + private: V8_INLINE void AllocateParameter(Variable* var, int index); @@ -1430,6 +1437,8 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { HasThisDeclarationField::Next; using ClassScopeHasPrivateBrandField = NeedsPrivateNameContextChainRecalcField::Next; + using ClassInitializerAllowsAwaitField = + ClassScopeHasPrivateBrandField::Next; #if DEBUG bool is_being_lazily_parsed_; diff --git a/deps/v8/src/codegen/compiler.cc b/deps/v8/src/codegen/compiler.cc index fbcf0d8ba77a..0a3599ee41c4 100644 --- a/deps/v8/src/codegen/compiler.cc +++ b/deps/v8/src/codegen/compiler.cc @@ -2852,8 +2852,8 @@ void BackgroundDeserializeTask::Run() { LocalHandleScope handle_scope(&isolate); DirectHandle inner_result; - off_thread_data_ = - CodeSerializer::StartDeserializeOffThread(&isolate, &cached_data_); + CodeSerializer::StartDeserializeOffThread(&isolate, &cached_data_, + &off_thread_data_); if (v8_flags.enable_slow_asserts && off_thread_data_.HasResult()) { #ifdef ENABLE_SLOW_DCHECKS MergeAssumptionChecker checker(&isolate, false); @@ -2866,6 +2866,11 @@ void BackgroundDeserializeTask::SourceTextAvailable( Isolate* isolate, Handle source_text, const ScriptDetails& script_details) { DCHECK_EQ(isolate, isolate_for_local_isolate_); + if (!CodeSerializer::NotifySourceTextAvailable(isolate, &off_thread_data_, + &cached_data_, source_text, + script_details)) { + return; + } LanguageMode language_mode = construct_language_mode(v8_flags.use_strict); background_merge_task_.SetUpOnMainThread(isolate, source_text, script_details, language_mode); diff --git a/deps/v8/src/codegen/compiler.h b/deps/v8/src/codegen/compiler.h index 7f8c3152e8ac..cfa6af01010b 100644 --- a/deps/v8/src/codegen/compiler.h +++ b/deps/v8/src/codegen/compiler.h @@ -719,7 +719,7 @@ class V8_EXPORT_PRIVATE BackgroundDeserializeTask { private: Isolate* isolate_for_local_isolate_; AlignedCachedData cached_data_; - CodeSerializer::OffThreadDeserializeData off_thread_data_; + OffThreadDeserializeData off_thread_data_; BackgroundMergeTask background_merge_task_; TimedHistogram* timer_; int64_t background_time_in_microseconds_ = 0; diff --git a/deps/v8/src/compiler/common-operator.cc b/deps/v8/src/compiler/common-operator.cc index 37ab33d7f744..0bc7016d6aba 100644 --- a/deps/v8/src/compiler/common-operator.cc +++ b/deps/v8/src/compiler/common-operator.cc @@ -515,6 +515,32 @@ const ExitMachineGraphParameters& ExitMachineGraphParametersOf( return OpParameter(op); } +#if V8_ENABLE_SANDBOX +size_t hash_value(const LoadTrustedPointerParameters& params) { + return base::hash_combine(params.offset, params.tag); +} + +V8_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, LoadTrustedPointerParameters params) { + return os << "offset=" << params.offset << ", tag.first=" << params.tag.first + << ", tag.last=" << params.tag.last; +} + +class LoadTrustedPointerOperator final + : public Operator1 { + public: + LoadTrustedPointerOperator(int offset, IndirectPointerTagRange tag) + : Operator1( + IrOpcode::kLoadTrustedPointer, Operator::kEliminatable, + "LoadTrustedPointer", 1, 1, 1, 1, 1, 0, {offset, tag}) {} +}; + +const Operator* CommonOperatorBuilder::LoadTrustedPointer( + int offset, IndirectPointerTagRange tag) { + return zone_->New(offset, tag); +} +#endif // V8_ENABLE_SANDBOX + #define COMMON_CACHED_OP_LIST(V) \ V(Plug, Operator::kNoProperties, 0, 0, 0, 1, 0, 0) \ V(Dead, Operator::kFoldable, 0, 0, 0, 1, 1, 1) \ diff --git a/deps/v8/src/compiler/common-operator.h b/deps/v8/src/compiler/common-operator.h index 6499e23637c3..3a1188f3574f 100644 --- a/deps/v8/src/compiler/common-operator.h +++ b/deps/v8/src/compiler/common-operator.h @@ -538,6 +538,20 @@ V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, V8_EXPORT_PRIVATE const ExitMachineGraphParameters& ExitMachineGraphParametersOf(const Operator* op) V8_WARN_UNUSED_RESULT; +#if V8_ENABLE_SANDBOX +struct LoadTrustedPointerParameters { + int offset; + IndirectPointerTagRange tag; + + bool operator==(const LoadTrustedPointerParameters&) const = default; +}; + +size_t hash_value(const LoadTrustedPointerParameters& params); + +V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, + LoadTrustedPointerParameters params); +#endif // V8_ENABLE_SANDBOX + // Interface for building common operators that can be used at any level of IR, // including JavaScript, mid-level, and low-level. class V8_EXPORT_PRIVATE CommonOperatorBuilder final @@ -616,6 +630,9 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final const Operator* HeapConstant(const Handle&); const Operator* CompressedHeapConstant(const Handle&); const Operator* TrustedHeapConstant(const Handle&); +#if V8_ENABLE_SANDBOX + const Operator* LoadTrustedPointer(int offset, IndirectPointerTagRange tag); +#endif const Operator* ObjectId(uint32_t); const Operator* RelocatableInt32Constant(int32_t value, diff --git a/deps/v8/src/compiler/opcodes.h b/deps/v8/src/compiler/opcodes.h index de11918ad138..d74406bfe7b0 100644 --- a/deps/v8/src/compiler/opcodes.h +++ b/deps/v8/src/compiler/opcodes.h @@ -85,15 +85,16 @@ V(EnterMachineGraph) \ V(ExitMachineGraph) -#define COMMON_OP_LIST(V) \ - CONSTANT_OP_LIST(V) \ - INNER_OP_LIST(V) \ - V(Unreachable) \ - V(DeadValue) \ - V(Dead) \ - V(Plug) \ - V(SLVerifierHint) \ - V(MajorGCForCompilerTesting) \ +#define COMMON_OP_LIST(V) \ + CONSTANT_OP_LIST(V) \ + INNER_OP_LIST(V) \ + V(Unreachable) \ + V(DeadValue) \ + V(Dead) \ + V(Plug) \ + V(SLVerifierHint) \ + V(MajorGCForCompilerTesting) \ + IF_SANDBOX(V, LoadTrustedPointer) \ V(StaticAssert) // Opcodes for JavaScript operators. diff --git a/deps/v8/src/compiler/simplified-lowering-verifier.cc b/deps/v8/src/compiler/simplified-lowering-verifier.cc index d288ed102b06..6d41bbb8a324 100644 --- a/deps/v8/src/compiler/simplified-lowering-verifier.cc +++ b/deps/v8/src/compiler/simplified-lowering-verifier.cc @@ -504,6 +504,7 @@ void SimplifiedLoweringVerifier::VisitNode(Node* node, CASE(Dead) CASE(Plug) CASE(MajorGCForCompilerTesting) + IF_SANDBOX(CASE, LoadTrustedPointer) CASE(StaticAssert) // Simplified change operators CASE(ChangeTaggedSignedToInt32) diff --git a/deps/v8/src/compiler/turbofan-typer.cc b/deps/v8/src/compiler/turbofan-typer.cc index 16fa4b6c4435..04df61211293 100644 --- a/deps/v8/src/compiler/turbofan-typer.cc +++ b/deps/v8/src/compiler/turbofan-typer.cc @@ -1297,6 +1297,9 @@ Type Typer::Visitor::TypeMajorGCForCompilerTesting(Node* node) { UNREACHABLE(); } Type Typer::Visitor::TypeStaticAssert(Node* node) { UNREACHABLE(); } +#if V8_ENABLE_SANDBOX +Type Typer::Visitor::TypeLoadTrustedPointer(Node* node) { UNREACHABLE(); } +#endif Type Typer::Visitor::TypeSLVerifierHint(Node* node) { UNREACHABLE(); } // JS comparison operators. diff --git a/deps/v8/src/compiler/turboshaft/graph-builder.cc b/deps/v8/src/compiler/turboshaft/graph-builder.cc index 4864bf773c51..5866bba154e0 100644 --- a/deps/v8/src/compiler/turboshaft/graph-builder.cc +++ b/deps/v8/src/compiler/turboshaft/graph-builder.cc @@ -1434,6 +1434,14 @@ OpIndex GraphBuilder::Process( return __ Load(Map(node->InputAt(0)), Map(node->InputAt(1)), LoadOp::Kind::Trapping(), loaded_rep); } +#if V8_ENABLE_SANDBOX + case IrOpcode::kLoadTrustedPointer: { + auto params = OpParameter(op); + return __ LoadTrustedPointer(Map(node->InputAt(0)), + LoadOp::Kind::TaggedBase(), params.tag, + params.offset + kHeapObjectTag); + } +#endif case IrOpcode::kStore: case IrOpcode::kUnalignedStore: { diff --git a/deps/v8/src/compiler/verifier.cc b/deps/v8/src/compiler/verifier.cc index a4787d8391b8..39d2dbced497 100644 --- a/deps/v8/src/compiler/verifier.cc +++ b/deps/v8/src/compiler/verifier.cc @@ -653,6 +653,11 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) { case IrOpcode::kExitMachineGraph: CheckValueInputIs(node, 0, Type::Machine()); break; +#if V8_ENABLE_SANDBOX + case IrOpcode::kLoadTrustedPointer: + // TODO(manoskouk): what are the constraints here? + break; +#endif // JavaScript operators // -------------------- diff --git a/deps/v8/src/compiler/wasm-graph-assembler.cc b/deps/v8/src/compiler/wasm-graph-assembler.cc index c5c4dd9160d2..f4e55a54a118 100644 --- a/deps/v8/src/compiler/wasm-graph-assembler.cc +++ b/deps/v8/src/compiler/wasm-graph-assembler.cc @@ -242,55 +242,6 @@ Node* WasmGraphAssembler::BuildDecodeSandboxedExternalPointer( #endif // V8_ENABLE_SANDBOX } -Node* WasmGraphAssembler::BuildDecodeTrustedPointer( - Node* handle, IndirectPointerTagRange tag_range) { -#if V8_ENABLE_SANDBOX - Node* index = Word32Shr(handle, Int32Constant(kTrustedPointerHandleShift)); - Node* offset = ChangeUint32ToUint64( - Word32Shl(index, Int32Constant(kTrustedPointerTableEntrySizeLog2))); - Node* table = Load(MachineType::Pointer(), LoadRootRegister(), - IsolateData::trusted_pointer_table_offset() + - Internals::kExternalEntityTableBasePointerOffset); - Node* decoded_ptr = Load(MachineType::Pointer(), table, offset); - - if (IsFastIndirectPointerTagRange(tag_range)) { - uint64_t mask = ComputeUntaggingMaskForFastIndirectPointerTag(tag_range); - decoded_ptr = WordAnd(decoded_ptr, IntPtrConstant(mask)); - } else { - Node* tag = - WordShr(decoded_ptr, IntPtrConstant(kTrustedPointerTableTagShift)); - - auto ok = MakeLabel(); - if (tag_range.Size() == 1) { - // The common and simple case: we expect exactly one tag. - Node* expected_tag = IntPtrConstant(tag_range.first); - GotoIf(WordEqual(tag, expected_tag), &ok, BranchHint::kTrue); - RuntimeAbort(AbortReason::kIndirectPointerTagMismatch); - Goto(&ok); // Unreachable, but needed for graph coherency. - } else { - // Range check. - Node* diff = IntPtrSub(tag, IntPtrConstant(tag_range.first)); - GotoIf(Uint64LessThanOrEqual( - diff, IntPtrConstant(tag_range.last - tag_range.first)), - &ok, BranchHint::kTrue); - RuntimeAbort(AbortReason::kIndirectPointerTagMismatch); - Goto(&ok); // Unreachable, but needed for graph coherency. - } - - Bind(&ok); - decoded_ptr = - WordAnd(decoded_ptr, IntPtrConstant(kTrustedPointerTablePayloadMask)); - } - - // We have to change the type of the result value to Tagged, so if the value - // gets spilled on the stack, it will get processed by the GC. - decoded_ptr = BitcastWordToTagged(decoded_ptr); - return decoded_ptr; -#else - UNREACHABLE(); -#endif // V8_ENABLE_SANDBOX -} - Node* WasmGraphAssembler::BuildLoadExternalPointerFromObject( Node* object, int field_offset, ExternalPointerTagRange tag_range, Node* isolate_root) { @@ -408,38 +359,14 @@ Node* WasmGraphAssembler::LoadByteArrayElement(Node* byte_array, return LoadFromObject(type, byte_array, offset); } -Node* WasmGraphAssembler::LoadImmutableTrustedPointerFromObject( - Node* object, int field_offset, IndirectPointerTagRange tag) { - Node* offset = IntPtrConstant(field_offset); -#ifdef V8_ENABLE_SANDBOX - Node* handle = LoadImmutableFromObject(MachineType::Uint32(), object, offset); - return BuildDecodeTrustedPointer(handle, tag); -#else - return LoadImmutableFromObject(MachineType::TaggedPointer(), object, offset); -#endif -} - Node* WasmGraphAssembler::LoadTrustedPointerFromObject( Node* object, int field_offset, IndirectPointerTagRange tag) { - Node* offset = IntPtrConstant(field_offset); #ifdef V8_ENABLE_SANDBOX - Node* handle = LoadFromObject(MachineType::Uint32(), object, offset); - return BuildDecodeTrustedPointer(handle, tag); + return AddNode(graph()->NewNode(common_.LoadTrustedPointer(field_offset, tag), + object, effect(), control())); #else - return LoadFromObject(MachineType::TaggedPointer(), object, offset); -#endif -} - -std::pair -WasmGraphAssembler::LoadTrustedPointerFromObjectTrapOnNull( - Node* object, int field_offset, IndirectPointerTagRange tag) { Node* offset = IntPtrConstant(field_offset); -#ifdef V8_ENABLE_SANDBOX - Node* handle = LoadTrapOnNull(MachineType::Uint32(), object, offset); - return {handle, BuildDecodeTrustedPointer(handle, tag)}; -#else - Node* value = LoadTrapOnNull(MachineType::TaggedPointer(), object, offset); - return {value, value}; + return LoadFromObject(MachineType::TaggedPointer(), object, offset); #endif } @@ -465,7 +392,7 @@ Node* WasmGraphAssembler::LoadContextNoCellFromJSFunction(Node* js_function) { Node* WasmGraphAssembler::LoadFunctionDataFromJSFunction(Node* js_function) { Node* shared = LoadSharedFunctionInfo(js_function); - return LoadImmutableTrustedPointerFromObject( + return LoadTrustedPointerFromObject( shared, offsetof(SharedFunctionInfo, trusted_function_data_) - kHeapObjectTag, kWasmExportedFunctionDataIndirectPointerTag); @@ -624,7 +551,7 @@ Node* WasmGraphAssembler::StringPrepareForGetCodeunit(Node* string) { Node* WasmGraphAssembler::LoadTrustedDataFromInstanceObject( Node* instance_object) { - return LoadImmutableTrustedPointerFromObject( + return LoadTrustedPointerFromObject( instance_object, offsetof(WasmInstanceObject, trusted_data_) - kHeapObjectTag, kWasmTrustedInstanceDataIndirectPointerTag); diff --git a/deps/v8/src/compiler/wasm-graph-assembler.h b/deps/v8/src/compiler/wasm-graph-assembler.h index f10e0205091c..0737d7999e7d 100644 --- a/deps/v8/src/compiler/wasm-graph-assembler.h +++ b/deps/v8/src/compiler/wasm-graph-assembler.h @@ -28,7 +28,8 @@ class WasmGraphAssembler : public GraphAssembler { public: WasmGraphAssembler(MachineGraph* mcgraph, Zone* zone) : GraphAssembler(mcgraph, zone, BranchSemantics::kMachine), - simplified_(zone) {} + simplified_(zone), + common_(zone) {} // While CallBuiltin() translates to a direct call to the address of the // builtin, CallBuiltinThroughJumptable instead jumps to a slot in a jump @@ -177,15 +178,8 @@ class WasmGraphAssembler : public GraphAssembler { ExternalPointerTagRange tag_range, Node* isolate_root); - Node* LoadImmutableTrustedPointerFromObject(Node* object, int offset, - IndirectPointerTagRange tag); Node* LoadTrustedPointerFromObject(Node* object, int offset, IndirectPointerTagRange tag); - // Returns the load node (where the source position for the trap needs to be - // set by the caller) and the result. - std::pair LoadTrustedPointerFromObjectTrapOnNull( - Node* object, int offset, IndirectPointerTagRange tag); - Node* BuildDecodeTrustedPointer(Node* handle, IndirectPointerTagRange tag); Node* IsSmi(Node* object); @@ -345,6 +339,7 @@ class WasmGraphAssembler : public GraphAssembler { } SimplifiedOperatorBuilder simplified_; + CommonOperatorBuilder common_; }; } // namespace compiler diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc index 7ae7d8f99d02..681dac659f1f 100644 --- a/deps/v8/src/ic/ic.cc +++ b/deps/v8/src/ic/ic.cc @@ -1760,17 +1760,6 @@ KeyedAccessLoadMode GetUpdatedLoadModeForMap(Isolate* isolate, Handle KeyedLoadIC::LoadElementHandler( DirectHandle receiver_map, KeyedAccessLoadMode new_load_mode, MaybeDirectHandle maybe_transition_target) { - // Has a getter interceptor, or is any has and has a query interceptor. - if (receiver_map->has_indexed_interceptor() && - (receiver_map->GetIndexedInterceptor()->has_getter() || - (IsAnyHas() && receiver_map->GetIndexedInterceptor()->has_query())) && - !receiver_map->GetIndexedInterceptor()->non_masking()) { - // TODO(jgruber): Update counter name. - TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedInterceptorStub); - return IsAnyHas() ? BUILTIN_CODE(isolate(), HasIndexedInterceptorIC) - : BUILTIN_CODE(isolate(), LoadIndexedInterceptorIC); - } - InstanceType instance_type = receiver_map->instance_type(); if (instance_type < FIRST_NONSTRING_TYPE) { TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedStringDH); @@ -1784,6 +1773,23 @@ Handle KeyedLoadIC::LoadElementHandler( if (instance_type == JS_PROXY_TYPE) { return LoadHandler::LoadProxy(isolate()); } + if (receiver_map->is_access_check_needed()) { + TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_SlowStub); + return LoadHandler::LoadSlow(isolate()); + } + + // Has a getter interceptor, or is any has and has a query interceptor. + if (receiver_map->has_indexed_interceptor() && + (receiver_map->GetIndexedInterceptor()->has_getter() || + (IsAnyHas() && receiver_map->GetIndexedInterceptor()->has_query())) && + !receiver_map->GetIndexedInterceptor()->non_masking()) { + DCHECK(!receiver_map->is_access_check_needed()); + // TODO(jgruber): Update counter name. + TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedInterceptorStub); + return IsAnyHas() ? BUILTIN_CODE(isolate(), HasIndexedInterceptorIC) + : BUILTIN_CODE(isolate(), LoadIndexedInterceptorIC); + } + #if V8_ENABLE_WEBASSEMBLY if (InstanceTypeChecker::IsWasmObject(instance_type)) { // TODO(jgruber): Update counter name. @@ -2870,7 +2876,8 @@ void KeyedStoreIC::UpdateStoreElement(Handle receiver_map, Handle KeyedStoreIC::StoreElementHandler( DirectHandle receiver_map, KeyedAccessStoreMode store_mode, MaybeDirectHandle> prev_validity_cell) { - if (!IsJSObjectMap(*receiver_map)) { + if (!IsJSObjectMap(*receiver_map) || receiver_map->is_access_check_needed() || + receiver_map->IsMapInArrayPrototypeChain(isolate())) { // DefineKeyedOwnIC, which is used to define computed fields in instances, // should handled by the slow stub below instead of the proxy stub. if (IsJSProxyMap(*receiver_map) && !IsDefineKeyedOwnIC()) { diff --git a/deps/v8/src/maglev/maglev-graph-builder.cc b/deps/v8/src/maglev/maglev-graph-builder.cc index b0bca8d41281..ca199bab0fab 100644 --- a/deps/v8/src/maglev/maglev-graph-builder.cc +++ b/deps/v8/src/maglev/maglev-graph-builder.cc @@ -9110,16 +9110,21 @@ MaglevGraphBuilder::BuildJSArrayBuiltinMapSwitchOnElementsKind( sub_graph.GotoOrTrim(&*object_case); sub_graph.Bind(&*object_case); } - any_successful |= (!build_kind_specific(kind).IsDoneWithAbort()); + ReduceResult result = build_kind_specific(kind); if (IsSmiElementsKind(kind) && make_smi_fallthrough_to_object) { // After building the SMI specific parts (see build_kind_specific call // above), jump to the beginning of the case for the object elements // kind. DCHECK(object_case.has_value()); sub_graph.GotoOrTrim(&*object_case); + + // Whether the Smi case is successful depends on whether the object case + // is successful, so don't update any_successful here. } else { DCHECK(do_return.has_value()); sub_graph.GotoOrTrim(&*do_return); + + any_successful |= !result.IsDoneWithAbort(); } sub_graph.Bind(&check_next_map); } else { @@ -16971,11 +16976,11 @@ void MaglevGraphBuilder::ProcessMergePointPredecessors( ResetBuilderCachedState(); if (merge_state.is_loop()) { - DCHECK_EQ(merge_state.predecessors_so_far(), - merge_state.predecessor_count() - 1); + CHECK_EQ(merge_state.predecessors_so_far(), + merge_state.predecessor_count() - 1); } else { - DCHECK_EQ(merge_state.predecessors_so_far(), - merge_state.predecessor_count()); + CHECK_EQ(merge_state.predecessors_so_far(), + merge_state.predecessor_count()); } if (merge_state.predecessor_count() == 1) { diff --git a/deps/v8/src/maglev/maglev-known-node-aspects.cc b/deps/v8/src/maglev/maglev-known-node-aspects.cc index f4abfca24955..63895d1f5f05 100644 --- a/deps/v8/src/maglev/maglev-known-node-aspects.cc +++ b/deps/v8/src/maglev/maglev-known-node-aspects.cc @@ -652,22 +652,22 @@ void KnownNodeAspects::ClearUnstableNodeAspectsForStoreMap( StoreMap* node, bool is_tracing_enabled) { if (!node->is_transitioning()) return; - if (NodeInfo* node_info = TryGetInfoFor(node->ValueInput().node())) { - if (node_info->possible_maps_are_known() && !node_info->maps_are_stale() && - node_info->possible_maps().size() == 1) { - compiler::MapRef old_map = node_info->possible_maps().at(0); - auto MaybeAliases = [&](compiler::MapRef map) -> bool { - return map.equals(old_map); - }; - // Mark aliasing maps as stale. - if (MarkMapsStaleIfAny(MaybeAliases)) { - if (V8_UNLIKELY(v8_flags.trace_maglev_kna && is_tracing_enabled)) { - std::cout << kRed << "[KNA] StoreMap: Invalidate alias " - << Brief(*old_map.object()) << kReset << std::endl; - } - } - return; - } + if (MarkSingleMapAsStale(node->ValueInput().node(), is_tracing_enabled)) { + return; + } + + // TODO(olivf): Only invalidate nodes with the same type. + OnSideEffect(); + if (V8_UNLIKELY(v8_flags.trace_maglev_kna && is_tracing_enabled)) { + std::cout << kRed << "[KNA] StoreMap: Invalidate all unstable maps" + << kReset << std::endl; + } +} + +void KnownNodeAspects::ClearUnstableNodeAspectsForMigration( + Node* node, bool is_tracing_enabled) { + if (MarkSingleMapAsStale(node->input_node(0), is_tracing_enabled)) { + return; } // TODO(olivf): Only invalidate nodes with the same type. @@ -1009,6 +1009,28 @@ KnownNodeAspects::ContextStoreResult KnownNodeAspects::RecordContextSlotStore( return {ContextStoreResult::kSetNewValue, std::move(aliased_slots)}; } +bool KnownNodeAspects::MarkSingleMapAsStale(ValueNode* node, + bool is_tracing_enabled) { + if (NodeInfo* node_info = TryGetInfoFor(node)) { + if (node_info->possible_maps_are_known() && !node_info->maps_are_stale() && + node_info->possible_maps().size() == 1) { + compiler::MapRef old_map = node_info->possible_maps().at(0); + auto MaybeAliases = [&](compiler::MapRef map) -> bool { + return map.equals(old_map); + }; + // Mark aliasing maps as stale. + if (MarkMapsStaleIfAny(MaybeAliases)) { + if (V8_UNLIKELY(v8_flags.trace_maglev_kna && is_tracing_enabled)) { + std::cout << kRed << "[KNA]: MarkSingleMapAsStale: Invalidate alias " + << Brief(*old_map.object()) << kReset << std::endl; + } + } + return true; + } + } + return false; +} + #ifdef DEBUG bool IsStringRootIndex(RootIndex index) { if (index > RootIndex::kLastReadOnlyRoot) return false; diff --git a/deps/v8/src/maglev/maglev-known-node-aspects.h b/deps/v8/src/maglev/maglev-known-node-aspects.h index b7f039113668..dd1ce8cc3858 100644 --- a/deps/v8/src/maglev/maglev-known-node-aspects.h +++ b/deps/v8/src/maglev/maglev-known-node-aspects.h @@ -407,6 +407,8 @@ class KnownNodeAspects { void ClearUnstableNodeAspectsForStoreMap(StoreMap* node, bool is_tracing_enabled); + void ClearUnstableNodeAspectsForMigration(Node* node, + bool is_tracing_enabled); void ClearUnstableNodeAspectsForElementsTransition( const ZoneVector& transition_sources, bool is_tracing_enabled); @@ -824,8 +826,7 @@ class KnownNodeAspects { std::is_same_v || std::is_same_v) { - // These instructions only migrate representations of values, not the - // values themselves, so cached values are still valid. + ClearUnstableNodeAspectsForMigration(node, is_tracing_enabled); } else if constexpr (std::is_same_v) { ClearUnstableNodeAspectsForStoreMap(node, is_tracing_enabled); } else if constexpr (std::is_same_v || @@ -910,6 +911,8 @@ class KnownNodeAspects { SmallZoneVector ClearAliasedContextSlotsFor( Graph* graph, ValueNode* context, int offset, ValueNode* value); + bool MarkSingleMapAsStale(ValueNode* node, bool is_tracing_enabled); + static constexpr uint32_t kEffectEpochForPureInstructions = std::numeric_limits::max(); static constexpr uint32_t kEffectEpochOverflow = diff --git a/deps/v8/src/maglev/maglev-phi-representation-selector.cc b/deps/v8/src/maglev/maglev-phi-representation-selector.cc index eff255ed43c5..5b44744d9e95 100644 --- a/deps/v8/src/maglev/maglev-phi-representation-selector.cc +++ b/deps/v8/src/maglev/maglev-phi-representation-selector.cc @@ -1074,7 +1074,7 @@ ValueNode* MaglevPhiRepresentationSelector::GetReplacementForPhiInputConversion( } ProcessResult MaglevPhiRepresentationSelector::UpdateUntaggingOfPhi( - Phi* phi, ValueNode* old_untagging) { + Phi* phi, ValueNode* old_untagging, const ProcessingState* state) { DCHECK_EQ(old_untagging->input_count(), 1); DCHECK(old_untagging->input(0).node()->Is()); @@ -1192,24 +1192,27 @@ ProcessResult MaglevPhiRepresentationSelector::UpdateUntaggingOfPhi( if (old_untagging->Is()) { conversion_is_truncating_float64 = true; } else if (old_untagging->Is()) { - if (from_repr == ValueRepresentation::kFloat64) { - // If {from_repr} is Float64, then the "CheckedNumber" part is - // guaranteed to pass and this operation just truncates its value to - // Int32. - conversion_is_truncating_float64 = true; - } else { - DCHECK_EQ(from_repr, ValueRepresentation::kHoleyFloat64); + if (from_repr == ValueRepresentation::kHoleyFloat64) { const auto* truncate = old_untagging->Cast(); // A HoleyFloat64 hole really means Undefined rather than the_hole: // whenever it gets rematerialized, it will always be rematerialized as - // Undefined. So, we can use a truncating conversion as long as the - // original assumed input type was allowing truncating Undefined. - // Assumptions without Undefined need to deopt for Hole/Undefined - // ==> not truncating. - conversion_is_truncating_float64 = !NodeTypeIs( - truncate->assumed_input_type(), NodeType::kNumberOrBoolean); + // Undefined. Assumptions without Undefined need to deopt on + // Hole/Undefined before truncating the Float64 value to Int32. + if (!NodeTypeCanBe(truncate->assumed_input_type(), + NodeType::kUndefined)) { + eager_deopt_frame_ = &old_untagging->eager_deopt_info()->top_frame(); + AddNewNodeNoInputConversion( + reducer_.current_block(), + BasicBlockPosition::At(state->node_index()), {phi}); +#ifdef DEBUG + eager_deopt_frame_ = nullptr; +#endif // DEBUG + } + } else { + DCHECK_EQ(from_repr, ValueRepresentation::kFloat64); } + conversion_is_truncating_float64 = true; } Opcode needed_conversion = GetOpcodeForConversion( diff --git a/deps/v8/src/maglev/maglev-phi-representation-selector.h b/deps/v8/src/maglev/maglev-phi-representation-selector.h index 5ecca6b95f2f..3007727a0999 100644 --- a/deps/v8/src/maglev/maglev-phi-representation-selector.h +++ b/deps/v8/src/maglev/maglev-phi-representation-selector.h @@ -206,7 +206,7 @@ class MaglevPhiRepresentationSelector { // removed altogether (or rather, replaced by an identity node). return UpdateUntaggingOfPhi( node->NodeBase::input(0).node()->template Cast(), - node->template Cast()); + node->template Cast(), state); } return ProcessResult::kContinue; } @@ -273,7 +273,8 @@ class MaglevPhiRepresentationSelector { // Updates {old_untagging} to reflect that its Phi input has been untagged and // that a different conversion is now needed. - ProcessResult UpdateUntaggingOfPhi(Phi* phi, ValueNode* old_untagging); + ProcessResult UpdateUntaggingOfPhi(Phi* phi, ValueNode* old_untagging, + const ProcessingState* state); ProcessResult EmitUnconditionalDeopt(NodeBase* node, DeoptimizeReason reason); diff --git a/deps/v8/src/maglev/maglev-range-analysis.h b/deps/v8/src/maglev/maglev-range-analysis.h index 51744959af0f..57d415f06ed1 100644 --- a/deps/v8/src/maglev/maglev-range-analysis.h +++ b/deps/v8/src/maglev/maglev-range-analysis.h @@ -67,6 +67,18 @@ class NodeRanges { return *range; } + void InitializeRangeIfMissing(BasicBlock* block, ValueNode* node, + Range range) { + DCHECK(ranges_initialized_.Contains(block->id())); + RangeMap& map = ranges_[block->id()]; + if (!map.find(node)) { + map = map.insert(zone(), node, range); + TRACE_RANGE("Initializing in Block b" << block->id() << ": " + << PrintNodeBrief(node) << ": " + << range); + } + } + void UnionUpdate(BasicBlock* block, ValueNode* node, Range range) { DCHECK(ranges_initialized_.Contains(block->id())); RangeMap& map = ranges_[block->id()]; @@ -210,6 +222,15 @@ class RangeProcessor { BlockProcessResult PreProcessBasicBlock(BasicBlock* block) { current_block_ = block; ranges_.EnsureMapExistsFor(block); + if (block->has_state() && block->state()->is_resumable_loop() && + block->predecessor_count() == 1) { + // Resumable loop headers might not have a live forward predecessor: that + // part of the code might be dead even though the loop is still reachable + // via a resume point. Make sure we initialize phis in such case. If the + // loop has a live predecessor, ProcessPhis is called when processing that + // live predecessor, and this code is a no-op. + InitializeLoopPhisIfMissing(block); + } return BlockProcessResult::kContinue; } BlockProcessResult PostProcessBasicBlock(BasicBlock* block) { @@ -543,6 +564,14 @@ class RangeProcessor { } } + void InitializeLoopPhisIfMissing(BasicBlock* block) { + if (!block->has_phi()) return; + for (Phi* phi : *block->phis()) { + ranges_.InitializeRangeIfMissing( + block, phi, phi->is_int32() ? Range::Int32() : Range::All()); + } + } + // Returns true if the loop reach a fixpoint. bool ProcessLoopPhisBackedge(BasicBlock* block, BasicBlock* backedge_pred) { if (!block->has_phi()) return true; diff --git a/deps/v8/src/objects/map-updater.cc b/deps/v8/src/objects/map-updater.cc index d62c94772f68..f1437356d69e 100644 --- a/deps/v8/src/objects/map-updater.cc +++ b/deps/v8/src/objects/map-updater.cc @@ -385,8 +385,9 @@ std::optional> MapUpdater::TryUpdateNoLock(Isolate* isolate, } if (root_map->prototype() != old_map->prototype()) { - auto maybe_transition = TransitionsAccessor::GetPrototypeTransition( - isolate, root_map, old_map->prototype()); + auto maybe_transition = + TransitionsAccessor(isolate, root_map, IsConcurrent(cmode)) + .GetPrototypeTransition(old_map->prototype()); if (!maybe_transition) { return {}; } diff --git a/deps/v8/src/objects/shared-function-info-inl.h b/deps/v8/src/objects/shared-function-info-inl.h index 93de8a242af5..c4504c0f58b5 100644 --- a/deps/v8/src/objects/shared-function-info-inl.h +++ b/deps/v8/src/objects/shared-function-info-inl.h @@ -511,6 +511,9 @@ BIT_FIELD_ACCESSORS(SharedFunctionInfo, relaxed_flags, SharedFunctionInfo::PrivateNameLookupSkipsOuterClassBit) BIT_FIELD_ACCESSORS(SharedFunctionInfo, relaxed_flags, is_hoisted_in_context, SharedFunctionInfo::IsHoistedInContextBit) +BIT_FIELD_ACCESSORS(SharedFunctionInfo, relaxed_flags, + class_initializer_allows_await, + SharedFunctionInfo::ClassInitializerAllowsAwaitBit) bool SharedFunctionInfo::optimization_disabled(CodeKind kind) const { switch (kind) { diff --git a/deps/v8/src/objects/shared-function-info.cc b/deps/v8/src/objects/shared-function-info.cc index 5151351c3ac4..0f4078ec21bc 100644 --- a/deps/v8/src/objects/shared-function-info.cc +++ b/deps/v8/src/objects/shared-function-info.cc @@ -600,6 +600,10 @@ void SharedFunctionInfo::InitFromFunctionLiteral(IsolateT* isolate, lit->has_static_private_methods_or_accessors()); raw_sfi->set_is_hoisted_in_context(lit->scope()->is_hoisted_in_context()); + DCHECK_IMPLIES(lit->scope()->class_initializer_allows_await(), + IsClassInitializerFunction(lit->kind())); + raw_sfi->set_class_initializer_allows_await( + lit->scope()->class_initializer_allows_await()); raw_sfi->set_is_toplevel(is_toplevel); DCHECK(IsTheHole(raw_sfi->outer_scope_info())); diff --git a/deps/v8/src/objects/shared-function-info.h b/deps/v8/src/objects/shared-function-info.h index d5f8a8fc2a94..dd0e0bcb5a45 100644 --- a/deps/v8/src/objects/shared-function-info.h +++ b/deps/v8/src/objects/shared-function-info.h @@ -289,6 +289,7 @@ V8_OBJECT class SharedFunctionInfo : public HeapObject { PropertiesAreFinalBit::Next; using IsHoistedInContextBit = PrivateNameLookupSkipsOuterClassBit::Next; + using ClassInitializerAllowsAwaitBit = IsHoistedInContextBit::Next; // Bit positions in |flags2|. using ClassScopeHasPrivateBrandBit = base::BitField; using HasStaticPrivateMethodsOrAccessorsBit = @@ -708,6 +709,9 @@ V8_OBJECT class SharedFunctionInfo : public HeapObject { // Indicates that the function is a hoisted-in-context declaration. DECL_BOOLEAN_ACCESSORS(is_hoisted_in_context) + // Indicates that a class initializer's enclosing scope allowed await. + DECL_BOOLEAN_ACCESSORS(class_initializer_allows_await) + inline FunctionKind kind() const; int UniqueIdInScript() const; diff --git a/deps/v8/src/objects/shared-function-info.tq b/deps/v8/src/objects/shared-function-info.tq index f4949b0bc77a..b46945f2c385 100644 --- a/deps/v8/src/objects/shared-function-info.tq +++ b/deps/v8/src/objects/shared-function-info.tq @@ -42,6 +42,7 @@ bitfield struct SharedFunctionInfoFlags extends uint32 { properties_are_final: bool: 1 bit; private_name_lookup_skips_outer_class: bool: 1 bit; is_hoisted_in_context: bool: 1 bit; + class_initializer_allows_await: bool: 1 bit; } @cppScope('SharedFunctionInfo') diff --git a/deps/v8/src/objects/transitions-inl.h b/deps/v8/src/objects/transitions-inl.h index af509675f54d..b694790a4cde 100644 --- a/deps/v8/src/objects/transitions-inl.h +++ b/deps/v8/src/objects/transitions-inl.h @@ -400,6 +400,14 @@ MaybeHandle TransitionsAccessor::SearchSpecial(Isolate* isolate, return MaybeHandle(result, isolate); } +// static +std::optional> TransitionsAccessor::GetPrototypeTransition( + Isolate* isolate, Tagged map, Tagged prototype) { + // This helper is supposed to be used only from the main thread. + DCHECK_EQ(ThreadId::Current(), isolate->thread_id()); + return TransitionsAccessor(isolate, map).GetPrototypeTransition(prototype); +} + // TODO(375937549): Convert to uint32_t. int TransitionArray::number_of_transitions() const { if (ulength().value() < kFirstIndex) return 0; diff --git a/deps/v8/src/objects/transitions.cc b/deps/v8/src/objects/transitions.cc index 907e8e695b58..0c0ac419f30d 100644 --- a/deps/v8/src/objects/transitions.cc +++ b/deps/v8/src/objects/transitions.cc @@ -435,8 +435,8 @@ bool TransitionsAccessor::PutPrototypeTransition(Isolate* isolate, const uint32_t header = TransitionArray::kProtoTransitionHeaderSize; - DirectHandle cache(GetPrototypeTransitions(isolate, *map), - isolate); + DirectHandle cache( + TransitionsAccessor(isolate, *map).GetPrototypeTransitions(), isolate); const uint32_t cache_len = cache->ulength().value(); const uint32_t capacity = cache_len >= header ? cache_len - header : 0; const uint32_t transitions = @@ -477,11 +477,13 @@ bool TransitionsAccessor::PutPrototypeTransition(Isolate* isolate, return true; } -// static std::optional> TransitionsAccessor::GetPrototypeTransition( - Isolate* isolate, Tagged map, Tagged prototype) { + Tagged prototype) { DisallowGarbageCollection no_gc; - Tagged cache = GetPrototypeTransitions(isolate, map); + if (encoding() != kFullTransitionArray) return {}; + base::MutexGuardIf guard(isolate_->full_transition_array_access(), + concurrent_access_); + Tagged cache = GetPrototypeTransitions(); const uint32_t length = TransitionArray::NumberOfPrototypeTransitions(cache); for (uint32_t i = 0; i < length; i++) { Tagged target = @@ -498,19 +500,11 @@ std::optional> TransitionsAccessor::GetPrototypeTransition( return {}; } -// static -Tagged TransitionsAccessor::GetPrototypeTransitions( - Isolate* isolate, Tagged map) { - Tagged raw_transitions = map->raw_transitions(kAcquireLoad); - if (GetEncoding(isolate, raw_transitions) != kFullTransitionArray) { - return ReadOnlyRoots(isolate).empty_weak_fixed_array(); - } - Tagged transition_array = - GetTransitionArray(isolate, raw_transitions); - if (!transition_array->HasPrototypeTransitions()) { - return ReadOnlyRoots(isolate).empty_weak_fixed_array(); +Tagged TransitionsAccessor::GetPrototypeTransitions() { + if (!HasPrototypeTransitions()) { + return ReadOnlyRoots(isolate_).empty_weak_fixed_array(); } - return transition_array->GetPrototypeTransitions(); + return transitions()->GetPrototypeTransitions(); } // static diff --git a/deps/v8/src/objects/transitions.h b/deps/v8/src/objects/transitions.h index 408bcaf0f4eb..d7e948ef9581 100644 --- a/deps/v8/src/objects/transitions.h +++ b/deps/v8/src/objects/transitions.h @@ -185,8 +185,13 @@ class V8_EXPORT_PRIVATE TransitionsAccessor { static bool PutPrototypeTransition(Isolate* isolate, DirectHandle, DirectHandle prototype, DirectHandle target_map); - static std::optional> GetPrototypeTransition( + + std::optional> GetPrototypeTransition(Tagged prototype); + // Convenient helper for calling from the main thread, for other cases + // use the instance method above. + static inline std::optional> GetPrototypeTransition( Isolate* isolate, Tagged map, Tagged prototype); + bool HasPrototypeTransitions(); // During the first-time Map::Update and Map::TryUpdate, the migration target @@ -267,8 +272,7 @@ class V8_EXPORT_PRIVATE TransitionsAccessor { static void SetPrototypeTransitions( Isolate* isolate, DirectHandle map, DirectHandle proto_transitions); - static Tagged GetPrototypeTransitions(Isolate* isolate, - Tagged map); + Tagged GetPrototypeTransitions(); static void InsertHelper(Isolate* isolate, DirectHandle map, DirectHandle name, DirectHandle target, diff --git a/deps/v8/src/parsing/parse-info.cc b/deps/v8/src/parsing/parse-info.cc index f33708abdf84..aa1647ec7f47 100644 --- a/deps/v8/src/parsing/parse-info.cc +++ b/deps/v8/src/parsing/parse-info.cc @@ -55,6 +55,8 @@ UnoptimizedCompileFlags UnoptimizedCompileFlags::ForFunctionCompile( flags.set_is_lazy_compile(true); flags.set_is_repl_mode(script->is_repl_mode()); + flags.set_class_initializer_allows_await( + shared->class_initializer_allows_await()); // Do not support re-parsing top-level function of a wrapped script. DCHECK_IMPLIES(flags.is_toplevel(), !script->is_wrapped()); diff --git a/deps/v8/src/parsing/parse-info.h b/deps/v8/src/parsing/parse-info.h index ef6f4f577ee5..d62979f3f628 100644 --- a/deps/v8/src/parsing/parse-info.h +++ b/deps/v8/src/parsing/parse-info.h @@ -66,6 +66,7 @@ class Zone; V(compile_hints_magic_enabled, bool, 1, _) \ V(compile_hints_per_function_magic_enabled, bool, 1, _) \ V(is_hoisted_in_context, bool, 1, _) \ + V(class_initializer_allows_await, bool, 1, _) \ V(allow_heap_allocation, bool, 1, _) class V8_EXPORT_PRIVATE UnoptimizedCompileFlags { diff --git a/deps/v8/src/parsing/parser-base.h b/deps/v8/src/parsing/parser-base.h index 5b552c583792..1df1fa026f5b 100644 --- a/deps/v8/src/parsing/parser-base.h +++ b/deps/v8/src/parsing/parser-base.h @@ -450,7 +450,11 @@ class ParserBase { class FunctionState final : public BlockState { public: FunctionState(FunctionState** function_state_stack, Scope** scope_stack, - DeclarationScope* scope); + DeclarationScope* scope) + : FunctionState(function_state_stack, scope_stack, scope, + scope->function_kind()) {} + FunctionState(FunctionState** function_state_stack, Scope** scope_stack, + DeclarationScope* scope, FunctionKind kind); ~FunctionState(); DeclarationScope* scope() const { return scope_->AsDeclarationScope(); } @@ -467,7 +471,7 @@ class ParserBase { int suspend_count() const { return suspend_count_; } bool CanSuspend() const { return suspend_count_ > 0; } - FunctionKind kind() const { return scope()->function_kind(); } + FunctionKind kind() const { return kind_; } bool next_function_is_likely_called() const { return next_function_is_likely_called_; @@ -534,6 +538,7 @@ class ParserBase { FunctionState** function_state_stack_; FunctionState* outer_function_state_; DeclarationScope* scope_; + FunctionKind kind_; Target* target_stack_ = nullptr; // for break, continue statements // A reason, if any, why this function should not be optimized. @@ -639,6 +644,8 @@ class ParserBase { static_elements_scope = parser->NewFunctionScope(kind); static_elements_scope->SetLanguageMode(LanguageMode::kStrict); static_elements_scope->set_start_position(beg_pos); + static_elements_scope->set_class_initializer_allows_await( + parser->is_await_allowed()); static_elements_function_id = info_id; // Actually consume the id. The id that was passed in might be an // earlier id in case of computed property names. @@ -657,6 +664,8 @@ class ParserBase { instance_members_scope = parser->NewFunctionScope(kind); instance_members_scope->SetLanguageMode(LanguageMode::kStrict); instance_members_scope->set_start_position(beg_pos); + instance_members_scope->set_class_initializer_allows_await( + parser->is_await_allowed()); instance_members_function_id = info_id; // Actually consume the id. The id that was passed in might be an // earlier id in case of computed property names. @@ -1833,13 +1842,14 @@ class ParserBase { template ParserBase::FunctionState::FunctionState( FunctionState** function_state_stack, Scope** scope_stack, - DeclarationScope* scope) + DeclarationScope* scope, FunctionKind kind) : BlockState(scope_stack, scope), expected_property_count_(0), suspend_count_(0), function_state_stack_(function_state_stack), outer_function_state_(*function_state_stack), scope_(scope), + kind_(kind), dont_optimize_reason_(BailoutReason::kNoReason), next_function_is_likely_called_(false), previous_function_was_likely_called_(false), diff --git a/deps/v8/src/parsing/parser.cc b/deps/v8/src/parsing/parser.cc index 94f19994ccf1..388e4f1c96e7 100644 --- a/deps/v8/src/parsing/parser.cc +++ b/deps/v8/src/parsing/parser.cc @@ -1274,10 +1274,19 @@ FunctionLiteral* Parser::ParseClassForMemberInitialization( // this point the scanner should be rewound to the position of the class // token. DCHECK_EQ(peek_position(), initializer_pos); - // Insert a FunctionState with the closest outer Declaration scope + // Insert a FunctionState with the closest outer Declaration scope. + // The immediate enclosing function scope may have been elided from the + // ScopeInfo chain if it did not allocate a context. Since class bodies are + // always strict mode, 'yield' is never a valid identifier in computed + // property names, so we can unconditionally enable generator mode; whether + // 'await' is a keyword is recorded on the initializer SharedFunctionInfo. DeclarationScope* nearest_decl_scope = original_scope_->GetDeclarationScope(); DCHECK_NOT_NULL(nearest_decl_scope); - FunctionState function_state(&function_state_, &scope_, nearest_decl_scope); + FunctionKind enclosing_kind = flags().class_initializer_allows_await() + ? FunctionKind::kAsyncGeneratorFunction + : FunctionKind::kGeneratorFunction; + FunctionState function_state(&function_state_, &scope_, nearest_decl_scope, + enclosing_kind); // We preparse the class members that are not fields with initializers // in order to collect the function literal ids. diff --git a/deps/v8/src/snapshot/code-serializer.cc b/deps/v8/src/snapshot/code-serializer.cc index 034ef5f52ead..78ba29eeca3e 100644 --- a/deps/v8/src/snapshot/code-serializer.cc +++ b/deps/v8/src/snapshot/code-serializer.cc @@ -345,8 +345,8 @@ class StressOffThreadDeserializeThread final : public base::Thread { LocalIsolate local_isolate(isolate_, ThreadKind::kBackground); UnparkedScope unparked_scope(&local_isolate); LocalHandleScope handle_scope(&local_isolate); - off_thread_data_ = - CodeSerializer::StartDeserializeOffThread(&local_isolate, cached_data_); + CodeSerializer::StartDeserializeOffThread(&local_isolate, cached_data_, + &off_thread_data_); } MaybeDirectHandle Finalize( @@ -360,7 +360,7 @@ class StressOffThreadDeserializeThread final : public base::Thread { private: Isolate* isolate_; AlignedCachedData* cached_data_; - CodeSerializer::OffThreadDeserializeData off_thread_data_; + OffThreadDeserializeData off_thread_data_; }; void FinalizeDeserialization(Isolate* isolate, @@ -554,8 +554,7 @@ MaybeDirectHandle CodeSerializer::Deserialize( return scope.CloseAndEscape(result); } -DirectHandle