diff --git a/content/base/public/nsContentUtils.h b/content/base/public/nsContentUtils.h index 476903ddf3c..47a710ed61c 100644 --- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -1295,8 +1295,9 @@ public: #ifdef DEBUG static bool AreJSObjectsHeld(void* aScriptObjectHolder); - static void CheckCCWrapperTraversal(nsISupports* aScriptObjectHolder, - nsWrapperCache* aCache); + static void CheckCCWrapperTraversal(void* aScriptObjectHolder, + nsWrapperCache* aCache, + nsScriptObjectTracer* aTracer); #endif static void PreserveWrapper(nsISupports* aScriptObjectHolder, @@ -1309,15 +1310,23 @@ public: MOZ_ASSERT(ccISupports); nsXPCOMCycleCollectionParticipant* participant; CallQueryInterface(ccISupports, &participant); - HoldJSObjects(ccISupports, participant); + PreserveWrapper(ccISupports, aCache, participant); + } + } + static void PreserveWrapper(void* aScriptObjectHolder, + nsWrapperCache* aCache, + nsScriptObjectTracer* aTracer) + { + if (!aCache->PreservingWrapper()) { + HoldJSObjects(aScriptObjectHolder, aTracer); aCache->SetPreservingWrapper(true); #ifdef DEBUG // Make sure the cycle collector will be able to traverse to the wrapper. - CheckCCWrapperTraversal(ccISupports, aCache); + CheckCCWrapperTraversal(aScriptObjectHolder, aCache, aTracer); #endif } } - static void ReleaseWrapper(nsISupports* aScriptObjectHolder, + static void ReleaseWrapper(void* aScriptObjectHolder, nsWrapperCache* aCache); static void TraceWrapper(nsWrapperCache* aCache, TraceCallback aCallback, void *aClosure); diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index a8e1954a49a..ecffc388409 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -6394,26 +6394,24 @@ DebugWrapperTraceCallback(void *p, const char *name, void *closure) // static void -nsContentUtils::CheckCCWrapperTraversal(nsISupports* aScriptObjectHolder, - nsWrapperCache* aCache) +nsContentUtils::CheckCCWrapperTraversal(void* aScriptObjectHolder, + nsWrapperCache* aCache, + nsScriptObjectTracer* aTracer) { JSObject* wrapper = aCache->GetWrapper(); if (!wrapper) { return; } - nsXPCOMCycleCollectionParticipant* participant; - CallQueryInterface(aScriptObjectHolder, &participant); - DebugWrapperTraversalCallback callback(wrapper); - participant->Traverse(aScriptObjectHolder, callback); + aTracer->Traverse(aScriptObjectHolder, callback); NS_ASSERTION(callback.mFound, "Cycle collection participant didn't traverse to preserved " "wrapper! This will probably crash."); callback.mFound = false; - participant->Trace(aScriptObjectHolder, DebugWrapperTraceCallback, &callback); + aTracer->Trace(aScriptObjectHolder, DebugWrapperTraceCallback, &callback); NS_ASSERTION(callback.mFound, "Cycle collection participant didn't trace preserved wrapper! " "This will probably crash."); @@ -6932,7 +6930,7 @@ nsContentUtils::GetRootDocument(nsIDocument* aDoc) // static void -nsContentUtils::ReleaseWrapper(nsISupports* aScriptObjectHolder, +nsContentUtils::ReleaseWrapper(void* aScriptObjectHolder, nsWrapperCache* aCache) { if (aCache->PreservingWrapper()) { diff --git a/dom/base/nsWrapperCache.h b/dom/base/nsWrapperCache.h index 89c4a9a3b9a..a5b6a8c1b27 100644 --- a/dom/base/nsWrapperCache.h +++ b/dom/base/nsWrapperCache.h @@ -226,6 +226,9 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsWrapperCache, NS_WRAPPERCACHE_IID) #define NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \ nsContentUtils::ReleaseWrapper(s, tmp); +#define NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER_NATIVE \ + nsContentUtils::ReleaseWrapper(tmp, tmp); + #define NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class) \ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(_class) \ NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER \ diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 57d4b18818f..0dde2449dd8 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -93,11 +93,16 @@ def DOMClass(descriptor): protoList.extend(['prototypes::id::_ID_Count'] * (descriptor.config.maxProtoChainLength - len(protoList))) prototypeChainString = ', '.join(protoList) nativeHooks = "NULL" if descriptor.workers else "&NativeHooks" + if descriptor.workers or descriptor.nativeOwnership != 'refcounted': + participant = "nullptr" + else: + participant = "NS_CYCLE_COLLECTION_PARTICIPANT(%s)" % descriptor.nativeType return """{ { %s }, - %s, %s + %s, %s, %s }""" % (prototypeChainString, toStringBool(descriptor.nativeOwnership == 'nsisupports'), - nativeHooks) + nativeHooks, + participant) class CGDOMJSClass(CGThing): """ @@ -633,12 +638,13 @@ class CGAddPropertyHook(CGAbstractClassHook): 'JSBool', args) def generate_code(self): - # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=774279 - # Using a real trace hook might enable us to deal with non-nsISupports - # wrappercached things here. - assert self.descriptor.nativeOwnership == 'nsisupports' - return """ nsContentUtils::PreserveWrapper(reinterpret_cast(self), self); - return true;""" + assert not self.descriptor.workers and self.descriptor.wrapperCache + if self.descriptor.nativeOwnership == 'nsisupports': + preserveArgs = "reinterpret_cast(self), self" + else: + preserveArgs = "self, self, NS_CYCLE_COLLECTION_PARTICIPANT(%s)" % self.descriptor.nativeType + return """ nsContentUtils::PreserveWrapper(%s); + return true;""" % preserveArgs def DeferredFinalizeSmartPtr(descriptor): if descriptor.nativeOwnership == 'owned': diff --git a/dom/bindings/Configuration.py b/dom/bindings/Configuration.py index 283f6f75fe6..1ef0c2a1e0e 100644 --- a/dom/bindings/Configuration.py +++ b/dom/bindings/Configuration.py @@ -266,7 +266,9 @@ class Descriptor(DescriptorProvider): self.customTrace = desc.get('customTrace', self.workers) self.customFinalize = desc.get('customFinalize', self.workers) self.wrapperCache = (not self.interface.isCallback() and - (self.workers or desc.get('wrapperCache', True))) + (self.workers or + (self.nativeOwnership != 'owned' and + desc.get('wrapperCache', True)))) if not self.wrapperCache and self.prefable: raise TypeError("Descriptor for %s is prefable but not wrappercached" % diff --git a/dom/bindings/DOMJSClass.h b/dom/bindings/DOMJSClass.h index b59787a5ca4..d16547fbd6a 100644 --- a/dom/bindings/DOMJSClass.h +++ b/dom/bindings/DOMJSClass.h @@ -11,6 +11,8 @@ #include "mozilla/dom/PrototypeList.h" // auto-generated +class nsCycleCollectionParticipant; + // We use slot 0 for holding the raw object. This is safe for both // globals and non-globals. #define DOM_OBJECT_SLOT 0 @@ -66,6 +68,11 @@ struct DOMClass const bool mDOMObjectIsISupports; const NativePropertyHooks* mNativeHooks; + + // This stores the CC participant for the native, null if this class is for a + // worker or for a native inheriting from nsISupports (we can get the CC + // participant by QI'ing in that case). + nsCycleCollectionParticipant* mParticipant; }; // Special JSClass for reflected DOM objects. diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index 2d689d4094b..51870f78bbd 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -847,10 +847,16 @@ NoteGCThingXPCOMChildren(js::Class *clasp, JSObject *obj, static_cast(js::GetProxyPrivate(obj).toPrivate()); cb.NoteXPCOMChild(identity); } else { - nsISupports *identity; - if (UnwrapDOMObjectToISupports(obj, identity)) { + const DOMClass* domClass; + DOMObjectSlot slot = GetDOMClass(obj, domClass); + if (slot != eNonDOMObject) { NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "UnwrapDOMObject(obj)"); - cb.NoteXPCOMChild(identity); + if (domClass->mDOMObjectIsISupports) { + cb.NoteXPCOMChild(UnwrapDOMObject(obj, slot)); + } else if (domClass->mParticipant) { + cb.NoteNativeChild(UnwrapDOMObject(obj, slot), + domClass->mParticipant); + } } } }