diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index d47b8f7f5c8b..0776c052108f 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 19 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) 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/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/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