diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index 2f312e9b6280f4..dcdfbfc7ec58d1 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -5945,6 +5945,37 @@ class V8_EXPORT RegExp : public Object { static void CheckCast(Value* obj); }; +/** + * An instance of the built-in FinalizationRegistry constructor. + * + * The C++ name is FinalizationGroup for backwards compatibility. This API is + * experimental and deprecated. + */ +class V8_EXPORT FinalizationGroup : public Object { + public: + /** + * Runs the cleanup callback of the given FinalizationRegistry. + * + * V8 will inform the embedder that there are finalizer callbacks be + * called through HostCleanupFinalizationGroupCallback. + * + * HostCleanupFinalizationGroupCallback should schedule a task to + * call FinalizationGroup::Cleanup() at some point in the + * future. It's the embedders responsiblity to make this call at a + * time which does not interrupt synchronous ECMAScript code + * execution. + * + * If the result is Nothing then an exception has + * occurred. Otherwise the result is |true| if the cleanup callback + * was called successfully. The result is never |false|. + */ + V8_DEPRECATED( + "FinalizationGroup cleanup is automatic if " + "HostCleanupFinalizationGroupCallback is not set") + static V8_WARN_UNUSED_RESULT Maybe Cleanup( + Local finalization_group); +}; + /** * A JavaScript value that wraps a C++ void*. This type of value is mainly used * to associate C++ data structures with JavaScript objects. @@ -7197,6 +7228,20 @@ typedef void (*AddCrashKeyCallback)(CrashKeyId id, const std::string& value); typedef void (*BeforeCallEnteredCallback)(Isolate*); typedef void (*CallCompletedCallback)(Isolate*); +/** + * HostCleanupFinalizationGroupCallback is called when we require the + * embedder to enqueue a task that would call + * FinalizationGroup::Cleanup(). + * + * The FinalizationGroup is the one for which the embedder needs to + * call FinalizationGroup::Cleanup() on. + * + * The context provided is the one in which the FinalizationGroup was + * created in. + */ +typedef void (*HostCleanupFinalizationGroupCallback)( + Local context, Local fg); + /** * HostImportModuleDynamicallyCallback is called when we require the * embedder to load a module. This is used as part of the dynamic @@ -8536,6 +8581,17 @@ class V8_EXPORT Isolate { void SetAbortOnUncaughtExceptionCallback( AbortOnUncaughtExceptionCallback callback); + /** + * This specifies the callback to be called when FinalizationRegistries + * are ready to be cleaned up and require FinalizationGroup::Cleanup() + * to be called in a future task. + */ + V8_DEPRECATED( + "FinalizationRegistry cleanup is automatic if " + "HostCleanupFinalizationGroupCallback is not set") + void SetHostCleanupFinalizationGroupCallback( + HostCleanupFinalizationGroupCallback callback); + /** * This specifies the callback called by the upcoming dynamic * import() language feature to load modules. diff --git a/deps/v8/src/api/api-inl.h b/deps/v8/src/api/api-inl.h index f686424286d8fe..0d2ad2f8a0f8ce 100644 --- a/deps/v8/src/api/api-inl.h +++ b/deps/v8/src/api/api-inl.h @@ -86,6 +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, JSFinalizationRegistry, FinalizationGroup) TYPED_ARRAYS(MAKE_TO_LOCAL_TYPED_ARRAY) diff --git a/deps/v8/src/api/api.cc b/deps/v8/src/api/api.cc index 5b1c2b156b6e93..7f3c4bd36246ba 100644 --- a/deps/v8/src/api/api.cc +++ b/deps/v8/src/api/api.cc @@ -8298,6 +8298,33 @@ void Isolate::SetAbortOnUncaughtExceptionCallback( isolate->SetAbortOnUncaughtExceptionCallback(callback); } +void Isolate::SetHostCleanupFinalizationGroupCallback( + HostCleanupFinalizationGroupCallback callback) { + i::Isolate* isolate = reinterpret_cast(this); + isolate->SetHostCleanupFinalizationGroupCallback(callback); +} + +Maybe FinalizationGroup::Cleanup( + Local finalization_group) { + i::Handle fr = + Utils::OpenHandle(*finalization_group); + i::Isolate* isolate = fr->native_context().GetIsolate(); + i::Handle i_context(fr->native_context(), isolate); + Local context = Utils::ToLocal(i_context); + ENTER_V8(isolate, context, FinalizationGroup, Cleanup, Nothing(), + i::HandleScope); + i::Handle callback(fr->cleanup(), isolate); + i::Handle argv[] = {callback}; + fr->set_scheduled_for_cleanup(false); + has_pending_exception = + i::Execution::CallBuiltin(isolate, + isolate->finalization_registry_cleanup_some(), + fr, arraysize(argv), argv) + .is_null(); + RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool); + return Just(true); +} + void Isolate::SetHostImportModuleDynamicallyCallback( HostImportModuleDynamicallyCallback callback) { i::Isolate* isolate = reinterpret_cast(this); diff --git a/deps/v8/src/api/api.h b/deps/v8/src/api/api.h index ad879657c99247..29cc4eacfd7338 100644 --- a/deps/v8/src/api/api.h +++ b/deps/v8/src/api/api.h @@ -94,6 +94,7 @@ class RegisteredExtension { V(Data, Object) \ V(RegExp, JSRegExp) \ V(Object, JSReceiver) \ + V(FinalizationGroup, JSFinalizationRegistry) \ V(Array, JSArray) \ V(Map, JSMap) \ V(Set, JSSet) \ @@ -206,6 +207,8 @@ class Utils { v8::internal::Handle obj); static inline Local ToLocalBigUint64Array( v8::internal::Handle obj); + static inline Local ToLocal( + v8::internal::Handle obj); static inline Local ToLocalShared( v8::internal::Handle obj); diff --git a/deps/v8/src/execution/isolate.cc b/deps/v8/src/execution/isolate.cc index bea08a16b83524..2008bccb404a6e 100644 --- a/deps/v8/src/execution/isolate.cc +++ b/deps/v8/src/execution/isolate.cc @@ -3952,6 +3952,21 @@ MaybeHandle Isolate::RunHostImportModuleDynamicallyCallback( void Isolate::ClearKeptObjects() { heap()->ClearKeptObjects(); } +void Isolate::SetHostCleanupFinalizationGroupCallback( + HostCleanupFinalizationGroupCallback callback) { + host_cleanup_finalization_group_callback_ = callback; +} + +void Isolate::RunHostCleanupFinalizationGroupCallback( + Handle fr) { + if (host_cleanup_finalization_group_callback_ != nullptr) { + v8::Local api_context = + v8::Utils::ToLocal(handle(Context::cast(fr->native_context()), this)); + host_cleanup_finalization_group_callback_(api_context, + v8::Utils::ToLocal(fr)); + } +} + void Isolate::SetHostImportModuleDynamicallyCallback( HostImportModuleDynamicallyCallback callback) { host_import_module_dynamically_callback_ = callback; diff --git a/deps/v8/src/execution/isolate.h b/deps/v8/src/execution/isolate.h index de00d862a3b87a..78c6ca4b47d6ed 100644 --- a/deps/v8/src/execution/isolate.h +++ b/deps/v8/src/execution/isolate.h @@ -1416,6 +1416,14 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory { bool IsInAnyContext(Object object, uint32_t index); void ClearKeptObjects(); + void SetHostCleanupFinalizationGroupCallback( + HostCleanupFinalizationGroupCallback callback); + HostCleanupFinalizationGroupCallback + host_cleanup_finalization_group_callback() const { + return host_cleanup_finalization_group_callback_; + } + void RunHostCleanupFinalizationGroupCallback( + Handle fr); void SetHostImportModuleDynamicallyCallback( HostImportModuleDynamicallyCallback callback); @@ -1672,6 +1680,8 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory { v8::Isolate::AtomicsWaitCallback atomics_wait_callback_ = nullptr; void* atomics_wait_callback_data_ = nullptr; PromiseHook promise_hook_ = nullptr; + HostCleanupFinalizationGroupCallback + host_cleanup_finalization_group_callback_ = nullptr; HostImportModuleDynamicallyCallback host_import_module_dynamically_callback_ = nullptr; HostInitializeImportMetaObjectCallback diff --git a/deps/v8/src/heap/finalization-registry-cleanup-task.cc b/deps/v8/src/heap/finalization-registry-cleanup-task.cc index 2acfa31ffbae37..93997c91b6e401 100644 --- a/deps/v8/src/heap/finalization-registry-cleanup-task.cc +++ b/deps/v8/src/heap/finalization-registry-cleanup-task.cc @@ -37,6 +37,7 @@ void FinalizationRegistryCleanupTask::SlowAssertNoActiveJavaScript() { void FinalizationRegistryCleanupTask::RunInternal() { Isolate* isolate = heap_->isolate(); + DCHECK(!isolate->host_cleanup_finalization_group_callback()); SlowAssertNoActiveJavaScript(); TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", diff --git a/deps/v8/src/heap/heap.cc b/deps/v8/src/heap/heap.cc index 606ba0fe65fa45..d035fece83b799 100644 --- a/deps/v8/src/heap/heap.cc +++ b/deps/v8/src/heap/heap.cc @@ -1201,6 +1201,16 @@ void Heap::GarbageCollectionEpilogue() { TRACE_GC(tracer(), GCTracer::Scope::HEAP_EPILOGUE_REDUCE_NEW_SPACE); ReduceNewSpaceSize(); } + + if (FLAG_harmony_weak_refs && + isolate()->host_cleanup_finalization_group_callback()) { + HandleScope handle_scope(isolate()); + Handle finalization_registry; + while ( + DequeueDirtyJSFinalizationRegistry().ToHandle(&finalization_registry)) { + isolate()->RunHostCleanupFinalizationGroupCallback(finalization_registry); + } + } } class GCCallbacksScope { @@ -6208,6 +6218,7 @@ void Heap::SetInterpreterEntryTrampolineForProfiling(Code code) { } void Heap::PostFinalizationRegistryCleanupTaskIfNeeded() { + DCHECK(!isolate()->host_cleanup_finalization_group_callback()); // Only one cleanup task is posted at a time. if (!HasDirtyJSFinalizationRegistries() || is_finalization_registry_cleanup_task_posted_) { @@ -6267,6 +6278,7 @@ MaybeHandle Heap::DequeueDirtyJSFinalizationRegistry() { void Heap::RemoveDirtyFinalizationRegistriesOnContext(NativeContext context) { if (!FLAG_harmony_weak_refs) return; + if (isolate()->host_cleanup_finalization_group_callback()) return; DisallowHeapAllocation no_gc; diff --git a/deps/v8/src/heap/mark-compact.cc b/deps/v8/src/heap/mark-compact.cc index a7e1c93e1f49d0..53c215e2349a9a 100644 --- a/deps/v8/src/heap/mark-compact.cc +++ b/deps/v8/src/heap/mark-compact.cc @@ -2537,7 +2537,9 @@ void MarkCompactCollector::ClearJSWeakRefs() { RecordSlot(weak_cell, slot, HeapObject::cast(*slot)); } } - heap()->PostFinalizationRegistryCleanupTaskIfNeeded(); + if (!isolate()->host_cleanup_finalization_group_callback()) { + heap()->PostFinalizationRegistryCleanupTaskIfNeeded(); + } } void MarkCompactCollector::AbortWeakObjects() { diff --git a/deps/v8/src/logging/counters.h b/deps/v8/src/logging/counters.h index 02a6feee2e3d65..5c1aa81788eaf8 100644 --- a/deps/v8/src/logging/counters.h +++ b/deps/v8/src/logging/counters.h @@ -772,6 +772,7 @@ class RuntimeCallTimer final { V(Int8Array_New) \ V(Isolate_DateTimeConfigurationChangeNotification) \ V(Isolate_LocaleConfigurationChangeNotification) \ + V(FinalizationGroup_Cleanup) \ V(JSON_Parse) \ V(JSON_Stringify) \ V(Map_AsArray) \