diff --git a/js/public/GCAPI.h b/js/public/GCAPI.h index 98901cf9b143..ace9eab4263f 100644 --- a/js/public/GCAPI.h +++ b/js/public/GCAPI.h @@ -396,6 +396,16 @@ typedef void (*JSWeakPointerCompartmentCallback)(JSContext* cx, JS::Compartment* comp, void* data); +/* + * This is called to tell the embedding that the FinalizationGroup object + * |group| has cleanup work, and that then engine should be called back at an + * appropriate later time to perform this cleanup. + * + * This callback must not do anything that could cause GC. + */ +using JSHostCleanupFinalizationGroupCallback = void (*)(JSObject* group, + void* data); + /** * Each external string has a pointer to JSExternalStringCallbacks. Embedders * can use this to implement custom finalization or memory reporting behavior. @@ -1087,6 +1097,9 @@ extern JS_PUBLIC_API bool IsIdleGCTaskNeeded(JSRuntime* rt); extern JS_PUBLIC_API void RunIdleTimeGCTask(JSRuntime* rt); +extern JS_PUBLIC_API void SetHostCleanupFinalizationGroupCallback( + JSContext* cx, JSHostCleanupFinalizationGroupCallback cb, void* data); + } // namespace JS namespace js { diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp index ce4a2eb521f4..7d1fcd014858 100644 --- a/js/src/gc/GC.cpp +++ b/js/src/gc/GC.cpp @@ -213,6 +213,7 @@ #include "jstypes.h" #include "jsutil.h" +#include "builtin/FinalizationGroupObject.h" #include "debugger/DebugAPI.h" #include "gc/FindSCCs.h" #include "gc/FreeOp.h" @@ -1546,6 +1547,20 @@ void GCRuntime::callFinalizeCallbacks(JSFreeOp* fop, } } +void GCRuntime::setHostCleanupFinalizationGroupCallback( + JSHostCleanupFinalizationGroupCallback callback, void* data) { + hostCleanupFinalizationGroupCallback = {callback, data}; +} + +void GCRuntime::callHostCleanupFinalizationGroupCallback( + FinalizationGroupObject* group) { + JS::AutoSuppressGCAnalysis nogc; + auto& callback = hostCleanupFinalizationGroupCallback; + if (callback.op) { + callback.op(group, callback.data); + } +} + bool GCRuntime::addWeakPointerZonesCallback(JSWeakPointerZonesCallback callback, void* data) { return updateWeakPointerZonesCallbacks.ref().append( diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index 8886506f00f6..3b9bcb3cd3ad 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -30,6 +30,7 @@ class AutoAccessAtomsZone; class AutoLockGC; class AutoLockGCBgAlloc; class AutoLockHelperThreadState; +class FinalizationGroupObject; class VerifyPreTracer; class ZoneAllocator; @@ -395,6 +396,9 @@ class GCRuntime { MOZ_MUST_USE bool addFinalizeCallback(JSFinalizeCallback callback, void* data); void removeFinalizeCallback(JSFinalizeCallback func); + void setHostCleanupFinalizationGroupCallback( + JSHostCleanupFinalizationGroupCallback callback, void* data); + void callHostCleanupFinalizationGroupCallback(FinalizationGroupObject* group); MOZ_MUST_USE bool addWeakPointerZonesCallback( JSWeakPointerZonesCallback callback, void* data); void removeWeakPointerZonesCallback(JSWeakPointerZonesCallback callback); @@ -1045,6 +1049,8 @@ class GCRuntime { Callback gcDoCycleCollectionCallback; Callback tenuredCallback; CallbackVector finalizeCallbacks; + Callback + hostCleanupFinalizationGroupCallback; CallbackVector updateWeakPointerZonesCallbacks; CallbackVector updateWeakPointerCompartmentCallbacks; diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 8a48eab5bad7..59daed2ce962 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1285,6 +1285,12 @@ JS_PUBLIC_API void JS_RemoveFinalizeCallback(JSContext* cx, cx->runtime()->gc.removeFinalizeCallback(cb); } +JS_PUBLIC_API void JS::SetHostCleanupFinalizationGroupCallback( + JSContext* cx, JSHostCleanupFinalizationGroupCallback cb, void* data) { + AssertHeapIsIdle(); + cx->runtime()->gc.setHostCleanupFinalizationGroupCallback(cb, data); +} + JS_PUBLIC_API bool JS_AddWeakPointerZonesCallback(JSContext* cx, JSWeakPointerZonesCallback cb, void* data) {