From b872eaecd42bab510e408bd1086f9e8d011e632a Mon Sep 17 00:00:00 2001 From: inoway46 Date: Thu, 17 Sep 2026 12:14:46 +0900 Subject: [PATCH 1/2] deps: cherry-pick 8901c793e439 from V8 upstream Adapt deleted Context accesses and surrounding broker APIs to V8 13.6. Original commit message: [compiler] Stop collecting array and object prototypes We can check in O(1) whether an object is either Object.prototype or Array.prototype by directly comparing it with the objects, so there's no need to collect them. Change-Id: Iadedf8b05cae3d67191fb4836c186620dc009118 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/6487694 Commit-Queue: Toon Verwaest Reviewed-by: Igor Sheludko Commit-Queue: Igor Sheludko Auto-Submit: Toon Verwaest Cr-Commit-Position: refs/heads/main@{#99894} Refs: https://github.com/v8/v8/commit/8901c793e4392dfea261bcbf9c679e2978847d4d Refs: https://github.com/nodejs/node/issues/66053 Assisted-by: Codex Signed-off-by: inoway46 --- common.gypi | 2 +- deps/v8/src/compiler/heap-refs.cc | 2 -- deps/v8/src/compiler/js-heap-broker.cc | 34 +++----------------------- deps/v8/src/compiler/js-heap-broker.h | 16 ++++-------- 4 files changed, 9 insertions(+), 45 deletions(-) diff --git a/common.gypi b/common.gypi index 1effebe59bd4..59eb8582cb69 100644 --- a/common.gypi +++ b/common.gypi @@ -42,7 +42,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.53', + 'v8_embedder_string': '-node.54', ##### V8 defaults for Node.js ##### diff --git a/deps/v8/src/compiler/heap-refs.cc b/deps/v8/src/compiler/heap-refs.cc index 7a470132d7fc..5d4ef93a0168 100644 --- a/deps/v8/src/compiler/heap-refs.cc +++ b/deps/v8/src/compiler/heap-refs.cc @@ -1039,8 +1039,6 @@ void JSHeapBroker::InitializeAndStartSerializing( refs_ = zone()->New(kInitialRefsBucketCount, AddressMatcher(), zone()); - CollectArrayAndObjectPrototypes(); - SetTargetNativeContextRef(target_native_context); } diff --git a/deps/v8/src/compiler/js-heap-broker.cc b/deps/v8/src/compiler/js-heap-broker.cc index 3a7949ce8e43..f766e1273a03 100644 --- a/deps/v8/src/compiler/js-heap-broker.cc +++ b/deps/v8/src/compiler/js-heap-broker.cc @@ -47,7 +47,6 @@ JSHeapBroker::JSHeapBroker(Isolate* isolate, Zone* broker_zone, refs_(zone()->New(kMinimalRefsBucketCount, AddressMatcher(), zone())), root_index_map_(isolate), - array_and_object_prototypes_(zone()), tracing_enabled_(tracing_enabled), code_kind_(code_kind), feedback_(zone()), @@ -118,28 +117,6 @@ void JSHeapBroker::SetTargetNativeContextRef( target_native_context_ = MakeRef(this, *native_context); } -void JSHeapBroker::CollectArrayAndObjectPrototypes() { - DisallowGarbageCollection no_gc; - CHECK_EQ(mode(), kSerializing); - CHECK(array_and_object_prototypes_.empty()); - - Tagged maybe_context = isolate()->heap()->native_contexts_list(); - while (!IsUndefined(maybe_context, isolate())) { - Tagged context = Cast(maybe_context); - Tagged array_prot = - context->get(Context::INITIAL_ARRAY_PROTOTYPE_INDEX); - Tagged object_prot = - context->get(Context::INITIAL_OBJECT_PROTOTYPE_INDEX); - array_and_object_prototypes_.emplace( - CanonicalPersistentHandle(Cast(array_prot))); - array_and_object_prototypes_.emplace( - CanonicalPersistentHandle(Cast(object_prot))); - maybe_context = context->next_context_link(); - } - - CHECK(!array_and_object_prototypes_.empty()); -} - StringRef JSHeapBroker::GetTypedArrayStringTag(ElementsKind kind) { DCHECK(IsTypedArrayOrRabGsabTypedArrayElementsKind(kind)); switch (kind) { @@ -159,14 +136,9 @@ bool JSHeapBroker::IsArrayOrObjectPrototype(JSObjectRef object) const { } bool JSHeapBroker::IsArrayOrObjectPrototype(Handle object) const { - if (mode() == kDisabled) { - return isolate()->IsInCreationContext( - *object, Context::INITIAL_ARRAY_PROTOTYPE_INDEX) || - object->map(isolate_)->instance_type() == JS_OBJECT_PROTOTYPE_TYPE; - } - CHECK(!array_and_object_prototypes_.empty()); - return array_and_object_prototypes_.find(object) != - array_and_object_prototypes_.end(); + return isolate()->IsInCreationContext( + *object, Context::INITIAL_ARRAY_PROTOTYPE_INDEX) || + object->map(isolate_)->instance_type() == JS_OBJECT_PROTOTYPE_TYPE; } ObjectData* JSHeapBroker::TryGetOrCreateData(Tagged object, diff --git a/deps/v8/src/compiler/js-heap-broker.h b/deps/v8/src/compiler/js-heap-broker.h index 52677f517f5e..aaee5131b23c 100644 --- a/deps/v8/src/compiler/js-heap-broker.h +++ b/deps/v8/src/compiler/js-heap-broker.h @@ -285,12 +285,11 @@ class V8_EXPORT_PRIVATE JSHeapBroker { if (Tagged heap_object; TryCast(object, &heap_object)) { RootIndex root_index; - // CollectArrayAndObjectPrototypes calls this function often with T equal - // to JSObject. The root index map only contains immortal, immutable - // objects; it never contains any instances of type JSObject, since - // JSObjects must exist within a NativeContext, and NativeContexts can be - // created and destroyed. Thus, we can skip the lookup in the root index - // map for those values and save a little time. + // The root index map only contains immortal, immutable objects; it never + // contains any instances of type JSObject, since JSObjects must exist + // within a NativeContext, and NativeContexts can be created and + // destroyed. Thus, we can skip the lookup in the root index map for those + // values and save a little time. if constexpr (std::is_convertible_v) { DCHECK(!root_index_map_.Lookup(heap_object, &root_index)); } else if (root_index_map_.Lookup(heap_object, &root_index)) { @@ -428,8 +427,6 @@ class V8_EXPORT_PRIVATE JSHeapBroker { ProcessedFeedback const& ReadFeedbackForTemplateObject( FeedbackSource const& source); - void CollectArrayAndObjectPrototypes(); - void set_persistent_handles( std::unique_ptr persistent_handles) { DCHECK_NULL(ph_); @@ -457,9 +454,6 @@ class V8_EXPORT_PRIVATE JSHeapBroker { OptionalNativeContextRef target_native_context_; RefsMap* refs_; RootIndexMap root_index_map_; - ZoneUnorderedSet, IndirectHandle::hash, - IndirectHandle::equal_to> - array_and_object_prototypes_; BrokerMode mode_ = kDisabled; bool const tracing_enabled_; CodeKind const code_kind_; From 39c046602c7f62c58254dd5e27f36201c669f0a5 Mon Sep 17 00:00:00 2001 From: inoway46 Date: Thu, 17 Sep 2026 23:06:18 +0900 Subject: [PATCH 2/2] deps: cherry-pick c3553509f460 from V8 upstream Use the V8 13.6 ReadOnlyRoots API and add the missing bimodal MapRef::is_extensible accessor. Adapt surrounding broker APIs and the removed descriptor load to the v24 implementation. Original commit message: [compiler] Thread-safe IsArrayOrObjectPrototype Bug: 467311868 Change-Id: I574aa62d859030545e6a52d693a61e570381e557 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7460949 Reviewed-by: Leszek Swirski Commit-Queue: Jakob Linke Cr-Commit-Position: refs/heads/main@{#104707} Refs: https://github.com/v8/v8/commit/c3553509f460b104cb8d4faf610d229a2d033f7b Refs: https://github.com/nodejs/node/issues/66053 Assisted-by: Codex Signed-off-by: inoway46 --- common.gypi | 2 +- deps/v8/src/compiler/heap-refs.cc | 54 ++++++++++++------- deps/v8/src/compiler/heap-refs.h | 6 +++ deps/v8/src/compiler/js-heap-broker.cc | 10 ---- deps/v8/src/compiler/js-heap-broker.h | 5 -- .../js-native-context-specialization.cc | 2 +- deps/v8/src/compiler/node-properties.cc | 2 +- deps/v8/src/maglev/maglev-graph-builder.cc | 2 +- 8 files changed, 46 insertions(+), 37 deletions(-) diff --git a/common.gypi b/common.gypi index 59eb8582cb69..46ae0a4d4b93 100644 --- a/common.gypi +++ b/common.gypi @@ -42,7 +42,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.54', + 'v8_embedder_string': '-node.55', ##### V8 defaults for Node.js ##### diff --git a/deps/v8/src/compiler/heap-refs.cc b/deps/v8/src/compiler/heap-refs.cc index 5d4ef93a0168..1d379a2fc6e1 100644 --- a/deps/v8/src/compiler/heap-refs.cc +++ b/deps/v8/src/compiler/heap-refs.cc @@ -839,34 +839,33 @@ InstanceType HeapObjectData::GetMapInstanceType() const { namespace { -bool IsReadOnlyLengthDescriptor(Isolate* isolate, - DirectHandle jsarray_map) { - DCHECK(!jsarray_map->is_dictionary_map()); - Tagged descriptors = - jsarray_map->instance_descriptors(isolate, kRelaxedLoad); +bool IsReadOnlyLengthDescriptor(JSHeapBroker* broker, MapRef jsarray_map) { + DCHECK(!jsarray_map.is_dictionary_map()); + DescriptorArrayRef descriptors = jsarray_map.instance_descriptors(broker); static_assert( JSArray::kLengthOffset == JSObject::kHeaderSize, "The length should be the first property on the descriptor array"); InternalIndex offset(0); - return descriptors->GetDetails(offset).IsReadOnly(); + return descriptors.GetPropertyDetails(offset).IsReadOnly(); } // Important: this predicate does not check Protectors::IsNoElementsIntact. The // compiler checks protectors through the compilation dependency mechanism; it // doesn't make sense to do that here as part of every MapData construction. // Callers *must* take care to take the correct dependency themselves. -bool SupportsFastArrayIteration(JSHeapBroker* broker, DirectHandle map) { - return map->instance_type() == JS_ARRAY_TYPE && - IsFastElementsKind(map->elements_kind()) && - IsJSArray(map->prototype()) && - broker->IsArrayOrObjectPrototype(broker->CanonicalPersistentHandle( - Cast(map->prototype()))); +bool SupportsFastArrayIteration(JSHeapBroker* broker, MapRef map) { + if (map.instance_type() != JS_ARRAY_TYPE || + !IsFastElementsKind(map.elements_kind())) { + return false; + } + HeapObjectRef prototype = map.prototype(broker); + return prototype.IsJSArray() && + prototype.AsJSArray().IsArrayOrObjectPrototype(broker); } -bool SupportsFastArrayResize(JSHeapBroker* broker, DirectHandle map) { - return SupportsFastArrayIteration(broker, map) && map->is_extensible() && - !map->is_dictionary_map() && - !IsReadOnlyLengthDescriptor(broker->isolate(), map); +bool SupportsFastArrayResize(JSHeapBroker* broker, MapRef map) { + return SupportsFastArrayIteration(broker, map) && map.is_extensible() && + !map.is_dictionary_map() && !IsReadOnlyLengthDescriptor(broker, map); } } // namespace @@ -1248,11 +1247,11 @@ bool MapRef::PrototypesElementsDoNotHaveAccessorsOrThrow( } bool MapRef::supports_fast_array_iteration(JSHeapBroker* broker) const { - return SupportsFastArrayIteration(broker, object()); + return SupportsFastArrayIteration(broker, *this); } bool MapRef::supports_fast_array_resize(JSHeapBroker* broker) const { - return SupportsFastArrayResize(broker, object()); + return SupportsFastArrayResize(broker, *this); } namespace { @@ -1624,6 +1623,7 @@ HEAP_ACCESSOR_B(Map, bit_field3, NumberOfOwnDescriptors, Map::Bits3::NumberOfOwnDescriptorsBits) HEAP_ACCESSOR_B(Map, bit_field3, is_migration_target, Map::Bits3::IsMigrationTargetBit) +BIMODAL_ACCESSOR_B(Map, bit_field3, is_extensible, Map::Bits3::IsExtensibleBit) BIMODAL_ACCESSOR_B(Map, bit_field3, construction_counter, Map::Bits3::ConstructionCounterBits) HEAP_ACCESSOR_B(Map, bit_field, has_prototype_slot, @@ -1805,6 +1805,11 @@ ObjectRef MapRef::GetConstructor(JSHeapBroker* broker) const { return MakeRefAssumeMemoryFence(broker, object()->GetConstructor()); } +NativeContextRef MapRef::native_context(JSHeapBroker* broker) const { + // Immutable after initialization. + return MakeRefAssumeMemoryFence(broker, object()->native_context()); +} + HeapObjectRef MapRef::GetBackPointer(JSHeapBroker* broker) const { // Immutable after initialization. return MakeRefAssumeMemoryFence(broker, @@ -2459,6 +2464,19 @@ OptionalMapRef JSObjectRef::GetObjectCreateMap(JSHeapBroker* broker) const { maybe_object_create_map.GetHeapObjectAssumeWeak(), kAssumeMemoryFence)); } +bool JSObjectRef::IsArrayOrObjectPrototype(JSHeapBroker* broker) const { + MapRef map = this->map(broker); + if (map.instance_type() == JS_OBJECT_PROTOTYPE_TYPE) return true; + // Keep in sync with Isolate::IsInCreationContext: + MapRef metamap = map.map(broker); + // Filter out native-context independent objects. + if (*metamap.object() == ReadOnlyRoots(broker->isolate()).meta_map()) + return false; + OptionalNativeContextRef native_context = metamap.native_context(broker); + if (!native_context.has_value()) return false; + return native_context->initial_array_prototype(broker).equals(*this); +} + bool PropertyCellRef::Cache(JSHeapBroker* broker) const { if (data_->should_access_heap()) return true; CHECK(broker->mode() == JSHeapBroker::kSerializing || diff --git a/deps/v8/src/compiler/heap-refs.h b/deps/v8/src/compiler/heap-refs.h index cdf57451546e..04917b153df6 100644 --- a/deps/v8/src/compiler/heap-refs.h +++ b/deps/v8/src/compiler/heap-refs.h @@ -623,6 +623,10 @@ class JSObjectRef : public JSReceiverRef { bool IsElementsTenured(FixedArrayBaseRef elements); OptionalMapRef GetObjectCreateMap(JSHeapBroker* broker) const; + + // Check if this object is its creation context's %ArrayPrototype% or + // %ObjectPrototype%. + bool IsArrayOrObjectPrototype(JSHeapBroker* broker) const; }; class JSDataViewRef : public JSObjectRef { @@ -899,6 +903,7 @@ class V8_EXPORT_PRIVATE MapRef : public HeapObjectRef { bool has_indexed_interceptor() const; int construction_counter() const; bool is_migration_target() const; + bool is_extensible() const; bool supports_fast_array_iteration(JSHeapBroker* broker) const; bool supports_fast_array_resize(JSHeapBroker* broker) const; bool is_abandoned_prototype_map() const; @@ -940,6 +945,7 @@ class V8_EXPORT_PRIVATE MapRef : public HeapObjectRef { MapRef FindRootMap(JSHeapBroker* broker) const; ObjectRef GetConstructor(JSHeapBroker* broker) const; + NativeContextRef native_context(JSHeapBroker* broker) const; }; struct HolderLookupResult { diff --git a/deps/v8/src/compiler/js-heap-broker.cc b/deps/v8/src/compiler/js-heap-broker.cc index f766e1273a03..2fddcf1c06c4 100644 --- a/deps/v8/src/compiler/js-heap-broker.cc +++ b/deps/v8/src/compiler/js-heap-broker.cc @@ -131,16 +131,6 @@ StringRef JSHeapBroker::GetTypedArrayStringTag(ElementsKind kind) { } } -bool JSHeapBroker::IsArrayOrObjectPrototype(JSObjectRef object) const { - return IsArrayOrObjectPrototype(object.object()); -} - -bool JSHeapBroker::IsArrayOrObjectPrototype(Handle object) const { - return isolate()->IsInCreationContext( - *object, Context::INITIAL_ARRAY_PROTOTYPE_INDEX) || - object->map(isolate_)->instance_type() == JS_OBJECT_PROTOTYPE_TYPE; -} - ObjectData* JSHeapBroker::TryGetOrCreateData(Tagged object, GetOrCreateDataFlags flags) { return TryGetOrCreateData(CanonicalPersistentHandle(object), flags); diff --git a/deps/v8/src/compiler/js-heap-broker.h b/deps/v8/src/compiler/js-heap-broker.h index aaee5131b23c..6dcc7cb8675e 100644 --- a/deps/v8/src/compiler/js-heap-broker.h +++ b/deps/v8/src/compiler/js-heap-broker.h @@ -192,11 +192,6 @@ class V8_EXPORT_PRIVATE JSHeapBroker { ObjectData* TryGetOrCreateData(Tagged object, GetOrCreateDataFlags flags = {}); - // Check if {object} is any native context's %ArrayPrototype% or - // %ObjectPrototype%. - bool IsArrayOrObjectPrototype(JSObjectRef object) const; - bool IsArrayOrObjectPrototype(Handle object) const; - bool HasFeedback(FeedbackSource const& source) const; void SetFeedback(FeedbackSource const& source, ProcessedFeedback const* feedback); diff --git a/deps/v8/src/compiler/js-native-context-specialization.cc b/deps/v8/src/compiler/js-native-context-specialization.cc index e7a2abed27da..17b5f722fc82 100644 --- a/deps/v8/src/compiler/js-native-context-specialization.cc +++ b/deps/v8/src/compiler/js-native-context-specialization.cc @@ -4245,7 +4245,7 @@ bool JSNativeContextSpecialization::CanTreatHoleAsUndefined( for (MapRef receiver_map : receiver_maps) { ObjectRef receiver_prototype = receiver_map.prototype(broker()); if (!receiver_prototype.IsJSObject() || - !broker()->IsArrayOrObjectPrototype(receiver_prototype.AsJSObject())) { + !receiver_prototype.AsJSObject().IsArrayOrObjectPrototype(broker())) { return false; } } diff --git a/deps/v8/src/compiler/node-properties.cc b/deps/v8/src/compiler/node-properties.cc index 6e2ef92fc0ea..89af7582c5e0 100644 --- a/deps/v8/src/compiler/node-properties.cc +++ b/deps/v8/src/compiler/node-properties.cc @@ -417,7 +417,7 @@ NodeProperties::InferMapsResult NodeProperties::InferMapsUnsafe( // TODO(bmeurer): This can be removed once the Array.prototype and // Object.prototype have NO_ELEMENTS elements kind. if (!ref.IsJSObject() || - !broker->IsArrayOrObjectPrototype(ref.AsJSObject())) { + !ref.AsJSObject().IsArrayOrObjectPrototype(broker)) { if (ref.map(broker).is_stable()) { // The {receiver_map} is only reliable when we install a stability // code dependency. diff --git a/deps/v8/src/maglev/maglev-graph-builder.cc b/deps/v8/src/maglev/maglev-graph-builder.cc index db081bfde623..d1133abf2e28 100644 --- a/deps/v8/src/maglev/maglev-graph-builder.cc +++ b/deps/v8/src/maglev/maglev-graph-builder.cc @@ -5594,7 +5594,7 @@ bool MaglevGraphBuilder::CanTreatHoleAsUndefined( for (compiler::MapRef receiver_map : receiver_maps) { compiler::ObjectRef receiver_prototype = receiver_map.prototype(broker()); if (!receiver_prototype.IsJSObject() || - !broker()->IsArrayOrObjectPrototype(receiver_prototype.AsJSObject())) { + !receiver_prototype.AsJSObject().IsArrayOrObjectPrototype(broker())) { return false; } }