Bug 794694 - Make sure to trace all the gray GCthings, not only wrapper, r=mccr8
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Sat, 29 Sep 2012 01:29:37 +0300
changeset 108519 b274e8e3479f556868412ea9fba4af4adf39deee
parent 108518 ed5f377741045a9caf858d4edff4685b50f11961
child 108609 b62b229a4d4191270e44bad30a8695c555eedadb
push id82
push usershu@rfrn.org
push dateFri, 05 Oct 2012 13:20:22 +0000
reviewersmccr8
bugs794694
milestone18.0a1
Bug 794694 - Make sure to trace all the gray GCthings, not only wrapper, r=mccr8
content/base/src/nsXMLHttpRequest.cpp
content/events/src/nsDOMEventTargetHelper.cpp
dom/base/nsWrapperCache.h
dom/base/nsWrapperCacheInlines.h
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -524,17 +524,18 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(
     if (!isBlack && tmp->PreservingWrapper()) {
       xpc_UnmarkGrayObject(tmp->GetWrapperPreserveColor());
     }
     return true;
   }
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsXMLHttpRequest)
-  return tmp->IsBlack();
+  return tmp->
+    IsBlackAndDoesNotNeedTracing(static_cast<nsDOMEventTargetHelper*>(tmp));
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsXMLHttpRequest)
   return tmp->IsBlack();
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLHttpRequest,
                                                   nsXHREventTarget)
--- a/content/events/src/nsDOMEventTargetHelper.cpp
+++ b/content/events/src/nsDOMEventTargetHelper.cpp
@@ -48,17 +48,17 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(
     if (tmp->mListenerManager) {
       tmp->mListenerManager->UnmarkGrayJSListeners();
     }
     return true;
   }
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsDOMEventTargetHelper)
-  return tmp->IsBlack();
+  return tmp->IsBlackAndDoesNotNeedTracing(tmp);
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsDOMEventTargetHelper)
   return tmp->IsBlack();
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMEventTargetHelper)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
--- a/dom/base/nsWrapperCache.h
+++ b/dom/base/nsWrapperCache.h
@@ -154,16 +154,22 @@ public:
     return nullptr;
   }
 
   /**
    * Returns true if the object has a non-gray wrapper.
    */
   bool IsBlack();
 
+  /**
+   * Returns true if the object has a black wrapper,
+   * and all the GC things it is keeping alive are black too.
+   */
+  bool IsBlackAndDoesNotNeedTracing(nsISupports* aThis);
+
   // Only meant to be called by code that preserves a wrapper.
   void SetPreservingWrapper(bool aPreserve)
   {
     if(aPreserve) {
       mWrapperPtrBits |= WRAPPER_BIT_PRESERVED;
     }
     else {
       mWrapperPtrBits &= ~WRAPPER_BIT_PRESERVED;
--- a/dom/base/nsWrapperCacheInlines.h
+++ b/dom/base/nsWrapperCacheInlines.h
@@ -19,9 +19,31 @@ nsWrapperCache::GetWrapper() const
 
 inline bool
 nsWrapperCache::IsBlack()
 {
   JSObject* o = GetWrapperPreserveColor();
   return o && !xpc_IsGrayGCThing(o);
 }
 
+static void
+SearchGray(void* aGCThing, const char* aName, void* aClosure)
+{
+  bool* hasGrayObjects = static_cast<bool*>(aClosure);
+  if (!*hasGrayObjects && aGCThing && xpc_IsGrayGCThing(aGCThing)) {
+    *hasGrayObjects = true;
+  }
+}
+
+inline bool
+nsWrapperCache::IsBlackAndDoesNotNeedTracing(nsISupports* aThis)
+{
+  if (IsBlack()) {
+    nsXPCOMCycleCollectionParticipant* participant = nullptr;
+    CallQueryInterface(aThis, &participant);
+    bool hasGrayObjects = false;
+    participant->Trace(aThis, SearchGray, &hasGrayObjects);
+    return !hasGrayObjects;
+  }
+  return false;
+}
+
 #endif /* nsWrapperCache_h___ */