Bug 1020622 - Trace black windows' (webidl) event listeners, r=mccr8
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Thu, 05 Jun 2014 02:48:50 +0300
changeset 186833 ec751fbe4ebd611c941cd6b4cf9e2a3ad42e39d7
parent 186832 4d8bd0baf6332ccc5428e657d834a9970e1e127a
child 186834 25abaa7e7bb518a7fc79219b73f4f7e262afcd0e
push idunknown
push userunknown
push dateunknown
reviewersmccr8
bugs1020622
milestone32.0a1
Bug 1020622 - Trace black windows' (webidl) event listeners, r=mccr8
content/base/src/nsCCUncollectableMarker.cpp
dom/events/EventListenerManager.cpp
dom/events/EventListenerManager.h
xpcom/base/CycleCollectedJSRuntime.cpp
xpcom/base/CycleCollectedJSRuntime.h
--- a/content/base/src/nsCCUncollectableMarker.cpp
+++ b/content/base/src/nsCCUncollectableMarker.cpp
@@ -435,16 +435,21 @@ struct TraceClosure
 };
 
 static PLDHashOperator
 TraceActiveWindowGlobal(const uint64_t& aId, nsGlobalWindow*& aWindow, void* aClosure)
 {
   if (aWindow->GetDocShell() && aWindow->IsOuterWindow()) {
     TraceClosure* closure = static_cast<TraceClosure*>(aClosure);
     aWindow->TraceGlobalJSObject(closure->mTrc);
+    EventListenerManager* elm = aWindow->GetExistingListenerManager();
+    if (elm) {
+      elm->TraceListeners(closure->mTrc);
+    }
+
 #ifdef MOZ_XUL
     nsIDocument* doc = aWindow->GetExtantDoc();
     if (doc && doc->IsXUL()) {
       XULDocument* xulDoc = static_cast<XULDocument*>(doc);
       xulDoc->TraceProtos(closure->mTrc, closure->mGCNumber);
     }
 #endif
   }
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Microsoft's API Name hackery sucks
 #undef CreateEvent
 
 #include "mozilla/BasicEvents.h"
+#include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventListenerManager.h"
 #ifdef MOZ_B2G
 #include "mozilla/Hal.h"
 #endif // #ifdef MOZ_B2G
 #include "mozilla/HalSensor.h"
 #include "mozilla/InternalMutationEvent.h"
 #include "mozilla/JSEventHandler.h"
@@ -1324,16 +1325,37 @@ EventListenerManager::MarkForCC()
       listener.mListener.GetWebIDLCallback()->Callback();
     }
   }
   if (mRefCnt.IsPurple()) {
     mRefCnt.RemovePurple();
   }
 }
 
+void
+EventListenerManager::TraceListeners(JSTracer* aTrc)
+{
+  uint32_t count = mListeners.Length();
+  for (uint32_t i = 0; i < count; ++i) {
+    const Listener& listener = mListeners.ElementAt(i);
+    JSEventHandler* jsEventHandler = listener.GetJSEventHandler();
+    if (jsEventHandler) {
+      const TypedEventHandler& typedHandler =
+        jsEventHandler->GetTypedEventHandler();
+      if (typedHandler.HasEventHandler()) {
+        mozilla::TraceScriptHolder(typedHandler.Ptr(), aTrc);
+      }
+    } else if (listener.mListenerType == Listener::eWebIDLListener) {
+      mozilla::TraceScriptHolder(listener.mListener.GetWebIDLCallback(), aTrc);
+    }
+    // We might have eWrappedJSListener, but that is the legacy type for
+    // JS implemented event listeners, and trickier to handle here.
+  }
+}
+
 already_AddRefed<nsIScriptGlobalObject>
 EventListenerManager::GetScriptGlobalAndDocument(nsIDocument** aDoc)
 {
   nsCOMPtr<nsINode> node(do_QueryInterface(mTarget));
   nsCOMPtr<nsIDocument> doc;
   nsCOMPtr<nsIScriptGlobalObject> global;
   if (node) {
     // Try to get context from doc
--- a/dom/events/EventListenerManager.h
+++ b/dom/events/EventListenerManager.h
@@ -15,16 +15,17 @@
 #include "nsGkAtoms.h"
 #include "nsIDOMEventListener.h"
 #include "nsTObserverArray.h"
 
 class nsIDOMEvent;
 class nsIEventListenerInfo;
 class nsIScriptContext;
 class nsPIDOMWindow;
+class JSTracer;
 
 struct EventTypeData;
 
 template<class T> class nsCOMArray;
 
 namespace mozilla {
 
 class ELMCreationDetector;
@@ -399,16 +400,18 @@ public:
 
   uint32_t ListenerCount() const
   {
     return mListeners.Length();
   }
 
   void MarkForCC();
 
+  void TraceListeners(JSTracer* aTrc);
+
   dom::EventTarget* GetTarget() { return mTarget; }
 
 protected:
   void HandleEventInternal(nsPresContext* aPresContext,
                            WidgetEvent* aEvent,
                            nsIDOMEvent** aDOMEvent,
                            dom::EventTarget* aCurrentTarget,
                            nsEventStatus* aEventStatus);
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -827,16 +827,24 @@ static PLDHashOperator
 TraceJSHolder(void* aHolder, nsScriptObjectTracer*& aTracer, void* aArg)
 {
   aTracer->Trace(aHolder, JsGcTracer(), aArg);
 
   return PL_DHASH_NEXT;
 }
 
 void
+mozilla::TraceScriptHolder(nsISupports* aHolder, JSTracer* aTracer)
+{
+  nsXPCOMCycleCollectionParticipant* participant = nullptr;
+  CallQueryInterface(aHolder, &participant);
+  participant->Trace(aHolder, JsGcTracer(), aTracer);
+}
+
+void
 CycleCollectedJSRuntime::TraceNativeGrayRoots(JSTracer* aTracer)
 {
   // NB: This is here just to preserve the existing XPConnect order. I doubt it
   // would hurt to do this after the JS holders.
   TraceAdditionalNativeGrayRoots(aTracer);
 
   mJSHolders.Enumerate(TraceJSHolder, aTracer);
 }
--- a/xpcom/base/CycleCollectedJSRuntime.h
+++ b/xpcom/base/CycleCollectedJSRuntime.h
@@ -305,11 +305,13 @@ private:
   nsCOMPtr<nsIException> mPendingException;
 
   OOMState mOutOfMemoryState;
   OOMState mLargeAllocationFailureState;
 };
 
 MOZ_FINISH_NESTED_ENUM_CLASS(CycleCollectedJSRuntime::OOMState)
 
+void TraceScriptHolder(nsISupports* aHolder, JSTracer* aTracer);
+
 } // namespace mozilla
 
 #endif // mozilla_CycleCollectedJSRuntime_h__