[weakrefs] Rename FinalizationGroup to FinalizationRegistry in C++
Renaming the JS-visible identifiers and strings is left for a future CL. FinalizationGroup was renamed at Feb 2020 TC39, to better signal that if a FinalizationRegistry dies, the finalization actions registered with it may no longer be performed. Bug: v8:8179 Change-Id: I0d676a71a4a67d2b7175994a67458a6158065844 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2055381 Reviewed-by: Adam Klein <adamk@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Commit-Queue: Shu-yu Guo <syg@chromium.org> Cr-Commit-Position: refs/heads/master@{#66416}
This commit is contained in:
parent
aa9849470e
commit
5e797bf82a
4
BUILD.gn
4
BUILD.gn
@ -2334,8 +2334,8 @@ v8_source_set("v8_base_without_compiler") {
|
||||
"src/heap/factory-inl.h",
|
||||
"src/heap/factory.cc",
|
||||
"src/heap/factory.h",
|
||||
"src/heap/finalization-group-cleanup-task.cc",
|
||||
"src/heap/finalization-group-cleanup-task.h",
|
||||
"src/heap/finalization-registry-cleanup-task.cc",
|
||||
"src/heap/finalization-registry-cleanup-task.h",
|
||||
"src/heap/gc-idle-time-handler.cc",
|
||||
"src/heap/gc-idle-time-handler.h",
|
||||
"src/heap/gc-tracer.cc",
|
||||
|
@ -86,7 +86,7 @@ MAKE_TO_LOCAL(ToLocal, JSArrayBufferView, ArrayBufferView)
|
||||
MAKE_TO_LOCAL(ToLocal, JSDataView, DataView)
|
||||
MAKE_TO_LOCAL(ToLocal, JSTypedArray, TypedArray)
|
||||
MAKE_TO_LOCAL(ToLocalShared, JSArrayBuffer, SharedArrayBuffer)
|
||||
MAKE_TO_LOCAL(ToLocal, JSFinalizationGroup, FinalizationGroup)
|
||||
MAKE_TO_LOCAL(ToLocal, JSFinalizationRegistry, FinalizationGroup)
|
||||
|
||||
TYPED_ARRAYS(MAKE_TO_LOCAL_TYPED_ARRAY)
|
||||
|
||||
|
@ -895,7 +895,7 @@ StartupData SnapshotCreator::CreateBlob(
|
||||
startup_serializer.SerializeWeakReferencesAndDeferred();
|
||||
can_be_rehashed = can_be_rehashed && startup_serializer.can_be_rehashed();
|
||||
|
||||
startup_serializer.CheckNoDirtyFinalizationGroups();
|
||||
startup_serializer.CheckNoDirtyFinalizationRegistries();
|
||||
|
||||
read_only_serializer.FinalizeSerialization();
|
||||
can_be_rehashed = can_be_rehashed && read_only_serializer.can_be_rehashed();
|
||||
@ -8356,16 +8356,17 @@ void Isolate::SetHostCleanupFinalizationGroupCallback(
|
||||
|
||||
Maybe<bool> FinalizationGroup::Cleanup(
|
||||
Local<FinalizationGroup> finalization_group) {
|
||||
i::Handle<i::JSFinalizationGroup> fg = Utils::OpenHandle(*finalization_group);
|
||||
i::Isolate* isolate = fg->native_context().GetIsolate();
|
||||
i::Handle<i::Context> i_context(fg->native_context(), isolate);
|
||||
i::Handle<i::JSFinalizationRegistry> fr =
|
||||
Utils::OpenHandle(*finalization_group);
|
||||
i::Isolate* isolate = fr->native_context().GetIsolate();
|
||||
i::Handle<i::Context> i_context(fr->native_context(), isolate);
|
||||
Local<Context> context = Utils::ToLocal(i_context);
|
||||
ENTER_V8(isolate, context, FinalizationGroup, Cleanup, Nothing<bool>(),
|
||||
i::HandleScope);
|
||||
i::Handle<i::Object> callback(fg->cleanup(), isolate);
|
||||
fg->set_scheduled_for_cleanup(false);
|
||||
i::Handle<i::Object> callback(fr->cleanup(), isolate);
|
||||
fr->set_scheduled_for_cleanup(false);
|
||||
has_pending_exception =
|
||||
i::JSFinalizationGroup::Cleanup(isolate, fg, callback).IsNothing();
|
||||
i::JSFinalizationRegistry::Cleanup(isolate, fr, callback).IsNothing();
|
||||
RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
|
||||
return Just(true);
|
||||
}
|
||||
@ -11074,21 +11075,22 @@ void InvokeFunctionCallback(const v8::FunctionCallbackInfo<v8::Value>& info,
|
||||
callback(info);
|
||||
}
|
||||
|
||||
void InvokeFinalizationGroupCleanupFromTask(
|
||||
Handle<Context> context, Handle<JSFinalizationGroup> finalization_group,
|
||||
void InvokeFinalizationRegistryCleanupFromTask(
|
||||
Handle<Context> context,
|
||||
Handle<JSFinalizationRegistry> finalization_registry,
|
||||
Handle<Object> callback) {
|
||||
Isolate* isolate = finalization_group->native_context().GetIsolate();
|
||||
Isolate* isolate = finalization_registry->native_context().GetIsolate();
|
||||
RuntimeCallTimerScope timer(
|
||||
isolate, RuntimeCallCounterId::kFinalizationGroupCleanupFromTask);
|
||||
isolate, RuntimeCallCounterId::kFinalizationRegistryCleanupFromTask);
|
||||
// Do not use ENTER_V8 because this is always called from a running
|
||||
// FinalizationGroupCleanupTask within V8 and we should not log it as an API
|
||||
// call. This method is implemented here to avoid duplication of the exception
|
||||
// handling and microtask running logic in CallDepthScope.
|
||||
// FinalizationRegistryCleanupTask within V8 and we should not log it as an
|
||||
// API call. This method is implemented here to avoid duplication of the
|
||||
// exception handling and microtask running logic in CallDepthScope.
|
||||
if (IsExecutionTerminatingCheck(isolate)) return;
|
||||
Local<v8::Context> api_context = Utils::ToLocal(context);
|
||||
CallDepthScope<true> call_depth_scope(isolate, api_context);
|
||||
VMState<OTHER> state(isolate);
|
||||
if (JSFinalizationGroup::Cleanup(isolate, finalization_group, callback)
|
||||
if (JSFinalizationRegistry::Cleanup(isolate, finalization_registry, callback)
|
||||
.IsNothing()) {
|
||||
call_depth_scope.Escape();
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ namespace v8 {
|
||||
|
||||
namespace internal {
|
||||
class JSArrayBufferView;
|
||||
class JSFinalizationGroup;
|
||||
class JSFinalizationRegistry;
|
||||
} // namespace internal
|
||||
|
||||
namespace debug {
|
||||
@ -93,7 +93,7 @@ class RegisteredExtension {
|
||||
V(Data, Object) \
|
||||
V(RegExp, JSRegExp) \
|
||||
V(Object, JSReceiver) \
|
||||
V(FinalizationGroup, JSFinalizationGroup) \
|
||||
V(FinalizationGroup, JSFinalizationRegistry) \
|
||||
V(Array, JSArray) \
|
||||
V(Map, JSMap) \
|
||||
V(Set, JSSet) \
|
||||
@ -206,7 +206,7 @@ class Utils {
|
||||
static inline Local<BigUint64Array> ToLocalBigUint64Array(
|
||||
v8::internal::Handle<v8::internal::JSTypedArray> obj);
|
||||
static inline Local<FinalizationGroup> ToLocal(
|
||||
v8::internal::Handle<v8::internal::JSFinalizationGroup> obj);
|
||||
v8::internal::Handle<v8::internal::JSFinalizationRegistry> obj);
|
||||
|
||||
static inline Local<SharedArrayBuffer> ToLocalShared(
|
||||
v8::internal::Handle<v8::internal::JSArrayBuffer> obj);
|
||||
@ -562,8 +562,9 @@ void InvokeAccessorGetterCallback(
|
||||
void InvokeFunctionCallback(const v8::FunctionCallbackInfo<v8::Value>& info,
|
||||
v8::FunctionCallback callback);
|
||||
|
||||
void InvokeFinalizationGroupCleanupFromTask(
|
||||
Handle<Context> context, Handle<JSFinalizationGroup> finalization_group,
|
||||
void InvokeFinalizationRegistryCleanupFromTask(
|
||||
Handle<Context> context,
|
||||
Handle<JSFinalizationRegistry> finalization_registry,
|
||||
Handle<Object> callback);
|
||||
|
||||
} // namespace internal
|
||||
|
@ -979,11 +979,11 @@ namespace internal {
|
||||
CPP(Trace) \
|
||||
\
|
||||
/* Weak refs */ \
|
||||
CPP(FinalizationGroupCleanupIteratorNext) \
|
||||
CPP(FinalizationGroupCleanupSome) \
|
||||
CPP(FinalizationGroupConstructor) \
|
||||
CPP(FinalizationGroupRegister) \
|
||||
CPP(FinalizationGroupUnregister) \
|
||||
CPP(FinalizationRegistryCleanupIteratorNext) \
|
||||
CPP(FinalizationRegistryCleanupSome) \
|
||||
CPP(FinalizationRegistryConstructor) \
|
||||
CPP(FinalizationRegistryRegister) \
|
||||
CPP(FinalizationRegistryUnregister) \
|
||||
CPP(WeakRefConstructor) \
|
||||
CPP(WeakRefDeref) \
|
||||
\
|
||||
|
@ -9,7 +9,7 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
BUILTIN(FinalizationGroupConstructor) {
|
||||
BUILTIN(FinalizationRegistryConstructor) {
|
||||
HandleScope scope(isolate);
|
||||
Handle<JSFunction> target = args.target();
|
||||
if (args.new_target()->IsUndefined(isolate)) { // [[Call]]
|
||||
@ -31,22 +31,22 @@ BUILTIN(FinalizationGroupConstructor) {
|
||||
isolate, result,
|
||||
JSObject::New(target, new_target, Handle<AllocationSite>::null()));
|
||||
|
||||
Handle<JSFinalizationGroup> finalization_group =
|
||||
Handle<JSFinalizationGroup>::cast(result);
|
||||
finalization_group->set_native_context(*isolate->native_context());
|
||||
finalization_group->set_cleanup(*cleanup);
|
||||
finalization_group->set_flags(
|
||||
JSFinalizationGroup::ScheduledForCleanupField::encode(false));
|
||||
Handle<JSFinalizationRegistry> finalization_registry =
|
||||
Handle<JSFinalizationRegistry>::cast(result);
|
||||
finalization_registry->set_native_context(*isolate->native_context());
|
||||
finalization_registry->set_cleanup(*cleanup);
|
||||
finalization_registry->set_flags(
|
||||
JSFinalizationRegistry::ScheduledForCleanupField::encode(false));
|
||||
|
||||
DCHECK(finalization_group->active_cells().IsUndefined(isolate));
|
||||
DCHECK(finalization_group->cleared_cells().IsUndefined(isolate));
|
||||
DCHECK(finalization_group->key_map().IsUndefined(isolate));
|
||||
return *finalization_group;
|
||||
DCHECK(finalization_registry->active_cells().IsUndefined(isolate));
|
||||
DCHECK(finalization_registry->cleared_cells().IsUndefined(isolate));
|
||||
DCHECK(finalization_registry->key_map().IsUndefined(isolate));
|
||||
return *finalization_registry;
|
||||
}
|
||||
|
||||
BUILTIN(FinalizationGroupRegister) {
|
||||
BUILTIN(FinalizationRegistryRegister) {
|
||||
HandleScope scope(isolate);
|
||||
const char* method_name = "FinalizationGroup.prototype.register";
|
||||
const char* method_name = "FinalizationRegistry.prototype.register";
|
||||
|
||||
// 1. Let finalizationGroup be the this value.
|
||||
//
|
||||
@ -55,7 +55,7 @@ BUILTIN(FinalizationGroupRegister) {
|
||||
//
|
||||
// 4. If finalizationGroup does not have a [[Cells]] internal slot,
|
||||
// throw a TypeError exception.
|
||||
CHECK_RECEIVER(JSFinalizationGroup, finalization_group, method_name);
|
||||
CHECK_RECEIVER(JSFinalizationRegistry, finalization_registry, method_name);
|
||||
|
||||
Handle<Object> target = args.atOrUndefined(isolate, 1);
|
||||
|
||||
@ -86,15 +86,15 @@ BUILTIN(FinalizationGroupRegister) {
|
||||
}
|
||||
// TODO(marja): Realms.
|
||||
|
||||
JSFinalizationGroup::Register(finalization_group,
|
||||
Handle<JSReceiver>::cast(target), holdings,
|
||||
unregister_token, isolate);
|
||||
JSFinalizationRegistry::Register(finalization_registry,
|
||||
Handle<JSReceiver>::cast(target), holdings,
|
||||
unregister_token, isolate);
|
||||
return ReadOnlyRoots(isolate).undefined_value();
|
||||
}
|
||||
|
||||
BUILTIN(FinalizationGroupUnregister) {
|
||||
BUILTIN(FinalizationRegistryUnregister) {
|
||||
HandleScope scope(isolate);
|
||||
const char* method_name = "FinalizationGroup.prototype.unregister";
|
||||
const char* method_name = "FinalizationRegistry.prototype.unregister";
|
||||
|
||||
// 1. Let finalizationGroup be the this value.
|
||||
//
|
||||
@ -103,7 +103,7 @@ BUILTIN(FinalizationGroupUnregister) {
|
||||
//
|
||||
// 3. If finalizationGroup does not have a [[Cells]] internal slot,
|
||||
// throw a TypeError exception.
|
||||
CHECK_RECEIVER(JSFinalizationGroup, finalization_group, method_name);
|
||||
CHECK_RECEIVER(JSFinalizationRegistry, finalization_registry, method_name);
|
||||
|
||||
Handle<Object> unregister_token = args.atOrUndefined(isolate, 1);
|
||||
|
||||
@ -115,15 +115,16 @@ BUILTIN(FinalizationGroupUnregister) {
|
||||
unregister_token));
|
||||
}
|
||||
|
||||
bool success = JSFinalizationGroup::Unregister(
|
||||
finalization_group, Handle<JSReceiver>::cast(unregister_token), isolate);
|
||||
bool success = JSFinalizationRegistry::Unregister(
|
||||
finalization_registry, Handle<JSReceiver>::cast(unregister_token),
|
||||
isolate);
|
||||
|
||||
return *isolate->factory()->ToBoolean(success);
|
||||
}
|
||||
|
||||
BUILTIN(FinalizationGroupCleanupSome) {
|
||||
BUILTIN(FinalizationRegistryCleanupSome) {
|
||||
HandleScope scope(isolate);
|
||||
const char* method_name = "FinalizationGroup.prototype.cleanupSome";
|
||||
const char* method_name = "FinalizationRegistry.prototype.cleanupSome";
|
||||
|
||||
// 1. Let finalizationGroup be the this value.
|
||||
//
|
||||
@ -132,9 +133,9 @@ BUILTIN(FinalizationGroupCleanupSome) {
|
||||
//
|
||||
// 3. If finalizationGroup does not have a [[Cells]] internal slot,
|
||||
// throw a TypeError exception.
|
||||
CHECK_RECEIVER(JSFinalizationGroup, finalization_group, method_name);
|
||||
CHECK_RECEIVER(JSFinalizationRegistry, finalization_registry, method_name);
|
||||
|
||||
Handle<Object> callback(finalization_group->cleanup(), isolate);
|
||||
Handle<Object> callback(finalization_registry->cleanup(), isolate);
|
||||
Handle<Object> callback_obj = args.atOrUndefined(isolate, 1);
|
||||
|
||||
// 4. If callback is not undefined and IsCallable(callback) is
|
||||
@ -150,7 +151,7 @@ BUILTIN(FinalizationGroupCleanupSome) {
|
||||
|
||||
// Don't do set_scheduled_for_cleanup(false); we still have the task
|
||||
// scheduled.
|
||||
if (JSFinalizationGroup::Cleanup(isolate, finalization_group, callback)
|
||||
if (JSFinalizationRegistry::Cleanup(isolate, finalization_registry, callback)
|
||||
.IsNothing()) {
|
||||
DCHECK(isolate->has_pending_exception());
|
||||
return ReadOnlyRoots(isolate).exception();
|
||||
@ -158,19 +159,20 @@ BUILTIN(FinalizationGroupCleanupSome) {
|
||||
return ReadOnlyRoots(isolate).undefined_value();
|
||||
}
|
||||
|
||||
BUILTIN(FinalizationGroupCleanupIteratorNext) {
|
||||
BUILTIN(FinalizationRegistryCleanupIteratorNext) {
|
||||
HandleScope scope(isolate);
|
||||
CHECK_RECEIVER(JSFinalizationGroupCleanupIterator, iterator, "next");
|
||||
CHECK_RECEIVER(JSFinalizationRegistryCleanupIterator, iterator, "next");
|
||||
|
||||
Handle<JSFinalizationGroup> finalization_group(iterator->finalization_group(),
|
||||
isolate);
|
||||
if (!finalization_group->NeedsCleanup()) {
|
||||
Handle<JSFinalizationRegistry> finalization_registry(
|
||||
iterator->finalization_registry(), isolate);
|
||||
if (!finalization_registry->NeedsCleanup()) {
|
||||
return *isolate->factory()->NewJSIteratorResult(
|
||||
handle(ReadOnlyRoots(isolate).undefined_value(), isolate), true);
|
||||
}
|
||||
Handle<Object> holdings = handle(
|
||||
JSFinalizationGroup::PopClearedCellHoldings(finalization_group, isolate),
|
||||
isolate);
|
||||
Handle<Object> holdings =
|
||||
handle(JSFinalizationRegistry::PopClearedCellHoldings(
|
||||
finalization_registry, isolate),
|
||||
isolate);
|
||||
|
||||
return *isolate->factory()->NewJSIteratorResult(holdings, false);
|
||||
}
|
||||
|
@ -582,8 +582,8 @@ namespace internal {
|
||||
T(WeakRefsRegisterTargetMustBeObject, \
|
||||
"FinalizationGroup.prototype.register: target must be an object") \
|
||||
T(WeakRefsRegisterTargetAndHoldingsMustNotBeSame, \
|
||||
"FinalizationGroup.prototype.register: target and holdings must not be " \
|
||||
"same") \
|
||||
"FinalizationGroup.prototype.register: target and holdings must not " \
|
||||
"be same") \
|
||||
T(WeakRefsWeakRefConstructorTargetMustBeObject, \
|
||||
"WeakRef: target must be an object") \
|
||||
T(OptionalChainingNoNew, "Invalid optional chain from new expression") \
|
||||
|
@ -64,8 +64,8 @@ class JSSegmentIterator;
|
||||
class JSSegmenter;
|
||||
class JSV8BreakIterator;
|
||||
class JSWeakCollection;
|
||||
class JSFinalizationGroup;
|
||||
class JSFinalizationGroupCleanupIterator;
|
||||
class JSFinalizationRegistry;
|
||||
class JSFinalizationRegistryCleanupIterator;
|
||||
class JSWeakMap;
|
||||
class JSWeakRef;
|
||||
class JSWeakSet;
|
||||
|
@ -239,8 +239,8 @@ Type::bitset BitsetType::Lub(const MapRefLike& map) {
|
||||
case JS_MAP_VALUE_ITERATOR_TYPE:
|
||||
case JS_STRING_ITERATOR_TYPE:
|
||||
case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
|
||||
case JS_FINALIZATION_GROUP_TYPE:
|
||||
case JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_TYPE:
|
||||
case JS_FINALIZATION_REGISTRY_TYPE:
|
||||
case JS_FINALIZATION_REGISTRY_CLEANUP_ITERATOR_TYPE:
|
||||
case JS_WEAK_MAP_TYPE:
|
||||
case JS_WEAK_REF_TYPE:
|
||||
case JS_WEAK_SET_TYPE:
|
||||
|
@ -637,7 +637,7 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
|
||||
DCHECK(try_catch.HasCaught());
|
||||
return false;
|
||||
}
|
||||
// It's possible that a FinalizationGroup cleanup task threw an error.
|
||||
// It's possible that a FinalizationRegistry cleanup task threw an error.
|
||||
if (try_catch.HasCaught()) success = false;
|
||||
if (print_result) {
|
||||
if (options.test_shell) {
|
||||
|
@ -1070,8 +1070,8 @@ void WeakCell::WeakCellVerify(Isolate* isolate) {
|
||||
|
||||
CHECK(key_list_next().IsWeakCell() || key_list_next().IsUndefined(isolate));
|
||||
|
||||
CHECK(finalization_group().IsUndefined(isolate) ||
|
||||
finalization_group().IsJSFinalizationGroup());
|
||||
CHECK(finalization_registry().IsUndefined(isolate) ||
|
||||
finalization_registry().IsJSFinalizationRegistry());
|
||||
}
|
||||
|
||||
void JSWeakRef::JSWeakRefVerify(Isolate* isolate) {
|
||||
@ -1080,8 +1080,8 @@ void JSWeakRef::JSWeakRefVerify(Isolate* isolate) {
|
||||
CHECK(target().IsUndefined(isolate) || target().IsJSReceiver());
|
||||
}
|
||||
|
||||
void JSFinalizationGroup::JSFinalizationGroupVerify(Isolate* isolate) {
|
||||
CHECK(IsJSFinalizationGroup());
|
||||
void JSFinalizationRegistry::JSFinalizationRegistryVerify(Isolate* isolate) {
|
||||
CHECK(IsJSFinalizationRegistry());
|
||||
JSObjectVerify(isolate);
|
||||
VerifyHeapPointer(isolate, cleanup());
|
||||
CHECK(active_cells().IsUndefined(isolate) || active_cells().IsWeakCell());
|
||||
@ -1093,14 +1093,14 @@ void JSFinalizationGroup::JSFinalizationGroupVerify(Isolate* isolate) {
|
||||
CHECK(WeakCell::cast(cleared_cells()).prev().IsUndefined(isolate));
|
||||
}
|
||||
CHECK(next_dirty().IsUndefined(isolate) ||
|
||||
next_dirty().IsJSFinalizationGroup());
|
||||
next_dirty().IsJSFinalizationRegistry());
|
||||
}
|
||||
|
||||
void JSFinalizationGroupCleanupIterator::
|
||||
JSFinalizationGroupCleanupIteratorVerify(Isolate* isolate) {
|
||||
CHECK(IsJSFinalizationGroupCleanupIterator());
|
||||
void JSFinalizationRegistryCleanupIterator::
|
||||
JSFinalizationRegistryCleanupIteratorVerify(Isolate* isolate) {
|
||||
CHECK(IsJSFinalizationRegistryCleanupIterator());
|
||||
JSObjectVerify(isolate);
|
||||
VerifyHeapPointer(isolate, finalization_group());
|
||||
VerifyHeapPointer(isolate, finalization_registry());
|
||||
}
|
||||
|
||||
void JSWeakMap::JSWeakMapVerify(Isolate* isolate) {
|
||||
|
@ -1150,7 +1150,7 @@ void JSMapIterator::JSMapIteratorPrint(std::ostream& os) { // NOLINT
|
||||
|
||||
void WeakCell::WeakCellPrint(std::ostream& os) {
|
||||
PrintHeader(os, "WeakCell");
|
||||
os << "\n - finalization_group: " << Brief(finalization_group());
|
||||
os << "\n - finalization_registry: " << Brief(finalization_registry());
|
||||
os << "\n - target: " << Brief(target());
|
||||
os << "\n - holdings: " << Brief(holdings());
|
||||
os << "\n - prev: " << Brief(prev());
|
||||
@ -1166,8 +1166,8 @@ void JSWeakRef::JSWeakRefPrint(std::ostream& os) {
|
||||
JSObjectPrintBody(os, *this);
|
||||
}
|
||||
|
||||
void JSFinalizationGroup::JSFinalizationGroupPrint(std::ostream& os) {
|
||||
JSObjectPrintHeader(os, *this, "JSFinalizationGroup");
|
||||
void JSFinalizationRegistry::JSFinalizationRegistryPrint(std::ostream& os) {
|
||||
JSObjectPrintHeader(os, *this, "JSFinalizationRegistry");
|
||||
os << "\n - native_context: " << Brief(native_context());
|
||||
os << "\n - cleanup: " << Brief(cleanup());
|
||||
os << "\n - active_cells: " << Brief(active_cells());
|
||||
@ -1186,10 +1186,10 @@ void JSFinalizationGroup::JSFinalizationGroupPrint(std::ostream& os) {
|
||||
JSObjectPrintBody(os, *this);
|
||||
}
|
||||
|
||||
void JSFinalizationGroupCleanupIterator::
|
||||
JSFinalizationGroupCleanupIteratorPrint(std::ostream& os) {
|
||||
JSObjectPrintHeader(os, *this, "JSFinalizationGroupCleanupIterator");
|
||||
os << "\n - finalization_group: " << Brief(finalization_group());
|
||||
void JSFinalizationRegistryCleanupIterator::
|
||||
JSFinalizationRegistryCleanupIteratorPrint(std::ostream& os) {
|
||||
JSObjectPrintHeader(os, *this, "JSFinalizationRegistryCleanupIterator");
|
||||
os << "\n - finalization_registry: " << Brief(finalization_registry());
|
||||
JSObjectPrintBody(os, *this);
|
||||
}
|
||||
|
||||
|
@ -4017,12 +4017,12 @@ void Isolate::SetHostCleanupFinalizationGroupCallback(
|
||||
}
|
||||
|
||||
void Isolate::RunHostCleanupFinalizationGroupCallback(
|
||||
Handle<JSFinalizationGroup> fg) {
|
||||
Handle<JSFinalizationRegistry> fr) {
|
||||
if (host_cleanup_finalization_group_callback_ != nullptr) {
|
||||
v8::Local<v8::Context> api_context =
|
||||
v8::Utils::ToLocal(handle(Context::cast(fg->native_context()), this));
|
||||
v8::Utils::ToLocal(handle(Context::cast(fr->native_context()), this));
|
||||
host_cleanup_finalization_group_callback_(api_context,
|
||||
v8::Utils::ToLocal(fg));
|
||||
v8::Utils::ToLocal(fr));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1424,7 +1424,8 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
|
||||
host_cleanup_finalization_group_callback() const {
|
||||
return host_cleanup_finalization_group_callback_;
|
||||
}
|
||||
void RunHostCleanupFinalizationGroupCallback(Handle<JSFinalizationGroup> fg);
|
||||
void RunHostCleanupFinalizationGroupCallback(
|
||||
Handle<JSFinalizationRegistry> fr);
|
||||
|
||||
void SetHostImportModuleDynamicallyCallback(
|
||||
HostImportModuleDynamicallyCallback callback);
|
||||
|
@ -1,35 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef V8_HEAP_FINALIZATION_GROUP_CLEANUP_TASK_H_
|
||||
#define V8_HEAP_FINALIZATION_GROUP_CLEANUP_TASK_H_
|
||||
|
||||
#include "src/objects/js-weak-refs.h"
|
||||
#include "src/tasks/cancelable-task.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// The GC schedules a cleanup task when the dirty FinalizationGroup list is
|
||||
// non-empty. The task processes a single FinalizationGroup and posts another
|
||||
// cleanup task if there are remaining dirty FinalizationGroups on the list.
|
||||
class FinalizationGroupCleanupTask : public CancelableTask {
|
||||
public:
|
||||
explicit FinalizationGroupCleanupTask(Heap* heap);
|
||||
~FinalizationGroupCleanupTask() override = default;
|
||||
|
||||
private:
|
||||
FinalizationGroupCleanupTask(const FinalizationGroupCleanupTask&) = delete;
|
||||
void operator=(const FinalizationGroupCleanupTask&) = delete;
|
||||
|
||||
void RunInternal() override;
|
||||
void SlowAssertNoActiveJavaScript();
|
||||
|
||||
Heap* heap_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_HEAP_FINALIZATION_GROUP_CLEANUP_TASK_H_
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/heap/finalization-group-cleanup-task.h"
|
||||
#include "src/heap/finalization-registry-cleanup-task.h"
|
||||
|
||||
#include "src/execution/frames.h"
|
||||
#include "src/execution/interrupts-scope.h"
|
||||
@ -15,10 +15,10 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
FinalizationGroupCleanupTask::FinalizationGroupCleanupTask(Heap* heap)
|
||||
FinalizationRegistryCleanupTask::FinalizationRegistryCleanupTask(Heap* heap)
|
||||
: CancelableTask(heap->isolate()), heap_(heap) {}
|
||||
|
||||
void FinalizationGroupCleanupTask::SlowAssertNoActiveJavaScript() {
|
||||
void FinalizationRegistryCleanupTask::SlowAssertNoActiveJavaScript() {
|
||||
#ifdef ENABLE_SLOW_DCHECKS
|
||||
class NoActiveJavaScript : public ThreadVisitor {
|
||||
public:
|
||||
@ -35,39 +35,42 @@ void FinalizationGroupCleanupTask::SlowAssertNoActiveJavaScript() {
|
||||
#endif // ENABLE_SLOW_DCHECKS
|
||||
}
|
||||
|
||||
void FinalizationGroupCleanupTask::RunInternal() {
|
||||
void FinalizationRegistryCleanupTask::RunInternal() {
|
||||
Isolate* isolate = heap_->isolate();
|
||||
DCHECK(!isolate->host_cleanup_finalization_group_callback());
|
||||
SlowAssertNoActiveJavaScript();
|
||||
|
||||
TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8",
|
||||
"V8.FinalizationGroupCleanupTask");
|
||||
"V8.FinalizationRegistryCleanupTask");
|
||||
|
||||
HandleScope handle_scope(isolate);
|
||||
Handle<JSFinalizationGroup> finalization_group;
|
||||
// There could be no dirty FinalizationGroups. When a context is disposed by
|
||||
// the embedder, its FinalizationGroups are removed from the dirty list.
|
||||
if (!heap_->DequeueDirtyJSFinalizationGroup().ToHandle(&finalization_group)) {
|
||||
Handle<JSFinalizationRegistry> finalization_registry;
|
||||
// There could be no dirty FinalizationRegistries. When a context is disposed
|
||||
// by the embedder, its FinalizationRegistries are removed from the dirty
|
||||
// list.
|
||||
if (!heap_->DequeueDirtyJSFinalizationRegistry().ToHandle(
|
||||
&finalization_registry)) {
|
||||
return;
|
||||
}
|
||||
finalization_group->set_scheduled_for_cleanup(false);
|
||||
finalization_registry->set_scheduled_for_cleanup(false);
|
||||
|
||||
// Since FinalizationGroup cleanup callbacks are scheduled by V8, enter the
|
||||
// FinalizationGroup's context.
|
||||
Handle<Context> context(Context::cast(finalization_group->native_context()),
|
||||
isolate);
|
||||
Handle<Object> callback(finalization_group->cleanup(), isolate);
|
||||
// Since FinalizationRegistry cleanup callbacks are scheduled by V8, enter the
|
||||
// FinalizationRegistry's context.
|
||||
Handle<Context> context(
|
||||
Context::cast(finalization_registry->native_context()), isolate);
|
||||
Handle<Object> callback(finalization_registry->cleanup(), isolate);
|
||||
v8::Context::Scope context_scope(v8::Utils::ToLocal(context));
|
||||
v8::TryCatch catcher(reinterpret_cast<v8::Isolate*>(isolate));
|
||||
catcher.SetVerbose(true);
|
||||
|
||||
// Exceptions are reported via the message handler. This is ensured by the
|
||||
// verbose TryCatch.
|
||||
InvokeFinalizationGroupCleanupFromTask(context, finalization_group, callback);
|
||||
InvokeFinalizationRegistryCleanupFromTask(context, finalization_registry,
|
||||
callback);
|
||||
|
||||
// Repost if there are remaining dirty FinalizationGroups.
|
||||
heap_->set_is_finalization_group_cleanup_task_posted(false);
|
||||
heap_->PostFinalizationGroupCleanupTaskIfNeeded();
|
||||
// Repost if there are remaining dirty FinalizationRegistries.
|
||||
heap_->set_is_finalization_registry_cleanup_task_posted(false);
|
||||
heap_->PostFinalizationRegistryCleanupTaskIfNeeded();
|
||||
}
|
||||
|
||||
} // namespace internal
|
36
src/heap/finalization-registry-cleanup-task.h
Normal file
36
src/heap/finalization-registry-cleanup-task.h
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
#ifndef V8_HEAP_FINALIZATION_REGISTRY_CLEANUP_TASK_H_
|
||||
#define V8_HEAP_FINALIZATION_REGISTRY_CLEANUP_TASK_H_
|
||||
|
||||
#include "src/objects/js-weak-refs.h"
|
||||
#include "src/tasks/cancelable-task.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// The GC schedules a cleanup task when the dirty FinalizationRegistry list is
|
||||
// non-empty. The task processes a single FinalizationRegistry and posts another
|
||||
// cleanup task if there are remaining dirty FinalizationRegistries on the list.
|
||||
class FinalizationRegistryCleanupTask : public CancelableTask {
|
||||
public:
|
||||
explicit FinalizationRegistryCleanupTask(Heap* heap);
|
||||
~FinalizationRegistryCleanupTask() override = default;
|
||||
|
||||
private:
|
||||
FinalizationRegistryCleanupTask(const FinalizationRegistryCleanupTask&) =
|
||||
delete;
|
||||
void operator=(const FinalizationRegistryCleanupTask&) = delete;
|
||||
|
||||
void RunInternal() override;
|
||||
void SlowAssertNoActiveJavaScript();
|
||||
|
||||
Heap* heap_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_HEAP_FINALIZATION_REGISTRY_CLEANUP_TASK_H_
|
@ -640,8 +640,8 @@ void Heap::DecrementExternalBackingStoreBytes(ExternalBackingStoreType type,
|
||||
base::CheckedDecrement(&backing_store_bytes_, amount);
|
||||
}
|
||||
|
||||
bool Heap::HasDirtyJSFinalizationGroups() {
|
||||
return !dirty_js_finalization_groups_list().IsUndefined(isolate());
|
||||
bool Heap::HasDirtyJSFinalizationRegistries() {
|
||||
return !dirty_js_finalization_registries_list().IsUndefined(isolate());
|
||||
}
|
||||
|
||||
AlwaysAllocateScope::AlwaysAllocateScope(Heap* heap) : heap_(heap) {
|
||||
|
130
src/heap/heap.cc
130
src/heap/heap.cc
@ -33,7 +33,7 @@
|
||||
#include "src/heap/combined-heap.h"
|
||||
#include "src/heap/concurrent-marking.h"
|
||||
#include "src/heap/embedder-tracing.h"
|
||||
#include "src/heap/finalization-group-cleanup-task.h"
|
||||
#include "src/heap/finalization-registry-cleanup-task.h"
|
||||
#include "src/heap/gc-idle-time-handler.h"
|
||||
#include "src/heap/gc-tracer.h"
|
||||
#include "src/heap/heap-controller.h"
|
||||
@ -206,8 +206,8 @@ Heap::Heap()
|
||||
|
||||
set_native_contexts_list(Smi::zero());
|
||||
set_allocation_sites_list(Smi::zero());
|
||||
set_dirty_js_finalization_groups_list(Smi::zero());
|
||||
set_dirty_js_finalization_groups_list_tail(Smi::zero());
|
||||
set_dirty_js_finalization_registries_list(Smi::zero());
|
||||
set_dirty_js_finalization_registries_list_tail(Smi::zero());
|
||||
// Put a dummy entry in the remembered pages so we can find the list the
|
||||
// minidump even if there are no real unmapped pages.
|
||||
RememberUnmappedPage(kNullAddress, false);
|
||||
@ -1202,9 +1202,10 @@ void Heap::GarbageCollectionEpilogue() {
|
||||
if (FLAG_harmony_weak_refs &&
|
||||
isolate()->host_cleanup_finalization_group_callback()) {
|
||||
HandleScope handle_scope(isolate());
|
||||
Handle<JSFinalizationGroup> finalization_group;
|
||||
while (DequeueDirtyJSFinalizationGroup().ToHandle(&finalization_group)) {
|
||||
isolate()->RunHostCleanupFinalizationGroupCallback(finalization_group);
|
||||
Handle<JSFinalizationRegistry> finalization_registry;
|
||||
while (
|
||||
DequeueDirtyJSFinalizationRegistry().ToHandle(&finalization_registry)) {
|
||||
isolate()->RunHostCleanupFinalizationGroupCallback(finalization_registry);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1659,7 +1660,7 @@ int Heap::NotifyContextDisposed(bool dependant_context) {
|
||||
}
|
||||
isolate()->AbortConcurrentOptimization(BlockingBehavior::kDontBlock);
|
||||
if (!isolate()->context().is_null()) {
|
||||
RemoveDirtyFinalizationGroupsOnContext(isolate()->raw_native_context());
|
||||
RemoveDirtyFinalizationRegistriesOnContext(isolate()->raw_native_context());
|
||||
}
|
||||
|
||||
number_of_disposed_maps_ = retained_maps().length();
|
||||
@ -2652,7 +2653,7 @@ void Heap::UpdateReferencesInExternalStringTable(
|
||||
void Heap::ProcessAllWeakReferences(WeakObjectRetainer* retainer) {
|
||||
ProcessNativeContexts(retainer);
|
||||
ProcessAllocationSites(retainer);
|
||||
ProcessDirtyJSFinalizationGroups(retainer);
|
||||
ProcessDirtyJSFinalizationRegistries(retainer);
|
||||
}
|
||||
|
||||
|
||||
@ -2674,24 +2675,24 @@ void Heap::ProcessAllocationSites(WeakObjectRetainer* retainer) {
|
||||
set_allocation_sites_list(allocation_site_obj);
|
||||
}
|
||||
|
||||
void Heap::ProcessDirtyJSFinalizationGroups(WeakObjectRetainer* retainer) {
|
||||
Object head = VisitWeakList<JSFinalizationGroup>(
|
||||
this, dirty_js_finalization_groups_list(), retainer);
|
||||
set_dirty_js_finalization_groups_list(head);
|
||||
void Heap::ProcessDirtyJSFinalizationRegistries(WeakObjectRetainer* retainer) {
|
||||
Object head = VisitWeakList<JSFinalizationRegistry>(
|
||||
this, dirty_js_finalization_registries_list(), retainer);
|
||||
set_dirty_js_finalization_registries_list(head);
|
||||
// If the list is empty, set the tail to undefined. Otherwise the tail is set
|
||||
// by WeakListVisitor<JSFinalizationGroup>::VisitLiveObject.
|
||||
if (head.IsUndefined(isolate())) {
|
||||
set_dirty_js_finalization_groups_list_tail(head);
|
||||
set_dirty_js_finalization_registries_list_tail(head);
|
||||
}
|
||||
}
|
||||
|
||||
void Heap::ProcessWeakListRoots(WeakObjectRetainer* retainer) {
|
||||
set_native_contexts_list(retainer->RetainAs(native_contexts_list()));
|
||||
set_allocation_sites_list(retainer->RetainAs(allocation_sites_list()));
|
||||
set_dirty_js_finalization_groups_list(
|
||||
retainer->RetainAs(dirty_js_finalization_groups_list()));
|
||||
set_dirty_js_finalization_groups_list_tail(
|
||||
retainer->RetainAs(dirty_js_finalization_groups_list_tail()));
|
||||
set_dirty_js_finalization_registries_list(
|
||||
retainer->RetainAs(dirty_js_finalization_registries_list()));
|
||||
set_dirty_js_finalization_registries_list_tail(
|
||||
retainer->RetainAs(dirty_js_finalization_registries_list_tail()));
|
||||
}
|
||||
|
||||
void Heap::ForeachAllocationSite(
|
||||
@ -6069,58 +6070,59 @@ void Heap::SetInterpreterEntryTrampolineForProfiling(Code code) {
|
||||
set_interpreter_entry_trampoline_for_profiling(code);
|
||||
}
|
||||
|
||||
void Heap::PostFinalizationGroupCleanupTaskIfNeeded() {
|
||||
void Heap::PostFinalizationRegistryCleanupTaskIfNeeded() {
|
||||
DCHECK(!isolate()->host_cleanup_finalization_group_callback());
|
||||
// Only one cleanup task is posted at a time.
|
||||
if (!HasDirtyJSFinalizationGroups() ||
|
||||
is_finalization_group_cleanup_task_posted_) {
|
||||
if (!HasDirtyJSFinalizationRegistries() ||
|
||||
is_finalization_registry_cleanup_task_posted_) {
|
||||
return;
|
||||
}
|
||||
auto taskrunner = V8::GetCurrentPlatform()->GetForegroundTaskRunner(
|
||||
reinterpret_cast<v8::Isolate*>(isolate()));
|
||||
auto task = std::make_unique<FinalizationGroupCleanupTask>(this);
|
||||
auto task = std::make_unique<FinalizationRegistryCleanupTask>(this);
|
||||
taskrunner->PostNonNestableTask(std::move(task));
|
||||
is_finalization_group_cleanup_task_posted_ = true;
|
||||
is_finalization_registry_cleanup_task_posted_ = true;
|
||||
}
|
||||
|
||||
void Heap::EnqueueDirtyJSFinalizationGroup(
|
||||
JSFinalizationGroup finalization_group,
|
||||
void Heap::EnqueueDirtyJSFinalizationRegistry(
|
||||
JSFinalizationRegistry finalization_registry,
|
||||
std::function<void(HeapObject object, ObjectSlot slot, Object target)>
|
||||
gc_notify_updated_slot) {
|
||||
// Add a FinalizationGroup to the tail of the dirty list.
|
||||
DCHECK(!HasDirtyJSFinalizationGroups() ||
|
||||
dirty_js_finalization_groups_list().IsJSFinalizationGroup());
|
||||
DCHECK(finalization_group.next_dirty().IsUndefined(isolate()));
|
||||
DCHECK(!finalization_group.scheduled_for_cleanup());
|
||||
finalization_group.set_scheduled_for_cleanup(true);
|
||||
if (dirty_js_finalization_groups_list_tail().IsUndefined(isolate())) {
|
||||
DCHECK(dirty_js_finalization_groups_list().IsUndefined(isolate()));
|
||||
set_dirty_js_finalization_groups_list(finalization_group);
|
||||
// dirty_js_finalization_groups_list_ is rescanned by ProcessWeakListRoots.
|
||||
// Add a FinalizationRegistry to the tail of the dirty list.
|
||||
DCHECK(!HasDirtyJSFinalizationRegistries() ||
|
||||
dirty_js_finalization_registries_list().IsJSFinalizationRegistry());
|
||||
DCHECK(finalization_registry.next_dirty().IsUndefined(isolate()));
|
||||
DCHECK(!finalization_registry.scheduled_for_cleanup());
|
||||
finalization_registry.set_scheduled_for_cleanup(true);
|
||||
if (dirty_js_finalization_registries_list_tail().IsUndefined(isolate())) {
|
||||
DCHECK(dirty_js_finalization_registries_list().IsUndefined(isolate()));
|
||||
set_dirty_js_finalization_registries_list(finalization_registry);
|
||||
// dirty_js_finalization_registries_list_ is rescanned by
|
||||
// ProcessWeakListRoots.
|
||||
} else {
|
||||
JSFinalizationGroup tail =
|
||||
JSFinalizationGroup::cast(dirty_js_finalization_groups_list_tail());
|
||||
tail.set_next_dirty(finalization_group);
|
||||
gc_notify_updated_slot(
|
||||
tail,
|
||||
finalization_group.RawField(JSFinalizationGroup::kNextDirtyOffset),
|
||||
finalization_group);
|
||||
JSFinalizationRegistry tail = JSFinalizationRegistry::cast(
|
||||
dirty_js_finalization_registries_list_tail());
|
||||
tail.set_next_dirty(finalization_registry);
|
||||
gc_notify_updated_slot(tail,
|
||||
finalization_registry.RawField(
|
||||
JSFinalizationRegistry::kNextDirtyOffset),
|
||||
finalization_registry);
|
||||
}
|
||||
set_dirty_js_finalization_groups_list_tail(finalization_group);
|
||||
// dirty_js_finalization_groups_list_tail_ is rescanned by
|
||||
set_dirty_js_finalization_registries_list_tail(finalization_registry);
|
||||
// dirty_js_finalization_registries_list_tail_ is rescanned by
|
||||
// ProcessWeakListRoots.
|
||||
}
|
||||
|
||||
MaybeHandle<JSFinalizationGroup> Heap::DequeueDirtyJSFinalizationGroup() {
|
||||
// Take a FinalizationGroup from the head of the dirty list for fairness.
|
||||
if (HasDirtyJSFinalizationGroups()) {
|
||||
Handle<JSFinalizationGroup> head(
|
||||
JSFinalizationGroup::cast(dirty_js_finalization_groups_list()),
|
||||
MaybeHandle<JSFinalizationRegistry> Heap::DequeueDirtyJSFinalizationRegistry() {
|
||||
// Take a FinalizationRegistry from the head of the dirty list for fairness.
|
||||
if (HasDirtyJSFinalizationRegistries()) {
|
||||
Handle<JSFinalizationRegistry> head(
|
||||
JSFinalizationRegistry::cast(dirty_js_finalization_registries_list()),
|
||||
isolate());
|
||||
set_dirty_js_finalization_groups_list(head->next_dirty());
|
||||
set_dirty_js_finalization_registries_list(head->next_dirty());
|
||||
head->set_next_dirty(ReadOnlyRoots(this).undefined_value());
|
||||
if (*head == dirty_js_finalization_groups_list_tail()) {
|
||||
set_dirty_js_finalization_groups_list_tail(
|
||||
if (*head == dirty_js_finalization_registries_list_tail()) {
|
||||
set_dirty_js_finalization_registries_list_tail(
|
||||
ReadOnlyRoots(this).undefined_value());
|
||||
}
|
||||
return head;
|
||||
@ -6128,7 +6130,7 @@ MaybeHandle<JSFinalizationGroup> Heap::DequeueDirtyJSFinalizationGroup() {
|
||||
return {};
|
||||
}
|
||||
|
||||
void Heap::RemoveDirtyFinalizationGroupsOnContext(NativeContext context) {
|
||||
void Heap::RemoveDirtyFinalizationRegistriesOnContext(NativeContext context) {
|
||||
if (!FLAG_harmony_weak_refs) return;
|
||||
if (isolate()->host_cleanup_finalization_group_callback()) return;
|
||||
|
||||
@ -6136,26 +6138,28 @@ void Heap::RemoveDirtyFinalizationGroupsOnContext(NativeContext context) {
|
||||
|
||||
Isolate* isolate = this->isolate();
|
||||
Object prev = ReadOnlyRoots(isolate).undefined_value();
|
||||
Object current = dirty_js_finalization_groups_list();
|
||||
Object current = dirty_js_finalization_registries_list();
|
||||
while (!current.IsUndefined(isolate)) {
|
||||
JSFinalizationGroup finalization_group = JSFinalizationGroup::cast(current);
|
||||
if (finalization_group.native_context() == context) {
|
||||
JSFinalizationRegistry finalization_registry =
|
||||
JSFinalizationRegistry::cast(current);
|
||||
if (finalization_registry.native_context() == context) {
|
||||
if (prev.IsUndefined(isolate)) {
|
||||
set_dirty_js_finalization_groups_list(finalization_group.next_dirty());
|
||||
set_dirty_js_finalization_registries_list(
|
||||
finalization_registry.next_dirty());
|
||||
} else {
|
||||
JSFinalizationGroup::cast(prev).set_next_dirty(
|
||||
finalization_group.next_dirty());
|
||||
JSFinalizationRegistry::cast(prev).set_next_dirty(
|
||||
finalization_registry.next_dirty());
|
||||
}
|
||||
finalization_group.set_scheduled_for_cleanup(false);
|
||||
current = finalization_group.next_dirty();
|
||||
finalization_group.set_next_dirty(
|
||||
finalization_registry.set_scheduled_for_cleanup(false);
|
||||
current = finalization_registry.next_dirty();
|
||||
finalization_registry.set_next_dirty(
|
||||
ReadOnlyRoots(isolate).undefined_value());
|
||||
} else {
|
||||
prev = current;
|
||||
current = finalization_group.next_dirty();
|
||||
current = finalization_registry.next_dirty();
|
||||
}
|
||||
}
|
||||
set_dirty_js_finalization_groups_list_tail(prev);
|
||||
set_dirty_js_finalization_registries_list_tail(prev);
|
||||
}
|
||||
|
||||
void Heap::KeepDuringJob(Handle<JSReceiver> target) {
|
||||
|
@ -70,7 +70,7 @@ class HeapObjectAllocationTracker;
|
||||
class HeapObjectsFilter;
|
||||
class HeapStats;
|
||||
class Isolate;
|
||||
class JSFinalizationGroup;
|
||||
class JSFinalizationRegistry;
|
||||
class LocalEmbedderHeapTracer;
|
||||
class MemoryAllocator;
|
||||
class MemoryMeasurement;
|
||||
@ -502,17 +502,17 @@ class Heap {
|
||||
}
|
||||
Object allocation_sites_list() { return allocation_sites_list_; }
|
||||
|
||||
void set_dirty_js_finalization_groups_list(Object object) {
|
||||
dirty_js_finalization_groups_list_ = object;
|
||||
void set_dirty_js_finalization_registries_list(Object object) {
|
||||
dirty_js_finalization_registries_list_ = object;
|
||||
}
|
||||
Object dirty_js_finalization_groups_list() {
|
||||
return dirty_js_finalization_groups_list_;
|
||||
Object dirty_js_finalization_registries_list() {
|
||||
return dirty_js_finalization_registries_list_;
|
||||
}
|
||||
void set_dirty_js_finalization_groups_list_tail(Object object) {
|
||||
dirty_js_finalization_groups_list_tail_ = object;
|
||||
void set_dirty_js_finalization_registries_list_tail(Object object) {
|
||||
dirty_js_finalization_registries_list_tail_ = object;
|
||||
}
|
||||
Object dirty_js_finalization_groups_list_tail() {
|
||||
return dirty_js_finalization_groups_list_tail_;
|
||||
Object dirty_js_finalization_registries_list_tail() {
|
||||
return dirty_js_finalization_registries_list_tail_;
|
||||
}
|
||||
|
||||
// Used in CreateAllocationSiteStub and the (de)serializer.
|
||||
@ -813,29 +813,29 @@ class Heap {
|
||||
// See also: FLAG_interpreted_frames_native_stack.
|
||||
void SetInterpreterEntryTrampolineForProfiling(Code code);
|
||||
|
||||
void EnqueueDirtyJSFinalizationGroup(
|
||||
JSFinalizationGroup finalization_group,
|
||||
void EnqueueDirtyJSFinalizationRegistry(
|
||||
JSFinalizationRegistry finalization_registry,
|
||||
std::function<void(HeapObject object, ObjectSlot slot, Object target)>
|
||||
gc_notify_updated_slot);
|
||||
|
||||
MaybeHandle<JSFinalizationGroup> DequeueDirtyJSFinalizationGroup();
|
||||
MaybeHandle<JSFinalizationRegistry> DequeueDirtyJSFinalizationRegistry();
|
||||
|
||||
// Called from Heap::NotifyContextDisposed to remove all FinalizationGroups
|
||||
// with {context} from the dirty list when the context e.g. navigates away or
|
||||
// is detached. If the dirty list is empty afterwards, the cleanup task is
|
||||
// aborted if needed.
|
||||
void RemoveDirtyFinalizationGroupsOnContext(NativeContext context);
|
||||
// Called from Heap::NotifyContextDisposed to remove all
|
||||
// FinalizationRegistries with {context} from the dirty list when the context
|
||||
// e.g. navigates away or is detached. If the dirty list is empty afterwards,
|
||||
// the cleanup task is aborted if needed.
|
||||
void RemoveDirtyFinalizationRegistriesOnContext(NativeContext context);
|
||||
|
||||
inline bool HasDirtyJSFinalizationGroups();
|
||||
inline bool HasDirtyJSFinalizationRegistries();
|
||||
|
||||
void PostFinalizationGroupCleanupTaskIfNeeded();
|
||||
void PostFinalizationRegistryCleanupTaskIfNeeded();
|
||||
|
||||
void set_is_finalization_group_cleanup_task_posted(bool posted) {
|
||||
is_finalization_group_cleanup_task_posted_ = posted;
|
||||
void set_is_finalization_registry_cleanup_task_posted(bool posted) {
|
||||
is_finalization_registry_cleanup_task_posted_ = posted;
|
||||
}
|
||||
|
||||
bool is_finalization_group_cleanup_task_posted() {
|
||||
return is_finalization_group_cleanup_task_posted_;
|
||||
bool is_finalization_registry_cleanup_task_posted() {
|
||||
return is_finalization_registry_cleanup_task_posted_;
|
||||
}
|
||||
|
||||
V8_EXPORT_PRIVATE void KeepDuringJob(Handle<JSReceiver> target);
|
||||
@ -1748,7 +1748,7 @@ class Heap {
|
||||
void ProcessYoungWeakReferences(WeakObjectRetainer* retainer);
|
||||
void ProcessNativeContexts(WeakObjectRetainer* retainer);
|
||||
void ProcessAllocationSites(WeakObjectRetainer* retainer);
|
||||
void ProcessDirtyJSFinalizationGroups(WeakObjectRetainer* retainer);
|
||||
void ProcessDirtyJSFinalizationRegistries(WeakObjectRetainer* retainer);
|
||||
void ProcessWeakListRoots(WeakObjectRetainer* retainer);
|
||||
|
||||
// ===========================================================================
|
||||
@ -2053,9 +2053,9 @@ class Heap {
|
||||
// List heads are initialized lazily and contain the undefined_value at start.
|
||||
Object native_contexts_list_;
|
||||
Object allocation_sites_list_;
|
||||
Object dirty_js_finalization_groups_list_;
|
||||
Object dirty_js_finalization_registries_list_;
|
||||
// Weak list tails.
|
||||
Object dirty_js_finalization_groups_list_tail_;
|
||||
Object dirty_js_finalization_registries_list_tail_;
|
||||
|
||||
std::vector<GCCallbackTuple> gc_epilogue_callbacks_;
|
||||
std::vector<GCCallbackTuple> gc_prologue_callbacks_;
|
||||
@ -2192,7 +2192,7 @@ class Heap {
|
||||
|
||||
std::vector<HeapObjectAllocationTracker*> allocation_trackers_;
|
||||
|
||||
bool is_finalization_group_cleanup_task_posted_ = false;
|
||||
bool is_finalization_registry_cleanup_task_posted_ = false;
|
||||
|
||||
std::unique_ptr<third_party_heap::Heap> tp_heap_;
|
||||
|
||||
|
@ -2494,18 +2494,18 @@ void MarkCompactCollector::ClearJSWeakRefs() {
|
||||
if (!non_atomic_marking_state()->IsBlackOrGrey(target)) {
|
||||
DCHECK(!target.IsUndefined());
|
||||
// The value of the WeakCell is dead.
|
||||
JSFinalizationGroup finalization_group =
|
||||
JSFinalizationGroup::cast(weak_cell.finalization_group());
|
||||
if (!finalization_group.scheduled_for_cleanup()) {
|
||||
heap()->EnqueueDirtyJSFinalizationGroup(finalization_group,
|
||||
gc_notify_updated_slot);
|
||||
JSFinalizationRegistry finalization_registry =
|
||||
JSFinalizationRegistry::cast(weak_cell.finalization_registry());
|
||||
if (!finalization_registry.scheduled_for_cleanup()) {
|
||||
heap()->EnqueueDirtyJSFinalizationRegistry(finalization_registry,
|
||||
gc_notify_updated_slot);
|
||||
}
|
||||
// We're modifying the pointers in WeakCell and JSFinalizationGroup during
|
||||
// GC; thus we need to record the slots it writes. The normal write
|
||||
// We're modifying the pointers in WeakCell and JSFinalizationRegistry
|
||||
// during GC; thus we need to record the slots it writes. The normal write
|
||||
// barrier is not enough, since it's disabled before GC.
|
||||
weak_cell.Nullify(isolate(), gc_notify_updated_slot);
|
||||
DCHECK(finalization_group.NeedsCleanup());
|
||||
DCHECK(finalization_group.scheduled_for_cleanup());
|
||||
DCHECK(finalization_registry.NeedsCleanup());
|
||||
DCHECK(finalization_registry.scheduled_for_cleanup());
|
||||
} else {
|
||||
// The value of the WeakCell is alive.
|
||||
ObjectSlot slot = weak_cell.RawField(WeakCell::kTargetOffset);
|
||||
@ -2521,9 +2521,9 @@ void MarkCompactCollector::ClearJSWeakRefs() {
|
||||
// WeakCell. Like above, we're modifying pointers during GC, so record the
|
||||
// slots.
|
||||
HeapObject undefined = ReadOnlyRoots(isolate()).undefined_value();
|
||||
JSFinalizationGroup finalization_group =
|
||||
JSFinalizationGroup::cast(weak_cell.finalization_group());
|
||||
finalization_group.RemoveUnregisterToken(
|
||||
JSFinalizationRegistry finalization_registry =
|
||||
JSFinalizationRegistry::cast(weak_cell.finalization_registry());
|
||||
finalization_registry.RemoveUnregisterToken(
|
||||
JSReceiver::cast(unregister_token), isolate(),
|
||||
[undefined](WeakCell matched_cell) {
|
||||
matched_cell.set_unregister_token(undefined);
|
||||
@ -2536,7 +2536,7 @@ void MarkCompactCollector::ClearJSWeakRefs() {
|
||||
}
|
||||
}
|
||||
if (!isolate()->host_cleanup_finalization_group_callback()) {
|
||||
heap()->PostFinalizationGroupCleanupTaskIfNeeded();
|
||||
heap()->PostFinalizationRegistryCleanupTaskIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,23 +186,27 @@ struct WeakListVisitor<AllocationSite> {
|
||||
};
|
||||
|
||||
template <>
|
||||
struct WeakListVisitor<JSFinalizationGroup> {
|
||||
static void SetWeakNext(JSFinalizationGroup obj, Object next) {
|
||||
struct WeakListVisitor<JSFinalizationRegistry> {
|
||||
static void SetWeakNext(JSFinalizationRegistry obj, Object next) {
|
||||
obj.set_next_dirty(next, UPDATE_WEAK_WRITE_BARRIER);
|
||||
}
|
||||
|
||||
static Object WeakNext(JSFinalizationGroup obj) { return obj.next_dirty(); }
|
||||
|
||||
static HeapObject WeakNextHolder(JSFinalizationGroup obj) { return obj; }
|
||||
|
||||
static int WeakNextOffset() { return JSFinalizationGroup::kNextDirtyOffset; }
|
||||
|
||||
static void VisitLiveObject(Heap* heap, JSFinalizationGroup obj,
|
||||
WeakObjectRetainer*) {
|
||||
heap->set_dirty_js_finalization_groups_list_tail(obj);
|
||||
static Object WeakNext(JSFinalizationRegistry obj) {
|
||||
return obj.next_dirty();
|
||||
}
|
||||
|
||||
static void VisitPhantomObject(Heap*, JSFinalizationGroup) {}
|
||||
static HeapObject WeakNextHolder(JSFinalizationRegistry obj) { return obj; }
|
||||
|
||||
static int WeakNextOffset() {
|
||||
return JSFinalizationRegistry::kNextDirtyOffset;
|
||||
}
|
||||
|
||||
static void VisitLiveObject(Heap* heap, JSFinalizationRegistry obj,
|
||||
WeakObjectRetainer*) {
|
||||
heap->set_dirty_js_finalization_registries_list_tail(obj);
|
||||
}
|
||||
|
||||
static void VisitPhantomObject(Heap*, JSFinalizationRegistry) {}
|
||||
};
|
||||
|
||||
template Object VisitWeakList<Context>(Heap* heap, Object list,
|
||||
@ -211,7 +215,7 @@ template Object VisitWeakList<Context>(Heap* heap, Object list,
|
||||
template Object VisitWeakList<AllocationSite>(Heap* heap, Object list,
|
||||
WeakObjectRetainer* retainer);
|
||||
|
||||
template Object VisitWeakList<JSFinalizationGroup>(
|
||||
template Object VisitWeakList<JSFinalizationRegistry>(
|
||||
Heap* heap, Object list, WeakObjectRetainer* retainer);
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -67,8 +67,9 @@ bool Heap::CreateHeapObjects() {
|
||||
|
||||
set_native_contexts_list(ReadOnlyRoots(this).undefined_value());
|
||||
set_allocation_sites_list(ReadOnlyRoots(this).undefined_value());
|
||||
set_dirty_js_finalization_groups_list(ReadOnlyRoots(this).undefined_value());
|
||||
set_dirty_js_finalization_groups_list_tail(
|
||||
set_dirty_js_finalization_registries_list(
|
||||
ReadOnlyRoots(this).undefined_value());
|
||||
set_dirty_js_finalization_registries_list_tail(
|
||||
ReadOnlyRoots(this).undefined_value());
|
||||
|
||||
return true;
|
||||
|
@ -4307,44 +4307,46 @@ void Genesis::InitializeGlobal_harmony_weak_refs() {
|
||||
Handle<JSGlobalObject> global(native_context()->global_object(), isolate());
|
||||
|
||||
{
|
||||
// Create %FinalizationGroupPrototype%
|
||||
Handle<String> finalization_group_name =
|
||||
// Create %FinalizationRegistryPrototype%
|
||||
Handle<String> finalization_registry_name =
|
||||
factory->NewStringFromStaticChars("FinalizationGroup");
|
||||
Handle<JSObject> finalization_group_prototype = factory->NewJSObject(
|
||||
Handle<JSObject> finalization_registry_prototype = factory->NewJSObject(
|
||||
isolate()->object_function(), AllocationType::kOld);
|
||||
|
||||
// Create %FinalizationGroup%
|
||||
Handle<JSFunction> finalization_group_fun = CreateFunction(
|
||||
isolate(), finalization_group_name, JS_FINALIZATION_GROUP_TYPE,
|
||||
JSFinalizationGroup::kHeaderSize, 0, finalization_group_prototype,
|
||||
Builtins::kFinalizationGroupConstructor);
|
||||
// Create %FinalizationRegistry%
|
||||
Handle<JSFunction> finalization_registry_fun = CreateFunction(
|
||||
isolate(), finalization_registry_name, JS_FINALIZATION_REGISTRY_TYPE,
|
||||
JSFinalizationRegistry::kHeaderSize, 0, finalization_registry_prototype,
|
||||
Builtins::kFinalizationRegistryConstructor);
|
||||
InstallWithIntrinsicDefaultProto(
|
||||
isolate(), finalization_group_fun,
|
||||
Context::JS_FINALIZATION_GROUP_FUNCTION_INDEX);
|
||||
isolate(), finalization_registry_fun,
|
||||
Context::JS_FINALIZATION_REGISTRY_FUNCTION_INDEX);
|
||||
|
||||
finalization_group_fun->shared().DontAdaptArguments();
|
||||
finalization_group_fun->shared().set_length(1);
|
||||
finalization_registry_fun->shared().DontAdaptArguments();
|
||||
finalization_registry_fun->shared().set_length(1);
|
||||
|
||||
// Install the "constructor" property on the prototype.
|
||||
JSObject::AddProperty(isolate(), finalization_group_prototype,
|
||||
factory->constructor_string(), finalization_group_fun,
|
||||
DONT_ENUM);
|
||||
JSObject::AddProperty(isolate(), finalization_registry_prototype,
|
||||
factory->constructor_string(),
|
||||
finalization_registry_fun, DONT_ENUM);
|
||||
|
||||
InstallToStringTag(isolate(), finalization_group_prototype,
|
||||
finalization_group_name);
|
||||
InstallToStringTag(isolate(), finalization_registry_prototype,
|
||||
finalization_registry_name);
|
||||
|
||||
JSObject::AddProperty(isolate(), global, finalization_group_name,
|
||||
finalization_group_fun, DONT_ENUM);
|
||||
JSObject::AddProperty(isolate(), global, finalization_registry_name,
|
||||
finalization_registry_fun, DONT_ENUM);
|
||||
|
||||
SimpleInstallFunction(isolate(), finalization_group_prototype, "register",
|
||||
Builtins::kFinalizationGroupRegister, 2, false);
|
||||
SimpleInstallFunction(isolate(), finalization_registry_prototype,
|
||||
"register", Builtins::kFinalizationRegistryRegister,
|
||||
2, false);
|
||||
|
||||
SimpleInstallFunction(isolate(), finalization_group_prototype, "unregister",
|
||||
Builtins::kFinalizationGroupUnregister, 1, false);
|
||||
SimpleInstallFunction(isolate(), finalization_registry_prototype,
|
||||
"unregister",
|
||||
Builtins::kFinalizationRegistryUnregister, 1, false);
|
||||
|
||||
SimpleInstallFunction(isolate(), finalization_group_prototype,
|
||||
SimpleInstallFunction(isolate(), finalization_registry_prototype,
|
||||
"cleanupSome",
|
||||
Builtins::kFinalizationGroupCleanupSome, 0, false);
|
||||
Builtins::kFinalizationRegistryCleanupSome, 0, false);
|
||||
}
|
||||
{
|
||||
// Create %WeakRefPrototype%
|
||||
@ -4383,7 +4385,7 @@ void Genesis::InitializeGlobal_harmony_weak_refs() {
|
||||
}
|
||||
|
||||
{
|
||||
// Create cleanup iterator for JSFinalizationGroup.
|
||||
// Create cleanup iterator for JSFinalizationRegistry.
|
||||
Handle<JSObject> iterator_prototype(
|
||||
native_context()->initial_iterator_prototype(), isolate());
|
||||
|
||||
@ -4395,14 +4397,14 @@ void Genesis::InitializeGlobal_harmony_weak_refs() {
|
||||
"FinalizationGroup Cleanup Iterator");
|
||||
|
||||
SimpleInstallFunction(isolate(), cleanup_iterator_prototype, "next",
|
||||
Builtins::kFinalizationGroupCleanupIteratorNext, 0,
|
||||
Builtins::kFinalizationRegistryCleanupIteratorNext, 0,
|
||||
true);
|
||||
Handle<Map> cleanup_iterator_map =
|
||||
factory->NewMap(JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_TYPE,
|
||||
JSFinalizationGroupCleanupIterator::kHeaderSize);
|
||||
factory->NewMap(JS_FINALIZATION_REGISTRY_CLEANUP_ITERATOR_TYPE,
|
||||
JSFinalizationRegistryCleanupIterator::kHeaderSize);
|
||||
Map::SetPrototype(isolate(), cleanup_iterator_map,
|
||||
cleanup_iterator_prototype);
|
||||
native_context()->set_js_finalization_group_cleanup_iterator_map(
|
||||
native_context()->set_js_finalization_registry_cleanup_iterator_map(
|
||||
*cleanup_iterator_map);
|
||||
}
|
||||
}
|
||||
|
@ -989,7 +989,7 @@ class RuntimeCallTimer final {
|
||||
V(DeoptimizeCode) \
|
||||
V(DeserializeContext) \
|
||||
V(DeserializeIsolate) \
|
||||
V(FinalizationGroupCleanupFromTask) \
|
||||
V(FinalizationRegistryCleanupFromTask) \
|
||||
V(FunctionCallback) \
|
||||
V(FunctionLengthGetter) \
|
||||
V(FunctionPrototypeGetter) \
|
||||
|
@ -188,13 +188,13 @@ enum ContextLookupFlags {
|
||||
V(JS_SET_FUN_INDEX, JSFunction, js_set_fun) \
|
||||
V(JS_SET_MAP_INDEX, Map, js_set_map) \
|
||||
V(WEAK_CELL_MAP_INDEX, Map, weak_cell_map) \
|
||||
V(JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_MAP_INDEX, Map, \
|
||||
js_finalization_group_cleanup_iterator_map) \
|
||||
V(JS_FINALIZATION_REGISTRY_CLEANUP_ITERATOR_MAP_INDEX, Map, \
|
||||
js_finalization_registry_cleanup_iterator_map) \
|
||||
V(JS_WEAK_MAP_FUN_INDEX, JSFunction, js_weak_map_fun) \
|
||||
V(JS_WEAK_SET_FUN_INDEX, JSFunction, js_weak_set_fun) \
|
||||
V(JS_WEAK_REF_FUNCTION_INDEX, JSFunction, js_weak_ref_fun) \
|
||||
V(JS_FINALIZATION_GROUP_FUNCTION_INDEX, JSFunction, \
|
||||
js_finalization_group_fun) \
|
||||
V(JS_FINALIZATION_REGISTRY_FUNCTION_INDEX, JSFunction, \
|
||||
js_finalization_registry_fun) \
|
||||
/* Context maps */ \
|
||||
V(NATIVE_CONTEXT_MAP_INDEX, Map, native_context_map) \
|
||||
V(FUNCTION_CONTEXT_MAP_INDEX, Map, function_context_map) \
|
||||
|
@ -2138,10 +2138,10 @@ int JSObject::GetHeaderSize(InstanceType type,
|
||||
return JSMapIterator::kHeaderSize;
|
||||
case JS_WEAK_REF_TYPE:
|
||||
return JSWeakRef::kHeaderSize;
|
||||
case JS_FINALIZATION_GROUP_TYPE:
|
||||
return JSFinalizationGroup::kHeaderSize;
|
||||
case JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_TYPE:
|
||||
return JSFinalizationGroupCleanupIterator::kHeaderSize;
|
||||
case JS_FINALIZATION_REGISTRY_TYPE:
|
||||
return JSFinalizationRegistry::kHeaderSize;
|
||||
case JS_FINALIZATION_REGISTRY_CLEANUP_ITERATOR_TYPE:
|
||||
return JSFinalizationRegistryCleanupIterator::kHeaderSize;
|
||||
case JS_WEAK_MAP_TYPE:
|
||||
return JSWeakMap::kHeaderSize;
|
||||
case JS_WEAK_SET_TYPE:
|
||||
@ -5252,7 +5252,7 @@ bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
|
||||
case JS_MESSAGE_OBJECT_TYPE:
|
||||
case JS_OBJECT_TYPE:
|
||||
case JS_ERROR_TYPE:
|
||||
case JS_FINALIZATION_GROUP_TYPE:
|
||||
case JS_FINALIZATION_REGISTRY_TYPE:
|
||||
case JS_ARGUMENTS_OBJECT_TYPE:
|
||||
case JS_PROMISE_TYPE:
|
||||
case JS_REG_EXP_TYPE:
|
||||
|
@ -19,25 +19,26 @@ namespace internal {
|
||||
|
||||
TQ_OBJECT_CONSTRUCTORS_IMPL(WeakCell)
|
||||
TQ_OBJECT_CONSTRUCTORS_IMPL(JSWeakRef)
|
||||
OBJECT_CONSTRUCTORS_IMPL(JSFinalizationGroup, JSObject)
|
||||
TQ_OBJECT_CONSTRUCTORS_IMPL(JSFinalizationGroupCleanupIterator)
|
||||
OBJECT_CONSTRUCTORS_IMPL(JSFinalizationRegistry, JSObject)
|
||||
TQ_OBJECT_CONSTRUCTORS_IMPL(JSFinalizationRegistryCleanupIterator)
|
||||
|
||||
ACCESSORS(JSFinalizationGroup, native_context, NativeContext,
|
||||
ACCESSORS(JSFinalizationRegistry, native_context, NativeContext,
|
||||
kNativeContextOffset)
|
||||
ACCESSORS(JSFinalizationGroup, cleanup, Object, kCleanupOffset)
|
||||
ACCESSORS(JSFinalizationGroup, active_cells, HeapObject, kActiveCellsOffset)
|
||||
ACCESSORS(JSFinalizationGroup, cleared_cells, HeapObject, kClearedCellsOffset)
|
||||
ACCESSORS(JSFinalizationGroup, key_map, Object, kKeyMapOffset)
|
||||
SMI_ACCESSORS(JSFinalizationGroup, flags, kFlagsOffset)
|
||||
ACCESSORS(JSFinalizationGroup, next_dirty, Object, kNextDirtyOffset)
|
||||
CAST_ACCESSOR(JSFinalizationGroup)
|
||||
ACCESSORS(JSFinalizationRegistry, cleanup, Object, kCleanupOffset)
|
||||
ACCESSORS(JSFinalizationRegistry, active_cells, HeapObject, kActiveCellsOffset)
|
||||
ACCESSORS(JSFinalizationRegistry, cleared_cells, HeapObject,
|
||||
kClearedCellsOffset)
|
||||
ACCESSORS(JSFinalizationRegistry, key_map, Object, kKeyMapOffset)
|
||||
SMI_ACCESSORS(JSFinalizationRegistry, flags, kFlagsOffset)
|
||||
ACCESSORS(JSFinalizationRegistry, next_dirty, Object, kNextDirtyOffset)
|
||||
CAST_ACCESSOR(JSFinalizationRegistry)
|
||||
|
||||
void JSFinalizationGroup::Register(
|
||||
Handle<JSFinalizationGroup> finalization_group, Handle<JSReceiver> target,
|
||||
Handle<Object> holdings, Handle<Object> unregister_token,
|
||||
Isolate* isolate) {
|
||||
void JSFinalizationRegistry::Register(
|
||||
Handle<JSFinalizationRegistry> finalization_registry,
|
||||
Handle<JSReceiver> target, Handle<Object> holdings,
|
||||
Handle<Object> unregister_token, Isolate* isolate) {
|
||||
Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell();
|
||||
weak_cell->set_finalization_group(*finalization_group);
|
||||
weak_cell->set_finalization_registry(*finalization_registry);
|
||||
weak_cell->set_target(*target);
|
||||
weak_cell->set_holdings(*holdings);
|
||||
weak_cell->set_prev(ReadOnlyRoots(isolate).undefined_value());
|
||||
@ -47,19 +48,20 @@ void JSFinalizationGroup::Register(
|
||||
weak_cell->set_key_list_next(ReadOnlyRoots(isolate).undefined_value());
|
||||
|
||||
// Add to active_cells.
|
||||
weak_cell->set_next(finalization_group->active_cells());
|
||||
if (finalization_group->active_cells().IsWeakCell()) {
|
||||
WeakCell::cast(finalization_group->active_cells()).set_prev(*weak_cell);
|
||||
weak_cell->set_next(finalization_registry->active_cells());
|
||||
if (finalization_registry->active_cells().IsWeakCell()) {
|
||||
WeakCell::cast(finalization_registry->active_cells()).set_prev(*weak_cell);
|
||||
}
|
||||
finalization_group->set_active_cells(*weak_cell);
|
||||
finalization_registry->set_active_cells(*weak_cell);
|
||||
|
||||
if (!unregister_token->IsUndefined(isolate)) {
|
||||
Handle<SimpleNumberDictionary> key_map;
|
||||
if (finalization_group->key_map().IsUndefined(isolate)) {
|
||||
if (finalization_registry->key_map().IsUndefined(isolate)) {
|
||||
key_map = SimpleNumberDictionary::New(isolate, 1);
|
||||
} else {
|
||||
key_map = handle(
|
||||
SimpleNumberDictionary::cast(finalization_group->key_map()), isolate);
|
||||
key_map =
|
||||
handle(SimpleNumberDictionary::cast(finalization_registry->key_map()),
|
||||
isolate);
|
||||
}
|
||||
|
||||
// Unregister tokens are held weakly as objects are often their own
|
||||
@ -74,29 +76,29 @@ void JSFinalizationGroup::Register(
|
||||
weak_cell->set_key_list_next(existing_weak_cell);
|
||||
}
|
||||
key_map = SimpleNumberDictionary::Set(isolate, key_map, key, weak_cell);
|
||||
finalization_group->set_key_map(*key_map);
|
||||
finalization_registry->set_key_map(*key_map);
|
||||
}
|
||||
}
|
||||
|
||||
bool JSFinalizationGroup::Unregister(
|
||||
Handle<JSFinalizationGroup> finalization_group,
|
||||
bool JSFinalizationRegistry::Unregister(
|
||||
Handle<JSFinalizationRegistry> finalization_registry,
|
||||
Handle<JSReceiver> unregister_token, Isolate* isolate) {
|
||||
// Iterate through the doubly linked list of WeakCells associated with the
|
||||
// key. Each WeakCell will be in the "active_cells" or "cleared_cells" list of
|
||||
// its FinalizationGroup; remove it from there.
|
||||
return finalization_group->RemoveUnregisterToken(
|
||||
// its FinalizationRegistry; remove it from there.
|
||||
return finalization_registry->RemoveUnregisterToken(
|
||||
*unregister_token, isolate,
|
||||
[isolate](WeakCell matched_cell) {
|
||||
matched_cell.RemoveFromFinalizationGroupCells(isolate);
|
||||
matched_cell.RemoveFromFinalizationRegistryCells(isolate);
|
||||
},
|
||||
[](HeapObject, ObjectSlot, Object) {});
|
||||
}
|
||||
|
||||
template <typename MatchCallback, typename GCNotifyUpdatedSlotCallback>
|
||||
bool JSFinalizationGroup::RemoveUnregisterToken(
|
||||
bool JSFinalizationRegistry::RemoveUnregisterToken(
|
||||
JSReceiver unregister_token, Isolate* isolate, MatchCallback match_callback,
|
||||
GCNotifyUpdatedSlotCallback gc_notify_updated_slot) {
|
||||
// This method is called from both FinalizationGroup#unregister and for
|
||||
// This method is called from both FinalizationRegistry#unregister and for
|
||||
// removing weakly-held dead unregister tokens. The latter is during GC so
|
||||
// this function cannot GC.
|
||||
DisallowHeapAllocation no_gc;
|
||||
@ -169,41 +171,42 @@ bool JSFinalizationGroup::RemoveUnregisterToken(
|
||||
return was_present;
|
||||
}
|
||||
|
||||
bool JSFinalizationGroup::NeedsCleanup() const {
|
||||
bool JSFinalizationRegistry::NeedsCleanup() const {
|
||||
return cleared_cells().IsWeakCell();
|
||||
}
|
||||
|
||||
bool JSFinalizationGroup::scheduled_for_cleanup() const {
|
||||
bool JSFinalizationRegistry::scheduled_for_cleanup() const {
|
||||
return ScheduledForCleanupField::decode(flags());
|
||||
}
|
||||
|
||||
void JSFinalizationGroup::set_scheduled_for_cleanup(
|
||||
void JSFinalizationRegistry::set_scheduled_for_cleanup(
|
||||
bool scheduled_for_cleanup) {
|
||||
set_flags(ScheduledForCleanupField::update(flags(), scheduled_for_cleanup));
|
||||
}
|
||||
|
||||
Object JSFinalizationGroup::PopClearedCellHoldings(
|
||||
Handle<JSFinalizationGroup> finalization_group, Isolate* isolate) {
|
||||
Object JSFinalizationRegistry::PopClearedCellHoldings(
|
||||
Handle<JSFinalizationRegistry> finalization_registry, Isolate* isolate) {
|
||||
Handle<WeakCell> weak_cell =
|
||||
handle(WeakCell::cast(finalization_group->cleared_cells()), isolate);
|
||||
handle(WeakCell::cast(finalization_registry->cleared_cells()), isolate);
|
||||
DCHECK(weak_cell->prev().IsUndefined(isolate));
|
||||
finalization_group->set_cleared_cells(weak_cell->next());
|
||||
finalization_registry->set_cleared_cells(weak_cell->next());
|
||||
weak_cell->set_next(ReadOnlyRoots(isolate).undefined_value());
|
||||
|
||||
if (finalization_group->cleared_cells().IsWeakCell()) {
|
||||
if (finalization_registry->cleared_cells().IsWeakCell()) {
|
||||
WeakCell cleared_cells_head =
|
||||
WeakCell::cast(finalization_group->cleared_cells());
|
||||
WeakCell::cast(finalization_registry->cleared_cells());
|
||||
DCHECK_EQ(cleared_cells_head.prev(), *weak_cell);
|
||||
cleared_cells_head.set_prev(ReadOnlyRoots(isolate).undefined_value());
|
||||
} else {
|
||||
DCHECK(finalization_group->cleared_cells().IsUndefined(isolate));
|
||||
DCHECK(finalization_registry->cleared_cells().IsUndefined(isolate));
|
||||
}
|
||||
|
||||
// Also remove the WeakCell from the key_map (if it's there).
|
||||
if (!weak_cell->unregister_token().IsUndefined(isolate)) {
|
||||
if (weak_cell->key_list_prev().IsUndefined(isolate)) {
|
||||
Handle<SimpleNumberDictionary> key_map = handle(
|
||||
SimpleNumberDictionary::cast(finalization_group->key_map()), isolate);
|
||||
Handle<SimpleNumberDictionary> key_map =
|
||||
handle(SimpleNumberDictionary::cast(finalization_registry->key_map()),
|
||||
isolate);
|
||||
Handle<Object> unregister_token =
|
||||
handle(weak_cell->unregister_token(), isolate);
|
||||
uint32_t key = Smi::ToInt(unregister_token->GetHash());
|
||||
@ -214,7 +217,7 @@ Object JSFinalizationGroup::PopClearedCellHoldings(
|
||||
// from the hash table.
|
||||
DCHECK(entry.is_found());
|
||||
key_map = SimpleNumberDictionary::DeleteEntry(isolate, key_map, entry);
|
||||
finalization_group->set_key_map(*key_map);
|
||||
finalization_registry->set_key_map(*key_map);
|
||||
} else {
|
||||
// weak_cell is the list head for its key; we need to change the value
|
||||
// of the key in the hash table.
|
||||
@ -224,7 +227,7 @@ Object JSFinalizationGroup::PopClearedCellHoldings(
|
||||
next->set_key_list_prev(ReadOnlyRoots(isolate).undefined_value());
|
||||
weak_cell->set_key_list_next(ReadOnlyRoots(isolate).undefined_value());
|
||||
key_map = SimpleNumberDictionary::Set(isolate, key_map, key, next);
|
||||
finalization_group->set_key_map(*key_map);
|
||||
finalization_registry->set_key_map(*key_map);
|
||||
}
|
||||
} else {
|
||||
// weak_cell is somewhere in the middle of its key list.
|
||||
@ -244,25 +247,26 @@ template <typename GCNotifyUpdatedSlotCallback>
|
||||
void WeakCell::Nullify(Isolate* isolate,
|
||||
GCNotifyUpdatedSlotCallback gc_notify_updated_slot) {
|
||||
// Remove from the WeakCell from the "active_cells" list of its
|
||||
// JSFinalizationGroup and insert it into the "cleared_cells" list. This is
|
||||
// JSFinalizationRegistry and insert it into the "cleared_cells" list. This is
|
||||
// only called for WeakCells which haven't been unregistered yet, so they will
|
||||
// be in the active_cells list. (The caller must guard against calling this
|
||||
// for unregistered WeakCells by checking that the target is not undefined.)
|
||||
DCHECK(target().IsJSReceiver());
|
||||
set_target(ReadOnlyRoots(isolate).undefined_value());
|
||||
|
||||
JSFinalizationGroup fg = JSFinalizationGroup::cast(finalization_group());
|
||||
JSFinalizationRegistry fr =
|
||||
JSFinalizationRegistry::cast(finalization_registry());
|
||||
if (prev().IsWeakCell()) {
|
||||
DCHECK_NE(fg.active_cells(), *this);
|
||||
DCHECK_NE(fr.active_cells(), *this);
|
||||
WeakCell prev_cell = WeakCell::cast(prev());
|
||||
prev_cell.set_next(next());
|
||||
gc_notify_updated_slot(prev_cell, prev_cell.RawField(WeakCell::kNextOffset),
|
||||
next());
|
||||
} else {
|
||||
DCHECK_EQ(fg.active_cells(), *this);
|
||||
fg.set_active_cells(next());
|
||||
DCHECK_EQ(fr.active_cells(), *this);
|
||||
fr.set_active_cells(next());
|
||||
gc_notify_updated_slot(
|
||||
fg, fg.RawField(JSFinalizationGroup::kActiveCellsOffset), next());
|
||||
fr, fr.RawField(JSFinalizationRegistry::kActiveCellsOffset), next());
|
||||
}
|
||||
if (next().IsWeakCell()) {
|
||||
WeakCell next_cell = WeakCell::cast(next());
|
||||
@ -272,7 +276,7 @@ void WeakCell::Nullify(Isolate* isolate,
|
||||
}
|
||||
|
||||
set_prev(ReadOnlyRoots(isolate).undefined_value());
|
||||
Object cleared_head = fg.cleared_cells();
|
||||
Object cleared_head = fr.cleared_cells();
|
||||
if (cleared_head.IsWeakCell()) {
|
||||
WeakCell cleared_head_cell = WeakCell::cast(cleared_head);
|
||||
cleared_head_cell.set_prev(*this);
|
||||
@ -280,29 +284,30 @@ void WeakCell::Nullify(Isolate* isolate,
|
||||
cleared_head_cell.RawField(WeakCell::kPrevOffset),
|
||||
*this);
|
||||
}
|
||||
set_next(fg.cleared_cells());
|
||||
set_next(fr.cleared_cells());
|
||||
gc_notify_updated_slot(*this, RawField(WeakCell::kNextOffset), next());
|
||||
fg.set_cleared_cells(*this);
|
||||
fr.set_cleared_cells(*this);
|
||||
gc_notify_updated_slot(
|
||||
fg, fg.RawField(JSFinalizationGroup::kClearedCellsOffset), *this);
|
||||
fr, fr.RawField(JSFinalizationRegistry::kClearedCellsOffset), *this);
|
||||
}
|
||||
|
||||
void WeakCell::RemoveFromFinalizationGroupCells(Isolate* isolate) {
|
||||
void WeakCell::RemoveFromFinalizationRegistryCells(Isolate* isolate) {
|
||||
// Remove the WeakCell from the list it's in (either "active_cells" or
|
||||
// "cleared_cells" of its JSFinalizationGroup).
|
||||
// "cleared_cells" of its JSFinalizationRegistry).
|
||||
|
||||
// It's important to set_target to undefined here. This guards that we won't
|
||||
// call Nullify (which assumes that the WeakCell is in active_cells).
|
||||
DCHECK(target().IsUndefined() || target().IsJSReceiver());
|
||||
set_target(ReadOnlyRoots(isolate).undefined_value());
|
||||
|
||||
JSFinalizationGroup fg = JSFinalizationGroup::cast(finalization_group());
|
||||
if (fg.active_cells() == *this) {
|
||||
JSFinalizationRegistry fr =
|
||||
JSFinalizationRegistry::cast(finalization_registry());
|
||||
if (fr.active_cells() == *this) {
|
||||
DCHECK(prev().IsUndefined(isolate));
|
||||
fg.set_active_cells(next());
|
||||
} else if (fg.cleared_cells() == *this) {
|
||||
fr.set_active_cells(next());
|
||||
} else if (fr.cleared_cells() == *this) {
|
||||
DCHECK(!prev().IsWeakCell());
|
||||
fg.set_cleared_cells(next());
|
||||
fr.set_cleared_cells(next());
|
||||
} else {
|
||||
DCHECK(prev().IsWeakCell());
|
||||
WeakCell prev_cell = WeakCell::cast(prev());
|
||||
|
@ -16,13 +16,13 @@ namespace internal {
|
||||
class NativeContext;
|
||||
class WeakCell;
|
||||
|
||||
// FinalizationGroup object from the JS Weak Refs spec proposal:
|
||||
// FinalizationRegistry object from the JS Weak Refs spec proposal:
|
||||
// https://github.com/tc39/proposal-weakrefs
|
||||
class JSFinalizationGroup : public JSObject {
|
||||
class JSFinalizationRegistry : public JSObject {
|
||||
public:
|
||||
DECL_PRINTER(JSFinalizationGroup)
|
||||
EXPORT_DECL_VERIFIER(JSFinalizationGroup)
|
||||
DECL_CAST(JSFinalizationGroup)
|
||||
DECL_PRINTER(JSFinalizationRegistry)
|
||||
EXPORT_DECL_VERIFIER(JSFinalizationRegistry)
|
||||
DECL_CAST(JSFinalizationRegistry)
|
||||
|
||||
DECL_ACCESSORS(native_context, NativeContext)
|
||||
DECL_ACCESSORS(cleanup, Object)
|
||||
@ -37,13 +37,13 @@ class JSFinalizationGroup : public JSObject {
|
||||
|
||||
class BodyDescriptor;
|
||||
|
||||
inline static void Register(Handle<JSFinalizationGroup> finalization_group,
|
||||
Handle<JSReceiver> target,
|
||||
Handle<Object> holdings, Handle<Object> key,
|
||||
Isolate* isolate);
|
||||
inline static bool Unregister(Handle<JSFinalizationGroup> finalization_group,
|
||||
Handle<JSReceiver> unregister_token,
|
||||
Isolate* isolate);
|
||||
inline static void Register(
|
||||
Handle<JSFinalizationRegistry> finalization_registry,
|
||||
Handle<JSReceiver> target, Handle<Object> holdings, Handle<Object> key,
|
||||
Isolate* isolate);
|
||||
inline static bool Unregister(
|
||||
Handle<JSFinalizationRegistry> finalization_registry,
|
||||
Handle<JSReceiver> unregister_token, Isolate* isolate);
|
||||
|
||||
// RemoveUnregisterToken is called from both Unregister and during GC. Since
|
||||
// it modifies slots in key_map and WeakCells and the normal write barrier is
|
||||
@ -64,27 +64,27 @@ class JSFinalizationGroup : public JSObject {
|
||||
// Remove the first cleared WeakCell from the cleared_cells
|
||||
// list (assumes there is one) and return its holdings.
|
||||
inline static Object PopClearedCellHoldings(
|
||||
Handle<JSFinalizationGroup> finalization_group, Isolate* isolate);
|
||||
Handle<JSFinalizationRegistry> finalization_registry, Isolate* isolate);
|
||||
|
||||
// Constructs an iterator for the WeakCells in the cleared_cells list and
|
||||
// calls the user's cleanup function.
|
||||
//
|
||||
// Returns Nothing<bool> if exception occurs, otherwise returns Just(true).
|
||||
static V8_WARN_UNUSED_RESULT Maybe<bool> Cleanup(
|
||||
Isolate* isolate, Handle<JSFinalizationGroup> finalization_group,
|
||||
Isolate* isolate, Handle<JSFinalizationRegistry> finalization_registry,
|
||||
Handle<Object> callback);
|
||||
|
||||
// Layout description.
|
||||
DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize,
|
||||
TORQUE_GENERATED_JS_FINALIZATION_GROUP_FIELDS)
|
||||
DEFINE_FIELD_OFFSET_CONSTANTS(
|
||||
JSObject::kHeaderSize, TORQUE_GENERATED_JS_FINALIZATION_REGISTRY_FIELDS)
|
||||
|
||||
// Bitfields in flags.
|
||||
using ScheduledForCleanupField = base::BitField<bool, 0, 1>;
|
||||
|
||||
OBJECT_CONSTRUCTORS(JSFinalizationGroup, JSObject);
|
||||
OBJECT_CONSTRUCTORS(JSFinalizationRegistry, JSObject);
|
||||
};
|
||||
|
||||
// Internal object for storing weak references in JSFinalizationGroup.
|
||||
// Internal object for storing weak references in JSFinalizationRegistry.
|
||||
class WeakCell : public TorqueGeneratedWeakCell<WeakCell, HeapObject> {
|
||||
public:
|
||||
DECL_PRINTER(WeakCell)
|
||||
@ -93,14 +93,14 @@ class WeakCell : public TorqueGeneratedWeakCell<WeakCell, HeapObject> {
|
||||
class BodyDescriptor;
|
||||
|
||||
// Nullify is called during GC and it modifies the pointers in WeakCell and
|
||||
// JSFinalizationGroup. Thus we need to tell the GC about the modified slots
|
||||
// via the gc_notify_updated_slot function. The normal write barrier is not
|
||||
// enough, since it's disabled before GC.
|
||||
// JSFinalizationRegistry. Thus we need to tell the GC about the modified
|
||||
// slots via the gc_notify_updated_slot function. The normal write barrier is
|
||||
// not enough, since it's disabled before GC.
|
||||
template <typename GCNotifyUpdatedSlotCallback>
|
||||
inline void Nullify(Isolate* isolate,
|
||||
GCNotifyUpdatedSlotCallback gc_notify_updated_slot);
|
||||
|
||||
inline void RemoveFromFinalizationGroupCells(Isolate* isolate);
|
||||
inline void RemoveFromFinalizationRegistryCells(Isolate* isolate);
|
||||
|
||||
TQ_OBJECT_CONSTRUCTORS(WeakCell)
|
||||
};
|
||||
@ -115,14 +115,14 @@ class JSWeakRef : public TorqueGeneratedJSWeakRef<JSWeakRef, JSObject> {
|
||||
TQ_OBJECT_CONSTRUCTORS(JSWeakRef)
|
||||
};
|
||||
|
||||
class JSFinalizationGroupCleanupIterator
|
||||
: public TorqueGeneratedJSFinalizationGroupCleanupIterator<
|
||||
JSFinalizationGroupCleanupIterator, JSObject> {
|
||||
class JSFinalizationRegistryCleanupIterator
|
||||
: public TorqueGeneratedJSFinalizationRegistryCleanupIterator<
|
||||
JSFinalizationRegistryCleanupIterator, JSObject> {
|
||||
public:
|
||||
DECL_PRINTER(JSFinalizationGroupCleanupIterator)
|
||||
DECL_VERIFIER(JSFinalizationGroupCleanupIterator)
|
||||
DECL_PRINTER(JSFinalizationRegistryCleanupIterator)
|
||||
DECL_VERIFIER(JSFinalizationRegistryCleanupIterator)
|
||||
|
||||
TQ_OBJECT_CONSTRUCTORS(JSFinalizationGroupCleanupIterator)
|
||||
TQ_OBJECT_CONSTRUCTORS(JSFinalizationRegistryCleanupIterator)
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
@ -2,39 +2,39 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
extern class JSFinalizationGroup extends JSObject {
|
||||
extern class JSFinalizationRegistry extends JSObject {
|
||||
native_context: NativeContext;
|
||||
cleanup: Object;
|
||||
active_cells: Undefined|WeakCell;
|
||||
cleared_cells: Undefined|WeakCell;
|
||||
key_map: Object;
|
||||
// For the linked list of FinalizationGroups that need cleanup. This link
|
||||
// is weak.
|
||||
next_dirty: Undefined|JSFinalizationGroup;
|
||||
// For the linked list of FinalizationRegistries that need cleanup. This
|
||||
// link is weak.
|
||||
next_dirty: Undefined|JSFinalizationRegistry;
|
||||
flags: Smi;
|
||||
}
|
||||
|
||||
@generateCppClass
|
||||
extern class JSFinalizationGroupCleanupIterator extends JSObject {
|
||||
finalization_group: JSFinalizationGroup;
|
||||
extern class JSFinalizationRegistryCleanupIterator extends JSObject {
|
||||
finalization_registry: JSFinalizationRegistry;
|
||||
}
|
||||
|
||||
@generateCppClass
|
||||
extern class WeakCell extends HeapObject {
|
||||
finalization_group: Undefined|JSFinalizationGroup;
|
||||
finalization_registry: Undefined|JSFinalizationRegistry;
|
||||
target: Undefined|JSReceiver;
|
||||
unregister_token: Object;
|
||||
holdings: Object;
|
||||
|
||||
// For storing doubly linked lists of WeakCells in JSFinalizationGroup's
|
||||
// For storing doubly linked lists of WeakCells in JSFinalizationRegistry's
|
||||
// "active_cells" and "cleared_cells" lists.
|
||||
prev: Undefined|WeakCell;
|
||||
next: Undefined|WeakCell;
|
||||
|
||||
// For storing doubly linked lists of WeakCells per key in
|
||||
// JSFinalizationGroup's key-based hashmap. The key is the identity hash of
|
||||
// unregister_token. WeakCell also needs to know its token, so that we can
|
||||
// remove its corresponding key from the key_map when we remove the last
|
||||
// JSFinalizationRegistry's key-based hashmap. The key is the identity hash
|
||||
// of unregister_token. WeakCell also needs to know its token, so that we
|
||||
// can remove its corresponding key from the key_map when we remove the last
|
||||
// WeakCell associated with it or when the unregister_token dies. The
|
||||
// unregister token is stored above, after target, as both are weak.
|
||||
key_list_prev: Undefined|WeakCell;
|
||||
|
@ -288,8 +288,8 @@ VisitorId Map::GetVisitorId(Map map) {
|
||||
case JS_PROMISE_TYPE:
|
||||
case JS_REG_EXP_TYPE:
|
||||
case JS_REG_EXP_STRING_ITERATOR_TYPE:
|
||||
case JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_TYPE:
|
||||
case JS_FINALIZATION_GROUP_TYPE:
|
||||
case JS_FINALIZATION_REGISTRY_CLEANUP_ITERATOR_TYPE:
|
||||
case JS_FINALIZATION_REGISTRY_TYPE:
|
||||
#ifdef V8_INTL_SUPPORT
|
||||
case JS_V8_BREAK_ITERATOR_TYPE:
|
||||
case JS_COLLATOR_TYPE:
|
||||
|
@ -140,8 +140,8 @@ class ZoneForwardList;
|
||||
V(JSDataView) \
|
||||
V(JSDate) \
|
||||
V(JSError) \
|
||||
V(JSFinalizationGroup) \
|
||||
V(JSFinalizationGroupCleanupIterator) \
|
||||
V(JSFinalizationRegistry) \
|
||||
V(JSFinalizationRegistryCleanupIterator) \
|
||||
V(JSFunction) \
|
||||
V(JSFunctionOrBoundFunction) \
|
||||
V(JSGeneratorObject) \
|
||||
|
@ -248,7 +248,7 @@ class JSWeakRef::BodyDescriptor final : public BodyDescriptorBase {
|
||||
}
|
||||
};
|
||||
|
||||
class JSFinalizationGroup::BodyDescriptor final : public BodyDescriptorBase {
|
||||
class JSFinalizationRegistry::BodyDescriptor final : public BodyDescriptorBase {
|
||||
public:
|
||||
static bool IsValidSlot(Map map, HeapObject obj, int offset) {
|
||||
return IsValidJSObjectSlotImpl(map, obj, offset);
|
||||
@ -979,8 +979,8 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) {
|
||||
case JS_SPECIAL_API_OBJECT_TYPE:
|
||||
case JS_MESSAGE_OBJECT_TYPE:
|
||||
case JS_BOUND_FUNCTION_TYPE:
|
||||
case JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_TYPE:
|
||||
case JS_FINALIZATION_GROUP_TYPE:
|
||||
case JS_FINALIZATION_REGISTRY_CLEANUP_ITERATOR_TYPE:
|
||||
case JS_FINALIZATION_REGISTRY_TYPE:
|
||||
#ifdef V8_INTL_SUPPORT
|
||||
case JS_V8_BREAK_ITERATOR_TYPE:
|
||||
case JS_COLLATOR_TYPE:
|
||||
|
@ -8194,35 +8194,36 @@ HashTable<NameDictionary, NameDictionaryShape>::Shrink(Isolate* isolate,
|
||||
template void HashTable<GlobalDictionary, GlobalDictionaryShape>::Rehash(
|
||||
ReadOnlyRoots roots);
|
||||
|
||||
Maybe<bool> JSFinalizationGroup::Cleanup(
|
||||
Isolate* isolate, Handle<JSFinalizationGroup> finalization_group,
|
||||
Maybe<bool> JSFinalizationRegistry::Cleanup(
|
||||
Isolate* isolate, Handle<JSFinalizationRegistry> finalization_registry,
|
||||
Handle<Object> cleanup) {
|
||||
DCHECK(cleanup->IsCallable());
|
||||
// Attempt to shrink key_map now, as unregister tokens are held weakly and the
|
||||
// map is not shrinkable when sweeping dead tokens during GC itself.
|
||||
if (!finalization_group->key_map().IsUndefined(isolate)) {
|
||||
Handle<SimpleNumberDictionary> key_map = handle(
|
||||
SimpleNumberDictionary::cast(finalization_group->key_map()), isolate);
|
||||
if (!finalization_registry->key_map().IsUndefined(isolate)) {
|
||||
Handle<SimpleNumberDictionary> key_map =
|
||||
handle(SimpleNumberDictionary::cast(finalization_registry->key_map()),
|
||||
isolate);
|
||||
key_map = SimpleNumberDictionary::Shrink(isolate, key_map);
|
||||
finalization_group->set_key_map(*key_map);
|
||||
finalization_registry->set_key_map(*key_map);
|
||||
}
|
||||
|
||||
// It's possible that the cleared_cells list is empty, since
|
||||
// FinalizationGroup.unregister() removed all its elements before this task
|
||||
// FinalizationRegistry.unregister() removed all its elements before this task
|
||||
// ran. In that case, don't call the cleanup function.
|
||||
if (!finalization_group->cleared_cells().IsUndefined(isolate)) {
|
||||
if (!finalization_registry->cleared_cells().IsUndefined(isolate)) {
|
||||
// Construct the iterator.
|
||||
Handle<JSFinalizationGroupCleanupIterator> iterator;
|
||||
Handle<JSFinalizationRegistryCleanupIterator> iterator;
|
||||
{
|
||||
Handle<Map> cleanup_iterator_map(
|
||||
isolate->native_context()
|
||||
->js_finalization_group_cleanup_iterator_map(),
|
||||
->js_finalization_registry_cleanup_iterator_map(),
|
||||
isolate);
|
||||
iterator = Handle<JSFinalizationGroupCleanupIterator>::cast(
|
||||
iterator = Handle<JSFinalizationRegistryCleanupIterator>::cast(
|
||||
isolate->factory()->NewJSObjectFromMap(
|
||||
cleanup_iterator_map, AllocationType::kYoung,
|
||||
Handle<AllocationSite>::null()));
|
||||
iterator->set_finalization_group(*finalization_group);
|
||||
iterator->set_finalization_registry(*finalization_registry);
|
||||
}
|
||||
Handle<Object> args[] = {iterator};
|
||||
if (Execution::Call(
|
||||
|
@ -54,9 +54,9 @@ void StartupDeserializer::DeserializeInto(Isolate* isolate) {
|
||||
isolate->heap()->set_allocation_sites_list(
|
||||
ReadOnlyRoots(isolate).undefined_value());
|
||||
}
|
||||
isolate->heap()->set_dirty_js_finalization_groups_list(
|
||||
isolate->heap()->set_dirty_js_finalization_registries_list(
|
||||
ReadOnlyRoots(isolate).undefined_value());
|
||||
isolate->heap()->set_dirty_js_finalization_groups_list_tail(
|
||||
isolate->heap()->set_dirty_js_finalization_registries_list_tail(
|
||||
ReadOnlyRoots(isolate).undefined_value());
|
||||
|
||||
isolate->builtins()->MarkInitialized();
|
||||
|
@ -169,12 +169,13 @@ void StartupSerializer::SerializeUsingPartialSnapshotCache(
|
||||
sink->PutInt(cache_index, "partial_snapshot_cache_index");
|
||||
}
|
||||
|
||||
void StartupSerializer::CheckNoDirtyFinalizationGroups() {
|
||||
void StartupSerializer::CheckNoDirtyFinalizationRegistries() {
|
||||
Isolate* isolate = this->isolate();
|
||||
CHECK(isolate->heap()->dirty_js_finalization_groups_list().IsUndefined(
|
||||
isolate));
|
||||
CHECK(isolate->heap()->dirty_js_finalization_groups_list_tail().IsUndefined(
|
||||
CHECK(isolate->heap()->dirty_js_finalization_registries_list().IsUndefined(
|
||||
isolate));
|
||||
CHECK(
|
||||
isolate->heap()->dirty_js_finalization_registries_list_tail().IsUndefined(
|
||||
isolate));
|
||||
}
|
||||
|
||||
void SerializedHandleChecker::AddToSet(FixedArray serialized) {
|
||||
|
@ -41,9 +41,9 @@ class V8_EXPORT_PRIVATE StartupSerializer : public RootsSerializer {
|
||||
void SerializeUsingPartialSnapshotCache(SnapshotByteSink* sink,
|
||||
HeapObject obj);
|
||||
|
||||
// The per-heap dirty FinalizationGroup list is weak and not serialized. No
|
||||
// JSFinalizationGroups should be used during startup.
|
||||
void CheckNoDirtyFinalizationGroups();
|
||||
// The per-heap dirty FinalizationRegistry list is weak and not serialized. No
|
||||
// JSFinalizationRegistries should be used during startup.
|
||||
void CheckNoDirtyFinalizationRegistries();
|
||||
|
||||
private:
|
||||
void SerializeObject(HeapObject o) override;
|
||||
|
@ -16,23 +16,24 @@ namespace internal {
|
||||
|
||||
namespace {
|
||||
|
||||
Handle<JSFinalizationGroup> ConstructJSFinalizationGroup(Isolate* isolate) {
|
||||
Handle<JSFinalizationRegistry> ConstructJSFinalizationRegistry(
|
||||
Isolate* isolate) {
|
||||
Factory* factory = isolate->factory();
|
||||
Handle<String> finalization_group_name =
|
||||
Handle<String> finalization_registry_name =
|
||||
factory->NewStringFromStaticChars("FinalizationGroup");
|
||||
Handle<Object> global =
|
||||
handle(isolate->native_context()->global_object(), isolate);
|
||||
Handle<JSFunction> finalization_group_fun = Handle<JSFunction>::cast(
|
||||
Object::GetProperty(isolate, global, finalization_group_name)
|
||||
Handle<JSFunction> finalization_registry_fun = Handle<JSFunction>::cast(
|
||||
Object::GetProperty(isolate, global, finalization_registry_name)
|
||||
.ToHandleChecked());
|
||||
auto finalization_group = Handle<JSFinalizationGroup>::cast(
|
||||
JSObject::New(finalization_group_fun, finalization_group_fun,
|
||||
auto finalization_registry = Handle<JSFinalizationRegistry>::cast(
|
||||
JSObject::New(finalization_registry_fun, finalization_registry_fun,
|
||||
Handle<AllocationSite>::null())
|
||||
.ToHandleChecked());
|
||||
#ifdef VERIFY_HEAP
|
||||
finalization_group->JSFinalizationGroupVerify(isolate);
|
||||
finalization_registry->JSFinalizationRegistryVerify(isolate);
|
||||
#endif // VERIFY_HEAP
|
||||
return finalization_group;
|
||||
return finalization_registry;
|
||||
}
|
||||
|
||||
Handle<JSWeakRef> ConstructJSWeakRef(Handle<JSReceiver> target,
|
||||
@ -64,27 +65,28 @@ Handle<JSObject> CreateKey(const char* key_prop_value, Isolate* isolate) {
|
||||
return key;
|
||||
}
|
||||
|
||||
Handle<WeakCell> FinalizationGroupRegister(
|
||||
Handle<JSFinalizationGroup> finalization_group, Handle<JSObject> target,
|
||||
Handle<Object> holdings, Handle<Object> key, Isolate* isolate) {
|
||||
JSFinalizationGroup::Register(finalization_group, target, holdings, key,
|
||||
isolate);
|
||||
CHECK(finalization_group->active_cells().IsWeakCell());
|
||||
Handle<WeakCell> FinalizationRegistryRegister(
|
||||
Handle<JSFinalizationRegistry> finalization_registry,
|
||||
Handle<JSObject> target, Handle<Object> holdings, Handle<Object> key,
|
||||
Isolate* isolate) {
|
||||
JSFinalizationRegistry::Register(finalization_registry, target, holdings, key,
|
||||
isolate);
|
||||
CHECK(finalization_registry->active_cells().IsWeakCell());
|
||||
Handle<WeakCell> weak_cell =
|
||||
handle(WeakCell::cast(finalization_group->active_cells()), isolate);
|
||||
handle(WeakCell::cast(finalization_registry->active_cells()), isolate);
|
||||
#ifdef VERIFY_HEAP
|
||||
weak_cell->WeakCellVerify(isolate);
|
||||
#endif // VERIFY_HEAP
|
||||
return weak_cell;
|
||||
}
|
||||
|
||||
Handle<WeakCell> FinalizationGroupRegister(
|
||||
Handle<JSFinalizationGroup> finalization_group, Handle<JSObject> target,
|
||||
Isolate* isolate) {
|
||||
Handle<WeakCell> FinalizationRegistryRegister(
|
||||
Handle<JSFinalizationRegistry> finalization_registry,
|
||||
Handle<JSObject> target, Isolate* isolate) {
|
||||
Handle<Object> undefined =
|
||||
handle(ReadOnlyRoots(isolate).undefined_value(), isolate);
|
||||
return FinalizationGroupRegister(finalization_group, target, undefined,
|
||||
undefined, isolate);
|
||||
return FinalizationRegistryRegister(finalization_registry, target, undefined,
|
||||
undefined, isolate);
|
||||
}
|
||||
|
||||
void NullifyWeakCell(Handle<WeakCell> weak_cell, Isolate* isolate) {
|
||||
@ -177,36 +179,36 @@ TEST(TestRegister) {
|
||||
LocalContext context;
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
HandleScope outer_scope(isolate);
|
||||
Handle<JSFinalizationGroup> finalization_group =
|
||||
ConstructJSFinalizationGroup(isolate);
|
||||
Handle<JSFinalizationRegistry> finalization_registry =
|
||||
ConstructJSFinalizationRegistry(isolate);
|
||||
Handle<JSObject> js_object =
|
||||
isolate->factory()->NewJSObject(isolate->object_function());
|
||||
|
||||
// Register a weak reference and verify internal data structures.
|
||||
Handle<WeakCell> weak_cell1 =
|
||||
FinalizationGroupRegister(finalization_group, js_object, isolate);
|
||||
FinalizationRegistryRegister(finalization_registry, js_object, isolate);
|
||||
|
||||
VerifyWeakCellChain(isolate, finalization_group->active_cells(), 1,
|
||||
VerifyWeakCellChain(isolate, finalization_registry->active_cells(), 1,
|
||||
*weak_cell1);
|
||||
CHECK(weak_cell1->key_list_prev().IsUndefined(isolate));
|
||||
CHECK(weak_cell1->key_list_next().IsUndefined(isolate));
|
||||
|
||||
CHECK(finalization_group->cleared_cells().IsUndefined(isolate));
|
||||
CHECK(finalization_registry->cleared_cells().IsUndefined(isolate));
|
||||
|
||||
// No key was used during registration, key-based map stays uninitialized.
|
||||
CHECK(finalization_group->key_map().IsUndefined(isolate));
|
||||
CHECK(finalization_registry->key_map().IsUndefined(isolate));
|
||||
|
||||
// Register another weak reference and verify internal data structures.
|
||||
Handle<WeakCell> weak_cell2 =
|
||||
FinalizationGroupRegister(finalization_group, js_object, isolate);
|
||||
FinalizationRegistryRegister(finalization_registry, js_object, isolate);
|
||||
|
||||
VerifyWeakCellChain(isolate, finalization_group->active_cells(), 2,
|
||||
VerifyWeakCellChain(isolate, finalization_registry->active_cells(), 2,
|
||||
*weak_cell2, *weak_cell1);
|
||||
CHECK(weak_cell2->key_list_prev().IsUndefined(isolate));
|
||||
CHECK(weak_cell2->key_list_next().IsUndefined(isolate));
|
||||
|
||||
CHECK(finalization_group->cleared_cells().IsUndefined(isolate));
|
||||
CHECK(finalization_group->key_map().IsUndefined(isolate));
|
||||
CHECK(finalization_registry->cleared_cells().IsUndefined(isolate));
|
||||
CHECK(finalization_registry->key_map().IsUndefined(isolate));
|
||||
}
|
||||
|
||||
TEST(TestRegisterWithKey) {
|
||||
@ -215,8 +217,8 @@ TEST(TestRegisterWithKey) {
|
||||
LocalContext context;
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
HandleScope outer_scope(isolate);
|
||||
Handle<JSFinalizationGroup> finalization_group =
|
||||
ConstructJSFinalizationGroup(isolate);
|
||||
Handle<JSFinalizationRegistry> finalization_registry =
|
||||
ConstructJSFinalizationRegistry(isolate);
|
||||
Handle<JSObject> js_object =
|
||||
isolate->factory()->NewJSObject(isolate->object_function());
|
||||
|
||||
@ -226,36 +228,36 @@ TEST(TestRegisterWithKey) {
|
||||
handle(ReadOnlyRoots(isolate).undefined_value(), isolate);
|
||||
|
||||
// Register a weak reference with a key and verify internal data structures.
|
||||
Handle<WeakCell> weak_cell1 = FinalizationGroupRegister(
|
||||
finalization_group, js_object, undefined, token1, isolate);
|
||||
Handle<WeakCell> weak_cell1 = FinalizationRegistryRegister(
|
||||
finalization_registry, js_object, undefined, token1, isolate);
|
||||
|
||||
{
|
||||
SimpleNumberDictionary key_map =
|
||||
SimpleNumberDictionary::cast(finalization_group->key_map());
|
||||
SimpleNumberDictionary::cast(finalization_registry->key_map());
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token1, 1, *weak_cell1);
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token2, 0);
|
||||
}
|
||||
|
||||
// Register another weak reference with a different key and verify internal
|
||||
// data structures.
|
||||
Handle<WeakCell> weak_cell2 = FinalizationGroupRegister(
|
||||
finalization_group, js_object, undefined, token2, isolate);
|
||||
Handle<WeakCell> weak_cell2 = FinalizationRegistryRegister(
|
||||
finalization_registry, js_object, undefined, token2, isolate);
|
||||
|
||||
{
|
||||
SimpleNumberDictionary key_map =
|
||||
SimpleNumberDictionary::cast(finalization_group->key_map());
|
||||
SimpleNumberDictionary::cast(finalization_registry->key_map());
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token1, 1, *weak_cell1);
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token2, 1, *weak_cell2);
|
||||
}
|
||||
|
||||
// Register another weak reference with token1 and verify internal data
|
||||
// structures.
|
||||
Handle<WeakCell> weak_cell3 = FinalizationGroupRegister(
|
||||
finalization_group, js_object, undefined, token1, isolate);
|
||||
Handle<WeakCell> weak_cell3 = FinalizationRegistryRegister(
|
||||
finalization_registry, js_object, undefined, token1, isolate);
|
||||
|
||||
{
|
||||
SimpleNumberDictionary key_map =
|
||||
SimpleNumberDictionary::cast(finalization_group->key_map());
|
||||
SimpleNumberDictionary::cast(finalization_registry->key_map());
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token1, 2, *weak_cell3,
|
||||
*weak_cell1);
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token2, 1, *weak_cell2);
|
||||
@ -268,29 +270,29 @@ TEST(TestWeakCellNullify1) {
|
||||
LocalContext context;
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
HandleScope outer_scope(isolate);
|
||||
Handle<JSFinalizationGroup> finalization_group =
|
||||
ConstructJSFinalizationGroup(isolate);
|
||||
Handle<JSFinalizationRegistry> finalization_registry =
|
||||
ConstructJSFinalizationRegistry(isolate);
|
||||
Handle<JSObject> js_object =
|
||||
isolate->factory()->NewJSObject(isolate->object_function());
|
||||
|
||||
Handle<WeakCell> weak_cell1 =
|
||||
FinalizationGroupRegister(finalization_group, js_object, isolate);
|
||||
FinalizationRegistryRegister(finalization_registry, js_object, isolate);
|
||||
Handle<WeakCell> weak_cell2 =
|
||||
FinalizationGroupRegister(finalization_group, js_object, isolate);
|
||||
FinalizationRegistryRegister(finalization_registry, js_object, isolate);
|
||||
|
||||
// Nullify the first WeakCell and verify internal data structures.
|
||||
NullifyWeakCell(weak_cell1, isolate);
|
||||
CHECK_EQ(finalization_group->active_cells(), *weak_cell2);
|
||||
CHECK_EQ(finalization_registry->active_cells(), *weak_cell2);
|
||||
CHECK(weak_cell2->prev().IsUndefined(isolate));
|
||||
CHECK(weak_cell2->next().IsUndefined(isolate));
|
||||
CHECK_EQ(finalization_group->cleared_cells(), *weak_cell1);
|
||||
CHECK_EQ(finalization_registry->cleared_cells(), *weak_cell1);
|
||||
CHECK(weak_cell1->prev().IsUndefined(isolate));
|
||||
CHECK(weak_cell1->next().IsUndefined(isolate));
|
||||
|
||||
// Nullify the second WeakCell and verify internal data structures.
|
||||
NullifyWeakCell(weak_cell2, isolate);
|
||||
CHECK(finalization_group->active_cells().IsUndefined(isolate));
|
||||
CHECK_EQ(finalization_group->cleared_cells(), *weak_cell2);
|
||||
CHECK(finalization_registry->active_cells().IsUndefined(isolate));
|
||||
CHECK_EQ(finalization_registry->cleared_cells(), *weak_cell2);
|
||||
CHECK_EQ(weak_cell2->next(), *weak_cell1);
|
||||
CHECK(weak_cell2->prev().IsUndefined(isolate));
|
||||
CHECK_EQ(weak_cell1->prev(), *weak_cell2);
|
||||
@ -303,92 +305,92 @@ TEST(TestWeakCellNullify2) {
|
||||
LocalContext context;
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
HandleScope outer_scope(isolate);
|
||||
Handle<JSFinalizationGroup> finalization_group =
|
||||
ConstructJSFinalizationGroup(isolate);
|
||||
Handle<JSFinalizationRegistry> finalization_registry =
|
||||
ConstructJSFinalizationRegistry(isolate);
|
||||
Handle<JSObject> js_object =
|
||||
isolate->factory()->NewJSObject(isolate->object_function());
|
||||
|
||||
Handle<WeakCell> weak_cell1 =
|
||||
FinalizationGroupRegister(finalization_group, js_object, isolate);
|
||||
FinalizationRegistryRegister(finalization_registry, js_object, isolate);
|
||||
Handle<WeakCell> weak_cell2 =
|
||||
FinalizationGroupRegister(finalization_group, js_object, isolate);
|
||||
FinalizationRegistryRegister(finalization_registry, js_object, isolate);
|
||||
|
||||
// Like TestWeakCellNullify1 but nullify the WeakCells in opposite order.
|
||||
NullifyWeakCell(weak_cell2, isolate);
|
||||
CHECK_EQ(finalization_group->active_cells(), *weak_cell1);
|
||||
CHECK_EQ(finalization_registry->active_cells(), *weak_cell1);
|
||||
CHECK(weak_cell1->prev().IsUndefined(isolate));
|
||||
CHECK(weak_cell1->next().IsUndefined(isolate));
|
||||
CHECK_EQ(finalization_group->cleared_cells(), *weak_cell2);
|
||||
CHECK_EQ(finalization_registry->cleared_cells(), *weak_cell2);
|
||||
CHECK(weak_cell2->prev().IsUndefined(isolate));
|
||||
CHECK(weak_cell2->next().IsUndefined(isolate));
|
||||
|
||||
NullifyWeakCell(weak_cell1, isolate);
|
||||
CHECK(finalization_group->active_cells().IsUndefined(isolate));
|
||||
CHECK_EQ(finalization_group->cleared_cells(), *weak_cell1);
|
||||
CHECK(finalization_registry->active_cells().IsUndefined(isolate));
|
||||
CHECK_EQ(finalization_registry->cleared_cells(), *weak_cell1);
|
||||
CHECK_EQ(weak_cell1->next(), *weak_cell2);
|
||||
CHECK(weak_cell1->prev().IsUndefined(isolate));
|
||||
CHECK_EQ(weak_cell2->prev(), *weak_cell1);
|
||||
CHECK(weak_cell2->next().IsUndefined(isolate));
|
||||
}
|
||||
|
||||
TEST(TestJSFinalizationGroupPopClearedCellHoldings1) {
|
||||
TEST(TestJSFinalizationRegistryPopClearedCellHoldings1) {
|
||||
FLAG_harmony_weak_refs = true;
|
||||
CcTest::InitializeVM();
|
||||
LocalContext context;
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Factory* factory = isolate->factory();
|
||||
HandleScope outer_scope(isolate);
|
||||
Handle<JSFinalizationGroup> finalization_group =
|
||||
ConstructJSFinalizationGroup(isolate);
|
||||
Handle<JSFinalizationRegistry> finalization_registry =
|
||||
ConstructJSFinalizationRegistry(isolate);
|
||||
Handle<JSObject> js_object =
|
||||
isolate->factory()->NewJSObject(isolate->object_function());
|
||||
Handle<Object> undefined =
|
||||
handle(ReadOnlyRoots(isolate).undefined_value(), isolate);
|
||||
|
||||
Handle<Object> holdings1 = factory->NewStringFromAsciiChecked("holdings1");
|
||||
Handle<WeakCell> weak_cell1 = FinalizationGroupRegister(
|
||||
finalization_group, js_object, holdings1, undefined, isolate);
|
||||
Handle<WeakCell> weak_cell1 = FinalizationRegistryRegister(
|
||||
finalization_registry, js_object, holdings1, undefined, isolate);
|
||||
Handle<Object> holdings2 = factory->NewStringFromAsciiChecked("holdings2");
|
||||
Handle<WeakCell> weak_cell2 = FinalizationGroupRegister(
|
||||
finalization_group, js_object, holdings2, undefined, isolate);
|
||||
Handle<WeakCell> weak_cell2 = FinalizationRegistryRegister(
|
||||
finalization_registry, js_object, holdings2, undefined, isolate);
|
||||
Handle<Object> holdings3 = factory->NewStringFromAsciiChecked("holdings3");
|
||||
Handle<WeakCell> weak_cell3 = FinalizationGroupRegister(
|
||||
finalization_group, js_object, holdings3, undefined, isolate);
|
||||
Handle<WeakCell> weak_cell3 = FinalizationRegistryRegister(
|
||||
finalization_registry, js_object, holdings3, undefined, isolate);
|
||||
|
||||
NullifyWeakCell(weak_cell2, isolate);
|
||||
NullifyWeakCell(weak_cell3, isolate);
|
||||
|
||||
CHECK(finalization_group->NeedsCleanup());
|
||||
Object cleared1 =
|
||||
JSFinalizationGroup::PopClearedCellHoldings(finalization_group, isolate);
|
||||
CHECK(finalization_registry->NeedsCleanup());
|
||||
Object cleared1 = JSFinalizationRegistry::PopClearedCellHoldings(
|
||||
finalization_registry, isolate);
|
||||
CHECK_EQ(cleared1, *holdings3);
|
||||
CHECK(weak_cell3->prev().IsUndefined(isolate));
|
||||
CHECK(weak_cell3->next().IsUndefined(isolate));
|
||||
|
||||
CHECK(finalization_group->NeedsCleanup());
|
||||
Object cleared2 =
|
||||
JSFinalizationGroup::PopClearedCellHoldings(finalization_group, isolate);
|
||||
CHECK(finalization_registry->NeedsCleanup());
|
||||
Object cleared2 = JSFinalizationRegistry::PopClearedCellHoldings(
|
||||
finalization_registry, isolate);
|
||||
CHECK_EQ(cleared2, *holdings2);
|
||||
CHECK(weak_cell2->prev().IsUndefined(isolate));
|
||||
CHECK(weak_cell2->next().IsUndefined(isolate));
|
||||
|
||||
CHECK(!finalization_group->NeedsCleanup());
|
||||
CHECK(!finalization_registry->NeedsCleanup());
|
||||
|
||||
NullifyWeakCell(weak_cell1, isolate);
|
||||
|
||||
CHECK(finalization_group->NeedsCleanup());
|
||||
Object cleared3 =
|
||||
JSFinalizationGroup::PopClearedCellHoldings(finalization_group, isolate);
|
||||
CHECK(finalization_registry->NeedsCleanup());
|
||||
Object cleared3 = JSFinalizationRegistry::PopClearedCellHoldings(
|
||||
finalization_registry, isolate);
|
||||
CHECK_EQ(cleared3, *holdings1);
|
||||
CHECK(weak_cell1->prev().IsUndefined(isolate));
|
||||
CHECK(weak_cell1->next().IsUndefined(isolate));
|
||||
|
||||
CHECK(!finalization_group->NeedsCleanup());
|
||||
CHECK(finalization_group->active_cells().IsUndefined(isolate));
|
||||
CHECK(finalization_group->cleared_cells().IsUndefined(isolate));
|
||||
CHECK(!finalization_registry->NeedsCleanup());
|
||||
CHECK(finalization_registry->active_cells().IsUndefined(isolate));
|
||||
CHECK(finalization_registry->cleared_cells().IsUndefined(isolate));
|
||||
}
|
||||
|
||||
TEST(TestJSFinalizationGroupPopClearedCellHoldings2) {
|
||||
TEST(TestJSFinalizationRegistryPopClearedCellHoldings2) {
|
||||
// Test that when all WeakCells for a key are popped, the key is removed from
|
||||
// the key map.
|
||||
FLAG_harmony_weak_refs = true;
|
||||
@ -397,18 +399,18 @@ TEST(TestJSFinalizationGroupPopClearedCellHoldings2) {
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Factory* factory = isolate->factory();
|
||||
HandleScope outer_scope(isolate);
|
||||
Handle<JSFinalizationGroup> finalization_group =
|
||||
ConstructJSFinalizationGroup(isolate);
|
||||
Handle<JSFinalizationRegistry> finalization_registry =
|
||||
ConstructJSFinalizationRegistry(isolate);
|
||||
Handle<JSObject> js_object =
|
||||
isolate->factory()->NewJSObject(isolate->object_function());
|
||||
Handle<JSObject> token1 = CreateKey("token1", isolate);
|
||||
|
||||
Handle<Object> holdings1 = factory->NewStringFromAsciiChecked("holdings1");
|
||||
Handle<WeakCell> weak_cell1 = FinalizationGroupRegister(
|
||||
finalization_group, js_object, holdings1, token1, isolate);
|
||||
Handle<WeakCell> weak_cell1 = FinalizationRegistryRegister(
|
||||
finalization_registry, js_object, holdings1, token1, isolate);
|
||||
Handle<Object> holdings2 = factory->NewStringFromAsciiChecked("holdings2");
|
||||
Handle<WeakCell> weak_cell2 = FinalizationGroupRegister(
|
||||
finalization_group, js_object, holdings2, token1, isolate);
|
||||
Handle<WeakCell> weak_cell2 = FinalizationRegistryRegister(
|
||||
finalization_registry, js_object, holdings2, token1, isolate);
|
||||
|
||||
NullifyWeakCell(weak_cell1, isolate);
|
||||
NullifyWeakCell(weak_cell2, isolate);
|
||||
@ -417,28 +419,28 @@ TEST(TestJSFinalizationGroupPopClearedCellHoldings2) {
|
||||
// active_cells to cleared_cells).
|
||||
{
|
||||
SimpleNumberDictionary key_map =
|
||||
SimpleNumberDictionary::cast(finalization_group->key_map());
|
||||
SimpleNumberDictionary::cast(finalization_registry->key_map());
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token1, 2, *weak_cell2,
|
||||
*weak_cell1);
|
||||
}
|
||||
|
||||
Object cleared1 =
|
||||
JSFinalizationGroup::PopClearedCellHoldings(finalization_group, isolate);
|
||||
Object cleared1 = JSFinalizationRegistry::PopClearedCellHoldings(
|
||||
finalization_registry, isolate);
|
||||
CHECK_EQ(cleared1, *holdings2);
|
||||
|
||||
{
|
||||
SimpleNumberDictionary key_map =
|
||||
SimpleNumberDictionary::cast(finalization_group->key_map());
|
||||
SimpleNumberDictionary::cast(finalization_registry->key_map());
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token1, 1, *weak_cell1);
|
||||
}
|
||||
|
||||
Object cleared2 =
|
||||
JSFinalizationGroup::PopClearedCellHoldings(finalization_group, isolate);
|
||||
Object cleared2 = JSFinalizationRegistry::PopClearedCellHoldings(
|
||||
finalization_registry, isolate);
|
||||
CHECK_EQ(cleared2, *holdings1);
|
||||
|
||||
{
|
||||
SimpleNumberDictionary key_map =
|
||||
SimpleNumberDictionary::cast(finalization_group->key_map());
|
||||
SimpleNumberDictionary::cast(finalization_registry->key_map());
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token1, 0);
|
||||
}
|
||||
}
|
||||
@ -449,8 +451,8 @@ TEST(TestUnregisterActiveCells) {
|
||||
LocalContext context;
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
HandleScope outer_scope(isolate);
|
||||
Handle<JSFinalizationGroup> finalization_group =
|
||||
ConstructJSFinalizationGroup(isolate);
|
||||
Handle<JSFinalizationRegistry> finalization_registry =
|
||||
ConstructJSFinalizationRegistry(isolate);
|
||||
Handle<JSObject> js_object =
|
||||
isolate->factory()->NewJSObject(isolate->object_function());
|
||||
|
||||
@ -459,41 +461,41 @@ TEST(TestUnregisterActiveCells) {
|
||||
Handle<Object> undefined =
|
||||
handle(ReadOnlyRoots(isolate).undefined_value(), isolate);
|
||||
|
||||
Handle<WeakCell> weak_cell1a = FinalizationGroupRegister(
|
||||
finalization_group, js_object, undefined, token1, isolate);
|
||||
Handle<WeakCell> weak_cell1b = FinalizationGroupRegister(
|
||||
finalization_group, js_object, undefined, token1, isolate);
|
||||
Handle<WeakCell> weak_cell1a = FinalizationRegistryRegister(
|
||||
finalization_registry, js_object, undefined, token1, isolate);
|
||||
Handle<WeakCell> weak_cell1b = FinalizationRegistryRegister(
|
||||
finalization_registry, js_object, undefined, token1, isolate);
|
||||
|
||||
Handle<WeakCell> weak_cell2a = FinalizationGroupRegister(
|
||||
finalization_group, js_object, undefined, token2, isolate);
|
||||
Handle<WeakCell> weak_cell2b = FinalizationGroupRegister(
|
||||
finalization_group, js_object, undefined, token2, isolate);
|
||||
Handle<WeakCell> weak_cell2a = FinalizationRegistryRegister(
|
||||
finalization_registry, js_object, undefined, token2, isolate);
|
||||
Handle<WeakCell> weak_cell2b = FinalizationRegistryRegister(
|
||||
finalization_registry, js_object, undefined, token2, isolate);
|
||||
|
||||
VerifyWeakCellChain(isolate, finalization_group->active_cells(), 4,
|
||||
VerifyWeakCellChain(isolate, finalization_registry->active_cells(), 4,
|
||||
*weak_cell2b, *weak_cell2a, *weak_cell1b, *weak_cell1a);
|
||||
VerifyWeakCellChain(isolate, finalization_group->cleared_cells(), 0);
|
||||
VerifyWeakCellChain(isolate, finalization_registry->cleared_cells(), 0);
|
||||
{
|
||||
SimpleNumberDictionary key_map =
|
||||
SimpleNumberDictionary::cast(finalization_group->key_map());
|
||||
SimpleNumberDictionary::cast(finalization_registry->key_map());
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token1, 2, *weak_cell1b,
|
||||
*weak_cell1a);
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token2, 2, *weak_cell2b,
|
||||
*weak_cell2a);
|
||||
}
|
||||
|
||||
JSFinalizationGroup::Unregister(finalization_group, token1, isolate);
|
||||
JSFinalizationRegistry::Unregister(finalization_registry, token1, isolate);
|
||||
{
|
||||
SimpleNumberDictionary key_map =
|
||||
SimpleNumberDictionary::cast(finalization_group->key_map());
|
||||
SimpleNumberDictionary::cast(finalization_registry->key_map());
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token1, 0);
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token2, 2, *weak_cell2b,
|
||||
*weak_cell2a);
|
||||
}
|
||||
|
||||
// Both weak_cell1a and weak_cell1b removed from active_cells.
|
||||
VerifyWeakCellChain(isolate, finalization_group->active_cells(), 2,
|
||||
VerifyWeakCellChain(isolate, finalization_registry->active_cells(), 2,
|
||||
*weak_cell2b, *weak_cell2a);
|
||||
VerifyWeakCellChain(isolate, finalization_group->cleared_cells(), 0);
|
||||
VerifyWeakCellChain(isolate, finalization_registry->cleared_cells(), 0);
|
||||
}
|
||||
|
||||
TEST(TestUnregisterActiveAndClearedCells) {
|
||||
@ -502,8 +504,8 @@ TEST(TestUnregisterActiveAndClearedCells) {
|
||||
LocalContext context;
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
HandleScope outer_scope(isolate);
|
||||
Handle<JSFinalizationGroup> finalization_group =
|
||||
ConstructJSFinalizationGroup(isolate);
|
||||
Handle<JSFinalizationRegistry> finalization_registry =
|
||||
ConstructJSFinalizationRegistry(isolate);
|
||||
Handle<JSObject> js_object =
|
||||
isolate->factory()->NewJSObject(isolate->object_function());
|
||||
|
||||
@ -512,40 +514,40 @@ TEST(TestUnregisterActiveAndClearedCells) {
|
||||
Handle<Object> undefined =
|
||||
handle(ReadOnlyRoots(isolate).undefined_value(), isolate);
|
||||
|
||||
Handle<WeakCell> weak_cell1a = FinalizationGroupRegister(
|
||||
finalization_group, js_object, undefined, token1, isolate);
|
||||
Handle<WeakCell> weak_cell1b = FinalizationGroupRegister(
|
||||
finalization_group, js_object, undefined, token1, isolate);
|
||||
Handle<WeakCell> weak_cell1a = FinalizationRegistryRegister(
|
||||
finalization_registry, js_object, undefined, token1, isolate);
|
||||
Handle<WeakCell> weak_cell1b = FinalizationRegistryRegister(
|
||||
finalization_registry, js_object, undefined, token1, isolate);
|
||||
|
||||
Handle<WeakCell> weak_cell2a = FinalizationGroupRegister(
|
||||
finalization_group, js_object, undefined, token2, isolate);
|
||||
Handle<WeakCell> weak_cell2b = FinalizationGroupRegister(
|
||||
finalization_group, js_object, undefined, token2, isolate);
|
||||
Handle<WeakCell> weak_cell2a = FinalizationRegistryRegister(
|
||||
finalization_registry, js_object, undefined, token2, isolate);
|
||||
Handle<WeakCell> weak_cell2b = FinalizationRegistryRegister(
|
||||
finalization_registry, js_object, undefined, token2, isolate);
|
||||
|
||||
NullifyWeakCell(weak_cell2a, isolate);
|
||||
|
||||
VerifyWeakCellChain(isolate, finalization_group->active_cells(), 3,
|
||||
VerifyWeakCellChain(isolate, finalization_registry->active_cells(), 3,
|
||||
*weak_cell2b, *weak_cell1b, *weak_cell1a);
|
||||
VerifyWeakCellChain(isolate, finalization_group->cleared_cells(), 1,
|
||||
VerifyWeakCellChain(isolate, finalization_registry->cleared_cells(), 1,
|
||||
*weak_cell2a);
|
||||
{
|
||||
SimpleNumberDictionary key_map =
|
||||
SimpleNumberDictionary::cast(finalization_group->key_map());
|
||||
SimpleNumberDictionary::cast(finalization_registry->key_map());
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token1, 2, *weak_cell1b,
|
||||
*weak_cell1a);
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token2, 2, *weak_cell2b,
|
||||
*weak_cell2a);
|
||||
}
|
||||
|
||||
JSFinalizationGroup::Unregister(finalization_group, token2, isolate);
|
||||
JSFinalizationRegistry::Unregister(finalization_registry, token2, isolate);
|
||||
|
||||
// Both weak_cell2a and weak_cell2b removed.
|
||||
VerifyWeakCellChain(isolate, finalization_group->active_cells(), 2,
|
||||
VerifyWeakCellChain(isolate, finalization_registry->active_cells(), 2,
|
||||
*weak_cell1b, *weak_cell1a);
|
||||
VerifyWeakCellChain(isolate, finalization_group->cleared_cells(), 0);
|
||||
VerifyWeakCellChain(isolate, finalization_registry->cleared_cells(), 0);
|
||||
{
|
||||
SimpleNumberDictionary key_map =
|
||||
SimpleNumberDictionary::cast(finalization_group->key_map());
|
||||
SimpleNumberDictionary::cast(finalization_registry->key_map());
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token1, 2, *weak_cell1b,
|
||||
*weak_cell1a);
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token2, 0);
|
||||
@ -558,8 +560,8 @@ TEST(TestWeakCellUnregisterTwice) {
|
||||
LocalContext context;
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
HandleScope outer_scope(isolate);
|
||||
Handle<JSFinalizationGroup> finalization_group =
|
||||
ConstructJSFinalizationGroup(isolate);
|
||||
Handle<JSFinalizationRegistry> finalization_registry =
|
||||
ConstructJSFinalizationRegistry(isolate);
|
||||
Handle<JSObject> js_object =
|
||||
isolate->factory()->NewJSObject(isolate->object_function());
|
||||
|
||||
@ -567,35 +569,35 @@ TEST(TestWeakCellUnregisterTwice) {
|
||||
Handle<Object> undefined =
|
||||
handle(ReadOnlyRoots(isolate).undefined_value(), isolate);
|
||||
|
||||
Handle<WeakCell> weak_cell1 = FinalizationGroupRegister(
|
||||
finalization_group, js_object, undefined, token1, isolate);
|
||||
Handle<WeakCell> weak_cell1 = FinalizationRegistryRegister(
|
||||
finalization_registry, js_object, undefined, token1, isolate);
|
||||
|
||||
VerifyWeakCellChain(isolate, finalization_group->active_cells(), 1,
|
||||
VerifyWeakCellChain(isolate, finalization_registry->active_cells(), 1,
|
||||
*weak_cell1);
|
||||
VerifyWeakCellChain(isolate, finalization_group->cleared_cells(), 0);
|
||||
VerifyWeakCellChain(isolate, finalization_registry->cleared_cells(), 0);
|
||||
{
|
||||
SimpleNumberDictionary key_map =
|
||||
SimpleNumberDictionary::cast(finalization_group->key_map());
|
||||
SimpleNumberDictionary::cast(finalization_registry->key_map());
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token1, 1, *weak_cell1);
|
||||
}
|
||||
|
||||
JSFinalizationGroup::Unregister(finalization_group, token1, isolate);
|
||||
JSFinalizationRegistry::Unregister(finalization_registry, token1, isolate);
|
||||
|
||||
VerifyWeakCellChain(isolate, finalization_group->active_cells(), 0);
|
||||
VerifyWeakCellChain(isolate, finalization_group->cleared_cells(), 0);
|
||||
VerifyWeakCellChain(isolate, finalization_registry->active_cells(), 0);
|
||||
VerifyWeakCellChain(isolate, finalization_registry->cleared_cells(), 0);
|
||||
{
|
||||
SimpleNumberDictionary key_map =
|
||||
SimpleNumberDictionary::cast(finalization_group->key_map());
|
||||
SimpleNumberDictionary::cast(finalization_registry->key_map());
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token1, 0);
|
||||
}
|
||||
|
||||
JSFinalizationGroup::Unregister(finalization_group, token1, isolate);
|
||||
JSFinalizationRegistry::Unregister(finalization_registry, token1, isolate);
|
||||
|
||||
VerifyWeakCellChain(isolate, finalization_group->active_cells(), 0);
|
||||
VerifyWeakCellChain(isolate, finalization_group->cleared_cells(), 0);
|
||||
VerifyWeakCellChain(isolate, finalization_registry->active_cells(), 0);
|
||||
VerifyWeakCellChain(isolate, finalization_registry->cleared_cells(), 0);
|
||||
{
|
||||
SimpleNumberDictionary key_map =
|
||||
SimpleNumberDictionary::cast(finalization_group->key_map());
|
||||
SimpleNumberDictionary::cast(finalization_registry->key_map());
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token1, 0);
|
||||
}
|
||||
}
|
||||
@ -607,37 +609,37 @@ TEST(TestWeakCellUnregisterPopped) {
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Factory* factory = isolate->factory();
|
||||
HandleScope outer_scope(isolate);
|
||||
Handle<JSFinalizationGroup> finalization_group =
|
||||
ConstructJSFinalizationGroup(isolate);
|
||||
Handle<JSFinalizationRegistry> finalization_registry =
|
||||
ConstructJSFinalizationRegistry(isolate);
|
||||
Handle<JSObject> js_object =
|
||||
isolate->factory()->NewJSObject(isolate->object_function());
|
||||
Handle<JSObject> token1 = CreateKey("token1", isolate);
|
||||
Handle<Object> holdings1 = factory->NewStringFromAsciiChecked("holdings1");
|
||||
Handle<WeakCell> weak_cell1 = FinalizationGroupRegister(
|
||||
finalization_group, js_object, holdings1, token1, isolate);
|
||||
Handle<WeakCell> weak_cell1 = FinalizationRegistryRegister(
|
||||
finalization_registry, js_object, holdings1, token1, isolate);
|
||||
|
||||
NullifyWeakCell(weak_cell1, isolate);
|
||||
|
||||
CHECK(finalization_group->NeedsCleanup());
|
||||
Object cleared1 =
|
||||
JSFinalizationGroup::PopClearedCellHoldings(finalization_group, isolate);
|
||||
CHECK(finalization_registry->NeedsCleanup());
|
||||
Object cleared1 = JSFinalizationRegistry::PopClearedCellHoldings(
|
||||
finalization_registry, isolate);
|
||||
CHECK_EQ(cleared1, *holdings1);
|
||||
|
||||
VerifyWeakCellChain(isolate, finalization_group->active_cells(), 0);
|
||||
VerifyWeakCellChain(isolate, finalization_group->cleared_cells(), 0);
|
||||
VerifyWeakCellChain(isolate, finalization_registry->active_cells(), 0);
|
||||
VerifyWeakCellChain(isolate, finalization_registry->cleared_cells(), 0);
|
||||
{
|
||||
SimpleNumberDictionary key_map =
|
||||
SimpleNumberDictionary::cast(finalization_group->key_map());
|
||||
SimpleNumberDictionary::cast(finalization_registry->key_map());
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token1, 0);
|
||||
}
|
||||
|
||||
JSFinalizationGroup::Unregister(finalization_group, token1, isolate);
|
||||
JSFinalizationRegistry::Unregister(finalization_registry, token1, isolate);
|
||||
|
||||
VerifyWeakCellChain(isolate, finalization_group->active_cells(), 0);
|
||||
VerifyWeakCellChain(isolate, finalization_group->cleared_cells(), 0);
|
||||
VerifyWeakCellChain(isolate, finalization_registry->active_cells(), 0);
|
||||
VerifyWeakCellChain(isolate, finalization_registry->cleared_cells(), 0);
|
||||
{
|
||||
SimpleNumberDictionary key_map =
|
||||
SimpleNumberDictionary::cast(finalization_group->key_map());
|
||||
SimpleNumberDictionary::cast(finalization_registry->key_map());
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token1, 0);
|
||||
}
|
||||
}
|
||||
@ -648,11 +650,11 @@ TEST(TestWeakCellUnregisterNonexistentKey) {
|
||||
LocalContext context;
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
HandleScope outer_scope(isolate);
|
||||
Handle<JSFinalizationGroup> finalization_group =
|
||||
ConstructJSFinalizationGroup(isolate);
|
||||
Handle<JSFinalizationRegistry> finalization_registry =
|
||||
ConstructJSFinalizationRegistry(isolate);
|
||||
Handle<JSObject> token1 = CreateKey("token1", isolate);
|
||||
|
||||
JSFinalizationGroup::Unregister(finalization_group, token1, isolate);
|
||||
JSFinalizationRegistry::Unregister(finalization_registry, token1, isolate);
|
||||
}
|
||||
|
||||
TEST(TestJSWeakRef) {
|
||||
@ -793,8 +795,8 @@ TEST(TestRemoveUnregisterToken) {
|
||||
LocalContext context;
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
HandleScope outer_scope(isolate);
|
||||
Handle<JSFinalizationGroup> finalization_group =
|
||||
ConstructJSFinalizationGroup(isolate);
|
||||
Handle<JSFinalizationRegistry> finalization_registry =
|
||||
ConstructJSFinalizationRegistry(isolate);
|
||||
Handle<JSObject> js_object =
|
||||
isolate->factory()->NewJSObject(isolate->object_function());
|
||||
|
||||
@ -803,32 +805,32 @@ TEST(TestRemoveUnregisterToken) {
|
||||
Handle<Object> undefined =
|
||||
handle(ReadOnlyRoots(isolate).undefined_value(), isolate);
|
||||
|
||||
Handle<WeakCell> weak_cell1a = FinalizationGroupRegister(
|
||||
finalization_group, js_object, undefined, token1, isolate);
|
||||
Handle<WeakCell> weak_cell1b = FinalizationGroupRegister(
|
||||
finalization_group, js_object, undefined, token1, isolate);
|
||||
Handle<WeakCell> weak_cell1a = FinalizationRegistryRegister(
|
||||
finalization_registry, js_object, undefined, token1, isolate);
|
||||
Handle<WeakCell> weak_cell1b = FinalizationRegistryRegister(
|
||||
finalization_registry, js_object, undefined, token1, isolate);
|
||||
|
||||
Handle<WeakCell> weak_cell2a = FinalizationGroupRegister(
|
||||
finalization_group, js_object, undefined, token2, isolate);
|
||||
Handle<WeakCell> weak_cell2b = FinalizationGroupRegister(
|
||||
finalization_group, js_object, undefined, token2, isolate);
|
||||
Handle<WeakCell> weak_cell2a = FinalizationRegistryRegister(
|
||||
finalization_registry, js_object, undefined, token2, isolate);
|
||||
Handle<WeakCell> weak_cell2b = FinalizationRegistryRegister(
|
||||
finalization_registry, js_object, undefined, token2, isolate);
|
||||
|
||||
NullifyWeakCell(weak_cell2a, isolate);
|
||||
|
||||
VerifyWeakCellChain(isolate, finalization_group->active_cells(), 3,
|
||||
VerifyWeakCellChain(isolate, finalization_registry->active_cells(), 3,
|
||||
*weak_cell2b, *weak_cell1b, *weak_cell1a);
|
||||
VerifyWeakCellChain(isolate, finalization_group->cleared_cells(), 1,
|
||||
VerifyWeakCellChain(isolate, finalization_registry->cleared_cells(), 1,
|
||||
*weak_cell2a);
|
||||
{
|
||||
SimpleNumberDictionary key_map =
|
||||
SimpleNumberDictionary::cast(finalization_group->key_map());
|
||||
SimpleNumberDictionary::cast(finalization_registry->key_map());
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token1, 2, *weak_cell1b,
|
||||
*weak_cell1a);
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token2, 2, *weak_cell2b,
|
||||
*weak_cell2a);
|
||||
}
|
||||
|
||||
finalization_group->RemoveUnregisterToken(
|
||||
finalization_registry->RemoveUnregisterToken(
|
||||
JSReceiver::cast(*token2), isolate,
|
||||
[undefined](WeakCell matched_cell) {
|
||||
matched_cell.set_unregister_token(*undefined);
|
||||
@ -836,15 +838,15 @@ TEST(TestRemoveUnregisterToken) {
|
||||
[](HeapObject, ObjectSlot, Object) {});
|
||||
|
||||
// Both weak_cell2a and weak_cell2b remain on the weak cell chains.
|
||||
VerifyWeakCellChain(isolate, finalization_group->active_cells(), 3,
|
||||
VerifyWeakCellChain(isolate, finalization_registry->active_cells(), 3,
|
||||
*weak_cell2b, *weak_cell1b, *weak_cell1a);
|
||||
VerifyWeakCellChain(isolate, finalization_group->cleared_cells(), 1,
|
||||
VerifyWeakCellChain(isolate, finalization_registry->cleared_cells(), 1,
|
||||
*weak_cell2a);
|
||||
|
||||
// But both weak_cell2a and weak_cell2b are removed from the key chain.
|
||||
{
|
||||
SimpleNumberDictionary key_map =
|
||||
SimpleNumberDictionary::cast(finalization_group->key_map());
|
||||
SimpleNumberDictionary::cast(finalization_registry->key_map());
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token1, 2, *weak_cell1b,
|
||||
*weak_cell1a);
|
||||
VerifyWeakCellKeyChain(isolate, key_map, *token2, 0);
|
||||
|
@ -30,10 +30,10 @@ void RunStdFunction(void* data) {
|
||||
}
|
||||
|
||||
template <typename TMixin>
|
||||
class WithFinalizationGroupMixin : public TMixin {
|
||||
class WithFinalizationRegistryMixin : public TMixin {
|
||||
public:
|
||||
WithFinalizationGroupMixin() = default;
|
||||
~WithFinalizationGroupMixin() override = default;
|
||||
WithFinalizationRegistryMixin() = default;
|
||||
~WithFinalizationRegistryMixin() override = default;
|
||||
|
||||
static void SetUpTestCase() {
|
||||
CHECK_NULL(save_flags_);
|
||||
@ -54,21 +54,21 @@ class WithFinalizationGroupMixin : public TMixin {
|
||||
private:
|
||||
static SaveFlags* save_flags_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WithFinalizationGroupMixin);
|
||||
DISALLOW_COPY_AND_ASSIGN(WithFinalizationRegistryMixin);
|
||||
};
|
||||
|
||||
template <typename TMixin>
|
||||
SaveFlags* WithFinalizationGroupMixin<TMixin>::save_flags_ = nullptr;
|
||||
SaveFlags* WithFinalizationRegistryMixin<TMixin>::save_flags_ = nullptr;
|
||||
|
||||
using TestWithNativeContextAndFinalizationGroup = //
|
||||
WithInternalIsolateMixin< //
|
||||
WithContextMixin< //
|
||||
WithFinalizationGroupMixin< //
|
||||
WithIsolateScopeMixin< //
|
||||
WithSharedIsolateMixin< //
|
||||
using TestWithNativeContextAndFinalizationRegistry = //
|
||||
WithInternalIsolateMixin< //
|
||||
WithContextMixin< //
|
||||
WithFinalizationRegistryMixin< //
|
||||
WithIsolateScopeMixin< //
|
||||
WithSharedIsolateMixin< //
|
||||
::testing::Test>>>>>;
|
||||
|
||||
class MicrotaskQueueTest : public TestWithNativeContextAndFinalizationGroup {
|
||||
class MicrotaskQueueTest : public TestWithNativeContextAndFinalizationRegistry {
|
||||
public:
|
||||
template <typename F>
|
||||
Handle<Microtask> NewMicrotask(F&& f) {
|
||||
|
@ -166,8 +166,8 @@ INSTANCE_TYPES = {
|
||||
1066: "JS_DATE_TIME_FORMAT_TYPE",
|
||||
1067: "JS_DISPLAY_NAMES_TYPE",
|
||||
1068: "JS_ERROR_TYPE",
|
||||
1069: "JS_FINALIZATION_GROUP_TYPE",
|
||||
1070: "JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_TYPE",
|
||||
1069: "JS_FINALIZATION_REGISTRY_TYPE",
|
||||
1070: "JS_FINALIZATION_REGISTRY_CLEANUP_ITERATOR_TYPE",
|
||||
1071: "JS_LIST_FORMAT_TYPE",
|
||||
1072: "JS_LOCALE_TYPE",
|
||||
1073: "JS_MESSAGE_OBJECT_TYPE",
|
||||
|
Loading…
Reference in New Issue
Block a user