Bug 801719 - Unmark certainly alive event listener and message managers, r=mccr8
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Wed, 17 Oct 2012 04:22:02 +0300
changeset 110561 5a6a36d109d7eeb64cfe0bee5cab16290d093424
parent 110560 62f61773ad4577a1f5bffdac7eb00ffbee5ca1fc
child 110562 29f170efc8b72a2dc82b02f3d2c27c407d699aad
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersmccr8
bugs801719
milestone19.0a1
Bug 801719 - Unmark certainly alive event listener and message managers, r=mccr8
content/base/src/FragmentOrElement.cpp
content/base/src/WebSocket.cpp
content/base/src/nsCCUncollectableMarker.cpp
content/base/src/nsContentUtils.cpp
content/base/src/nsDocument.cpp
content/base/src/nsEventSource.cpp
content/base/src/nsFrameMessageManager.cpp
content/base/src/nsXMLHttpRequest.cpp
content/events/src/nsDOMEventTargetHelper.cpp
content/events/src/nsEventListenerManager.cpp
content/events/src/nsEventListenerManager.h
dom/base/nsGlobalWindow.cpp
--- a/content/base/src/FragmentOrElement.cpp
+++ b/content/base/src/FragmentOrElement.cpp
@@ -1232,17 +1232,17 @@ FragmentOrElement::MarkUserDataHandler(v
 void
 FragmentOrElement::MarkNodeChildren(nsINode* aNode)
 {
   JSObject* o = GetJSObjectChild(aNode);
   xpc_UnmarkGrayObject(o);
 
   nsEventListenerManager* elm = aNode->GetListenerManager(false);
   if (elm) {
-    elm->UnmarkGrayJSListeners();
+    elm->MarkForCC();
   }
 
   if (aNode->HasProperties()) {
     nsIDocument* ownerDoc = aNode->OwnerDoc();
     ownerDoc->PropertyTable(DOM_USER_DATA)->
       Enumerate(aNode, FragmentOrElement::MarkUserData,
                 &nsCCUncollectableMarker::sGeneration);
     ownerDoc->PropertyTable(DOM_USER_DATA_HANDLER)->
--- a/content/base/src/WebSocket.cpp
+++ b/content/base/src/WebSocket.cpp
@@ -580,17 +580,17 @@ WebSocket::Constructor(JSContext* aCx,
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(WebSocket)
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(WebSocket)
   bool isBlack = tmp->IsBlack();
   if (isBlack|| tmp->mKeepingAlive) {
     if (tmp->mListenerManager) {
-      tmp->mListenerManager->UnmarkGrayJSListeners();
+      tmp->mListenerManager->MarkForCC();
     }
     if (!isBlack && tmp->PreservingWrapper()) {
       xpc_UnmarkGrayObject(tmp->GetWrapperPreserveColor());
     }
     return true;
   }
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
 
--- a/content/base/src/nsCCUncollectableMarker.cpp
+++ b/content/base/src/nsCCUncollectableMarker.cpp
@@ -87,61 +87,91 @@ MarkUserDataHandler(void* aNode, nsIAtom
   if (d && nsCCUncollectableMarker::InGeneration(d->GetMarkedCCGeneration())) {
     nsGenericElement::MarkUserDataHandler(aNode, aKey, aValue, aData);
   }
 }
 
 static void
 MarkMessageManagers()
 {
-  nsCOMPtr<nsIMessageBroadcaster> globalMM =
+  nsCOMPtr<nsIMessageBroadcaster> strongGlobalMM =
     do_GetService("@mozilla.org/globalmessagemanager;1");
-  if (!globalMM) {
+  if (!strongGlobalMM) {
     return;
   }
+  nsIMessageBroadcaster* globalMM = strongGlobalMM;
+  strongGlobalMM = nullptr;
 
   globalMM->MarkForCC();
   uint32_t childCount = 0;
   globalMM->GetChildCount(&childCount);
   for (uint32_t i = 0; i < childCount; ++i) {
     nsCOMPtr<nsIMessageListenerManager> childMM;
     globalMM->GetChildAt(i, getter_AddRefs(childMM));
     if (!childMM) {
       continue;
     }
-    nsCOMPtr<nsIMessageBroadcaster> windowMM = do_QueryInterface(childMM);
+    nsCOMPtr<nsIMessageBroadcaster> strongWindowMM = do_QueryInterface(childMM);
+    nsIMessageBroadcaster* windowMM = strongWindowMM;
+    childMM = nullptr;
+    strongWindowMM = nullptr;
     windowMM->MarkForCC();
     uint32_t tabChildCount = 0;
     windowMM->GetChildCount(&tabChildCount);
     for (uint32_t j = 0; j < tabChildCount; ++j) {
       nsCOMPtr<nsIMessageListenerManager> childMM;
       windowMM->GetChildAt(j, getter_AddRefs(childMM));
       if (!childMM) {
         continue;
       }
-      nsCOMPtr<nsIMessageSender> tabMM = do_QueryInterface(childMM);
+      nsCOMPtr<nsIMessageSender> strongTabMM = do_QueryInterface(childMM);
+      nsIMessageSender* tabMM = strongTabMM;
+      childMM = nullptr;
+      strongTabMM = nullptr;
       tabMM->MarkForCC();
       //XXX hack warning, but works, since we know that
       //    callback is frameloader.
       mozilla::dom::ipc::MessageManagerCallback* cb =
-        static_cast<nsFrameMessageManager*>(tabMM.get())->GetCallback();
+        static_cast<nsFrameMessageManager*>(tabMM)->GetCallback();
       if (cb) {
         nsFrameLoader* fl = static_cast<nsFrameLoader*>(cb);
         nsIDOMEventTarget* et = fl->GetTabChildGlobalAsEventTarget();
         if (!et) {
           continue;
         }
         static_cast<nsInProcessTabChildGlobal*>(et)->MarkForCC();
         nsEventListenerManager* elm = et->GetListenerManager(false);
         if (elm) {
-          elm->UnmarkGrayJSListeners();
+          elm->MarkForCC();
         }
       }
     }
   }
+  if (nsFrameMessageManager::sParentProcessManager) {
+    nsFrameMessageManager::sParentProcessManager->MarkForCC();
+    uint32_t childCount = 0;
+    nsFrameMessageManager::sParentProcessManager->GetChildCount(&childCount);
+    for (uint32_t i = 0; i < childCount; ++i) {
+      nsCOMPtr<nsIMessageListenerManager> childMM;
+      nsFrameMessageManager::sParentProcessManager->
+        GetChildAt(i, getter_AddRefs(childMM));
+      if (!childMM) {
+        continue;
+      }
+      nsIMessageListenerManager* child = childMM;
+      childMM = nullptr;
+      child->MarkForCC();
+    }
+  }
+  if (nsFrameMessageManager::sSameProcessParentManager) {
+    nsFrameMessageManager::sSameProcessParentManager->MarkForCC();
+  }
+  if (nsFrameMessageManager::sChildProcessManager) {
+    nsFrameMessageManager::sChildProcessManager->MarkForCC();
+  }
 }
 
 void
 MarkContentViewer(nsIContentViewer* aViewer, bool aCleanupJS,
                   bool aPrepareForCC)
 {
   if (!aViewer) {
     return;
@@ -149,23 +179,23 @@ MarkContentViewer(nsIContentViewer* aVie
 
   nsIDocument *doc = aViewer->GetDocument();
   if (doc &&
       doc->GetMarkedCCGeneration() != nsCCUncollectableMarker::sGeneration) {
     doc->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
     if (aCleanupJS) {
       nsEventListenerManager* elm = doc->GetListenerManager(false);
       if (elm) {
-        elm->UnmarkGrayJSListeners();
+        elm->MarkForCC();
       }
       nsCOMPtr<nsIDOMEventTarget> win = do_QueryInterface(doc->GetInnerWindow());
       if (win) {
         elm = win->GetListenerManager(false);
         if (elm) {
-          elm->UnmarkGrayJSListeners();
+          elm->MarkForCC();
         }
         static_cast<nsGlobalWindow*>(win.get())->UnmarkGrayTimers();
       }
 
       doc->PropertyTable(DOM_USER_DATA_HANDLER)->
         EnumerateAll(MarkUserDataHandler, &nsCCUncollectableMarker::sGeneration);
     } else if (aPrepareForCC) {
       // Unfortunately we need to still mark user data just before running CC so
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -3913,17 +3913,17 @@ ListenerEnumerator(PLDHashTable* aTable,
                    uint32_t aNumber, void* aArg)
 {
   EventListenerManagerMapEntry* entry =
     static_cast<EventListenerManagerMapEntry*>(aEntry);
   if (entry) {
     nsINode* n = static_cast<nsINode*>(entry->mListenerManager->GetTarget());
     if (n && n->IsInDoc() &&
         nsCCUncollectableMarker::InGeneration(n->OwnerDoc()->GetMarkedCCGeneration())) {
-      entry->mListenerManager->UnmarkGrayJSListeners();
+      entry->mListenerManager->MarkForCC();
     }
   }
   return PL_DHASH_NEXT;
 }
 
 void
 nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments(uint32_t aGeneration)
 {
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1712,17 +1712,17 @@ NS_INTERFACE_MAP_END
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDocument)
 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(nsDocument,
                                               nsNodeUtils::LastRelease(this))
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsDocument)
   if (nsGenericElement::CanSkip(tmp, aRemovingAllowed)) {
     nsEventListenerManager* elm = tmp->GetListenerManager(false);
     if (elm) {
-      elm->UnmarkGrayJSListeners();
+      elm->MarkForCC();
     }
     return true;
   }
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsDocument)
   return nsGenericElement::CanSkipInCC(tmp);
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
--- a/content/base/src/nsEventSource.cpp
+++ b/content/base/src/nsEventSource.cpp
@@ -76,17 +76,17 @@ nsEventSource::~nsEventSource()
 //-----------------------------------------------------------------------------
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsEventSource)
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsEventSource)
   bool isBlack = tmp->IsBlack();
   if (isBlack || tmp->mWaitingForOnStopRequest) {
     if (tmp->mListenerManager) {
-      tmp->mListenerManager->UnmarkGrayJSListeners();
+      tmp->mListenerManager->MarkForCC();
     }
     if (!isBlack && tmp->PreservingWrapper()) {
       xpc_UnmarkGrayObject(tmp->GetWrapperPreserveColor());
     }
     return true;
   }
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
 
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -1321,10 +1321,13 @@ NS_NewChildProcessMessageManager(nsISync
 
 bool
 nsFrameMessageManager::MarkForCC()
 {
   uint32_t len = mListeners.Length();
   for (uint32_t i = 0; i < len; ++i) {
     xpc_TryUnmarkWrappedGrayObject(mListeners[i].mListener);
   }
+  if (mRefCnt.IsPurple()) {
+    mRefCnt.RemovePurple();
+  }
   return true;
 }
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -578,17 +578,17 @@ nsXMLHttpRequest::SetRequestObserver(nsI
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLHttpRequest)
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsXMLHttpRequest)
   bool isBlack = tmp->IsBlack();
   if (isBlack || tmp->mWaitingForOnStopRequest) {
     if (tmp->mListenerManager) {
-      tmp->mListenerManager->UnmarkGrayJSListeners();
+      tmp->mListenerManager->MarkForCC();
     }
     if (!isBlack && tmp->PreservingWrapper()) {
       xpc_UnmarkGrayObject(tmp->GetWrapperPreserveColor());
     }
     return true;
   }
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
 
--- a/content/events/src/nsDOMEventTargetHelper.cpp
+++ b/content/events/src/nsDOMEventTargetHelper.cpp
@@ -42,17 +42,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mListenerManager)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsDOMEventTargetHelper)
   if (tmp->IsBlack()) {
     if (tmp->mListenerManager) {
-      tmp->mListenerManager->UnmarkGrayJSListeners();
+      tmp->mListenerManager->MarkForCC();
     }
     return true;
   }
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsDOMEventTargetHelper)
   return tmp->IsBlackAndDoesNotNeedTracing(tmp);
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
--- a/content/events/src/nsEventListenerManager.cpp
+++ b/content/events/src/nsEventListenerManager.cpp
@@ -1174,22 +1174,25 @@ nsEventListenerManager::SizeOfIncludingT
     if (jsl) {
       n += jsl->SizeOfIncludingThis(aMallocSizeOf);
     }
   }
   return n;
 }
 
 void
-nsEventListenerManager::UnmarkGrayJSListeners()
+nsEventListenerManager::MarkForCC()
 {
   uint32_t count = mListeners.Length();
   for (uint32_t i = 0; i < count; ++i) {
     const nsListenerStruct& ls = mListeners.ElementAt(i);
     nsIJSEventListener* jsl = ls.GetJSListener();
     if (jsl) {
       xpc_UnmarkGrayObject(jsl->GetHandler());
       xpc_UnmarkGrayObject(jsl->GetEventScope());
     } else if (ls.mListenerType == eWrappedJSListener) {
       xpc_TryUnmarkWrappedGrayObject(ls.mListener);
     }
   }
+  if (mRefCnt.IsPurple()) {
+    mRefCnt.RemovePurple();
+  }
 }
--- a/content/events/src/nsEventListenerManager.h
+++ b/content/events/src/nsEventListenerManager.h
@@ -221,17 +221,17 @@ public:
    * false if there definitely isn't.
    */
   bool MayHaveTouchEventListener() { return mMayHaveTouchEventListener; }
 
   bool MayHaveMouseEnterLeaveEventListener() { return mMayHaveMouseEnterLeaveEventListener; }
 
   size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
 
-  void UnmarkGrayJSListeners();
+  void MarkForCC();
 
   nsISupports* GetTarget() { return mTarget; }
 protected:
   nsresult HandleEventSubType(nsListenerStruct* aListenerStruct,
                               nsIDOMEventListener* aListener,
                               nsIDOMEvent* aDOMEvent,
                               nsIDOMEventTarget* aCurrentTarget,
                               uint32_t aPhaseFlags,
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1264,17 +1264,17 @@ MarkXBLHandlers(nsXBLPrototypeHandler* a
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindow)
   if (tmp->IsBlackForCC()) {
     if (tmp->mCachedXBLPrototypeHandlers.IsInitialized()) {
       tmp->mCachedXBLPrototypeHandlers.EnumerateRead(MarkXBLHandlers, nullptr);
     }
     nsEventListenerManager* elm = tmp->GetListenerManager(false);
     if (elm) {
-      elm->UnmarkGrayJSListeners();
+      elm->MarkForCC();
     }
     tmp->UnmarkGrayTimers();
     return true;
   }
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindow)
   return tmp->IsBlackForCC();