Commit 4d58f8ac authored by Seth Brenith's avatar Seth Brenith Committed by V8 LUCI CQ

Make JSFinalizationRegistry::next_dirty weak

Currently, JSFinalizationRegistry has a BodyDescriptor that iterates
next_dirty as a custom weak field, and it has a WeakListVisitor that
cleans up any items from the list that should be removed. However, none
of that code is used, because JSFinalizationRegistry objects are created
with visitor ID kVisitJSObjectFast. This change gives them a custom
visitor ID so that next_dirty can be treated as weak.

Bug: v8:12430
Change-Id: I31c1935257ad508b13a3e684662d2ca406d8ed19
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3307096
Commit-Queue: Seth Brenith <seth.brenith@microsoft.com>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78167}
parent d99c0dfd
......@@ -127,6 +127,10 @@ class ConcurrentMarkingVisitor final
return VisitJSObjectSubclass(map, object);
}
int VisitJSFinalizationRegistry(Map map, JSFinalizationRegistry object) {
return VisitJSObjectSubclass(map, object);
}
int VisitConsString(Map map, ConsString object) {
return VisitFullyWithSnapshot(map, object);
}
......@@ -210,19 +214,21 @@ class ConcurrentMarkingVisitor final
void VisitCodeTarget(Code host, RelocInfo* rinfo) final {
// This should never happen, because snapshotting is performed only on
// JSObjects (and derived classes).
// some String subclasses.
UNREACHABLE();
}
void VisitEmbeddedPointer(Code host, RelocInfo* rinfo) final {
// This should never happen, because snapshotting is performed only on
// JSObjects (and derived classes).
// some String subclasses.
UNREACHABLE();
}
void VisitCustomWeakPointers(HeapObject host, ObjectSlot start,
ObjectSlot end) override {
DCHECK(host.IsWeakCell() || host.IsJSWeakRef());
// This should never happen, because snapshotting is performed only on
// some String subclasses.
UNREACHABLE();
}
private:
......
......@@ -29,6 +29,7 @@ bool NativeContextInferrer::Infer(Isolate* isolate, Map map, HeapObject object,
native_context);
case kVisitJSApiObject:
case kVisitJSArrayBuffer:
case kVisitJSFinalizationRegistry:
case kVisitJSObject:
case kVisitJSObjectFast:
case kVisitJSTypedArray:
......
......@@ -30,6 +30,7 @@ namespace internal {
V(FixedDoubleArray) \
V(JSArrayBuffer) \
V(JSDataView) \
V(JSFinalizationRegistry) \
V(JSFunction) \
V(JSObject) \
V(JSTypedArray) \
......
......@@ -249,7 +249,6 @@ VisitorId Map::GetVisitorId(Map map) {
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
case JS_DATE_TYPE:
case JS_ERROR_TYPE:
case JS_FINALIZATION_REGISTRY_TYPE:
case JS_GENERATOR_OBJECT_TYPE:
case JS_ITERATOR_PROTOTYPE_TYPE:
case JS_MAP_ITERATOR_PROTOTYPE_TYPE:
......@@ -324,6 +323,9 @@ VisitorId Map::GetVisitorId(Map map) {
case WEAK_CELL_TYPE:
return kVisitWeakCell;
case JS_FINALIZATION_REGISTRY_TYPE:
return kVisitJSFinalizationRegistry;
case FILLER_TYPE:
case FOREIGN_TYPE:
case HEAP_NUMBER_TYPE:
......
......@@ -46,6 +46,7 @@ enum InstanceType : uint16_t;
V(JSApiObject) \
V(JSArrayBuffer) \
V(JSDataView) \
V(JSFinalizationRegistry) \
V(JSFunction) \
V(JSObject) \
V(JSObjectFast) \
......
......@@ -1748,6 +1748,9 @@ bool V8HeapExplorer::IsEssentialHiddenReference(Object parent,
if (parent.IsContext() &&
field_offset == Context::OffsetOfElementAt(Context::NEXT_CONTEXT_LINK))
return false;
if (parent.IsJSFinalizationRegistry() &&
field_offset == JSFinalizationRegistry::kNextDirtyOffset)
return false;
return true;
}
......
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --expose-gc --noincremental-marking --no-concurrent-inlining
let cleanup_called = false;
function cleanup(holdings) {
cleanup_called = true;
};
let cleanup_called_2 = false;
function cleanup2(holdings) {
cleanup_called_2 = true;
};
let fg = new FinalizationRegistry(cleanup);
(function() {
let fg2 = new FinalizationRegistry(cleanup2);
(function() {
fg.register({}, {});
fg2.register({}, {});
})();
// Schedule fg and fg2 for cleanup.
gc();
})();
// Collect fg2, but fg is still alive.
gc();
setTimeout(function() {
assertTrue(cleanup_called);
assertFalse(cleanup_called_2);
}, 0);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment