Bug 853910 part 1. Stop using prclist for our list of ListenerCollections. r=khuey
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 27 Mar 2013 22:47:25 -0400
changeset 126516 86253d3b7facbe116ca5277955dae767da944d8c
parent 126515 d507ab8a001946dfae3357686f583275733cfb27
child 126517 1b8b0c20f8bae72293315d97b55ec06983f0926f
push id24485
push userryanvm@gmail.com
push dateThu, 28 Mar 2013 12:31:20 +0000
treeherdermozilla-central@293498096b28 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs853910
milestone22.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 853910 part 1. Stop using prclist for our list of ListenerCollections. r=khuey
dom/workers/EventListenerManager.cpp
dom/workers/EventListenerManager.h
--- a/dom/workers/EventListenerManager.cpp
+++ b/dom/workers/EventListenerManager.cpp
@@ -7,55 +7,64 @@
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "js/Vector.h"
 #include "js/GCAPI.h"
 #include "mozilla/Util.h"
 #include "nsAutoJSValHolder.h"
 
+#include "prclist.h"
+
 #include "Events.h"
 #include "EventTarget.h"
 
 using namespace mozilla::dom;
+using namespace mozilla;
 USING_WORKERS_NAMESPACE
-using mozilla::ErrorResult;
 
-namespace {
-
-struct ListenerCollection : PRCList
+struct EventListenerManager::ListenerCollection :
+  public LinkedListElement<EventListenerManager::ListenerCollection>
 {
   jsid mTypeId;
   PRCList mListenerHead;
 
   static ListenerCollection*
-  Add(JSContext* aCx, ListenerCollection* aCollectionHead, jsid aTypeId)
+  Add(JSContext* aCx, LinkedList<ListenerCollection>& aCollections, jsid aTypeId)
   {
     ListenerCollection* collection =
       static_cast<ListenerCollection*>(JS_malloc(aCx,
                                                  sizeof(ListenerCollection)));
     if (!collection) {
       return NULL;
     }
 
-    PR_APPEND_LINK(collection, aCollectionHead);
+    new (collection) ListenerCollection(aTypeId);
+    aCollections.insertBack(collection);
 
-    collection->mTypeId = aTypeId;
-    PR_INIT_CLIST(&collection->mListenerHead);
     return collection;
   }
 
   static void
   Remove(JSContext* aCx, ListenerCollection* aCollection)
   {
-    PR_REMOVE_LINK(aCollection);
+    aCollection->remove();
     JS_free(aCx, aCollection);
   }
+
+private:
+  ListenerCollection(jsid aTypeId)
+    : mTypeId(aTypeId)
+  {
+    PR_INIT_CLIST(&mListenerHead);
+  }
 };
 
+namespace {
+
 struct ListenerData : PRCList
 {
   JSObject* mListener;
   EventListenerManager::Phase mPhase;
   bool mWantsUntrusted;
 
   static ListenerData*
   Add(JSContext* aCx, ListenerData* aListenerDataHead, JSObject* aListener,
@@ -92,28 +101,40 @@ DestroyList(JSFreeOp* aFop, PRCList* aLi
 {
   for (PRCList* elem = PR_NEXT_LINK(aListHead); elem != aListHead; ) {
     PRCList* nextElem = PR_NEXT_LINK(elem);
     JS_freeop(aFop, elem);
     elem = nextElem;
   }
 }
 
-inline ListenerCollection*
-GetCollectionForType(const PRCList* aHead, const jsid& aTypeId)
+template<typename T>
+inline void
+DestroyList(JSFreeOp* aFop, LinkedList<T>& aList)
 {
-  for (PRCList* elem = PR_NEXT_LINK(aHead);
-       elem != aHead;
-       elem = PR_NEXT_LINK(elem)) {
-    ListenerCollection* collection = static_cast<ListenerCollection*>(elem);
+  while (!aList.isEmpty()) {
+    T* elem = aList.popFirst();
+    JS_freeop(aFop, elem);
+  }
+}
+
+inline EventListenerManager::ListenerCollection*
+GetCollectionForType(const LinkedList<EventListenerManager::ListenerCollection>& aList,
+                     const jsid& aTypeId)
+{
+  for (const EventListenerManager::ListenerCollection* collection = aList.getFirst();
+       collection;
+       collection = collection->getNext()) {
     if (collection->mTypeId == aTypeId) {
-      return collection;
+      // We need to either cast away const here or write a second copy of this
+      // method that takes a non-const LinkedList
+      return const_cast<EventListenerManager::ListenerCollection*>(collection);
     }
   }
-  return NULL;
+  return nullptr;
 }
 
 class ContextAllocPolicy
 {
   JSContext* const mCx;
 
 public:
   ContextAllocPolicy(JSContext* aCx)
@@ -147,72 +168,66 @@ public:
   }
 };
 
 } // anonymous namespace
 
 #ifdef DEBUG
 EventListenerManager::~EventListenerManager()
 {
-  MOZ_ASSERT(PR_CLIST_IS_EMPTY(&mCollectionHead));
+  MOZ_ASSERT(mCollections.isEmpty());
 }
 #endif
 
 void
 EventListenerManager::TraceInternal(JSTracer* aTrc) const
 {
-  MOZ_ASSERT(!PR_CLIST_IS_EMPTY(&mCollectionHead));
+  MOZ_ASSERT(!mCollections.isEmpty());
 
-  for (PRCList* collectionElem = PR_NEXT_LINK(&mCollectionHead);
-       collectionElem != &mCollectionHead;
-       collectionElem = PR_NEXT_LINK(collectionElem)) {
-    ListenerCollection* collection =
-      static_cast<ListenerCollection*>(collectionElem);
+  for (const ListenerCollection* collection = mCollections.getFirst();
+       collection;
+       collection = collection->getNext()) {
 
     for (PRCList* listenerElem = PR_NEXT_LINK(&collection->mListenerHead);
          listenerElem != &collection->mListenerHead;
          listenerElem = PR_NEXT_LINK(listenerElem)) {
       JS_CALL_OBJECT_TRACER(aTrc,
                             static_cast<ListenerData*>(listenerElem)->mListener,
                             "EventListenerManager listener object");
     }
   }
 }
 
 void
 EventListenerManager::FinalizeInternal(JSFreeOp* aFop)
 {
-  MOZ_ASSERT(!PR_CLIST_IS_EMPTY(&mCollectionHead));
+  MOZ_ASSERT(!mCollections.isEmpty());
 
-  for (PRCList* elem = PR_NEXT_LINK(&mCollectionHead);
-       elem != &mCollectionHead;
-       elem = PR_NEXT_LINK(elem)) {
-    DestroyList(aFop, &static_cast<ListenerCollection*>(elem)->mListenerHead);
+  for (ListenerCollection* collection = mCollections.getFirst();
+       collection;
+       collection = collection->getNext()) {
+    DestroyList(aFop, &collection->mListenerHead);
   }
 
-  DestroyList(aFop, &mCollectionHead);
+  DestroyList(aFop, mCollections);
 
-#ifdef DEBUG
-  PR_INIT_CLIST(&mCollectionHead);
-#endif
+  MOZ_ASSERT(mCollections.isEmpty());
 }
 
 void
 EventListenerManager::Add(JSContext* aCx, const jsid& aType,
                           JSObject* aListener, Phase aPhase,
                           bool aWantsUntrusted, ErrorResult& aRv)
 {
   MOZ_ASSERT(aListener);
 
   ListenerCollection* collection =
-    GetCollectionForType(&mCollectionHead, aType);
+    GetCollectionForType(mCollections, aType);
   if (!collection) {
-    ListenerCollection* head =
-      static_cast<ListenerCollection*>(&mCollectionHead);
-    collection = ListenerCollection::Add(aCx, head, aType);
+    collection = ListenerCollection::Add(aCx, mCollections, aType);
     if (!collection) {
       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
       return;
     }
   }
 
   for (PRCList* elem = PR_NEXT_LINK(&collection->mListenerHead);
        elem != &collection->mListenerHead;
@@ -237,51 +252,49 @@ EventListenerManager::Add(JSContext* aCx
 void
 EventListenerManager::Remove(JSContext* aCx, const jsid& aType,
                              JSObject* aListener, Phase aPhase,
                              bool aClearEmpty)
 {
   MOZ_ASSERT(aListener);
 
   ListenerCollection* collection =
-    GetCollectionForType(&mCollectionHead, aType);
+    GetCollectionForType(mCollections, aType);
   if (collection) {
-  for (PRCList* elem = PR_NEXT_LINK(&collection->mListenerHead);
-       elem != &collection->mListenerHead;
-       elem = PR_NEXT_LINK(elem)) {
+    for (PRCList* elem = PR_NEXT_LINK(&collection->mListenerHead);
+         elem != &collection->mListenerHead;
+         elem = PR_NEXT_LINK(elem)) {
       ListenerData* listenerData = static_cast<ListenerData*>(elem);
       if (listenerData->mListener == aListener &&
           listenerData->mPhase == aPhase) {
         ListenerData::Remove(aCx, listenerData);
-      if (aClearEmpty && PR_CLIST_IS_EMPTY(&collection->mListenerHead)) {
-        ListenerCollection::Remove(aCx, collection);
+        if (aClearEmpty && PR_CLIST_IS_EMPTY(&collection->mListenerHead)) {
+          ListenerCollection::Remove(aCx, collection);
+        }
+        break;
       }
-      break;
     }
   }
-  }
 }
 
 JSObject*
 EventListenerManager::GetEventListener(const jsid& aType) const
 {
-  if (!PR_CLIST_IS_EMPTY(&mCollectionHead)) {
-    const ListenerCollection* collection =
-      GetCollectionForType(&mCollectionHead, aType);
+  const ListenerCollection* collection =
+    GetCollectionForType(mCollections, aType);
   if (collection) {
     for (PRCList* elem = PR_PREV_LINK(&collection->mListenerHead);
          elem != &collection->mListenerHead;
          elem = PR_NEXT_LINK(elem)) {
         ListenerData* listenerData = static_cast<ListenerData*>(elem);
         if (listenerData->mPhase == Onfoo) {
           return listenerData->mListener;
       }
     }
   }
-    }
 
   return NULL;
 }
 
 bool
 EventListenerManager::DispatchEvent(JSContext* aCx, const EventTarget& aTarget,
                                     JSObject* aEvent, ErrorResult& aRv) const
 {
@@ -299,17 +312,17 @@ EventListenerManager::DispatchEvent(JSCo
   }
 
   if (!JSVAL_IS_NULL(val)) {
     // Already has a target, must be recursively dispatched. Throw.
     aRv.Throw(NS_ERROR_FAILURE);
     return false;
   }
 
-  if (PR_CLIST_IS_EMPTY(&mCollectionHead)) {
+  if (mCollections.isEmpty()) {
     return false;
   }
 
   JSString* eventType;
   JSBool eventIsTrusted;
 
   if (!JS_GetProperty(aCx, aEvent, "type", &val) ||
       !(eventType = JS_ValueToString(aCx, val)) ||
@@ -322,18 +335,17 @@ EventListenerManager::DispatchEvent(JSCo
   // there is no need to worry about this property being faked.
   if (!JS_GetProperty(aCx, aEvent, "isTrusted", &val) ||
       !JS_ValueToBoolean(aCx, val, &eventIsTrusted)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return false;
   }
 
   ListenerCollection* collection =
-    GetCollectionForType(&mCollectionHead,
-                         INTERNED_STRING_TO_JSID(aCx, eventType));
+    GetCollectionForType(mCollections, INTERNED_STRING_TO_JSID(aCx, eventType));
   if (!collection) {
     return false;
   }
 
   ContextAllocPolicy ap(aCx);
 
   // XXXbent There is no reason to use nsAutoJSValHolder here as we should be
   //         able to use js::AutoValueVector. Worse, nsAutoJSValHolder is much
@@ -431,11 +443,11 @@ EventListenerManager::DispatchEvent(JSCo
 
   return EventWasCanceled(aEvent);
 }
 
 bool
 EventListenerManager::HasListenersForTypeInternal(JSContext* aCx,
                                                   const jsid& aType) const
 {
-  MOZ_ASSERT(!PR_CLIST_IS_EMPTY(&mCollectionHead));
-  return !!GetCollectionForType(&mCollectionHead, aType);
+  MOZ_ASSERT(!mCollections.isEmpty());
+  return !!GetCollectionForType(mCollections, aType);
 }
--- a/dom/workers/EventListenerManager.h
+++ b/dom/workers/EventListenerManager.h
@@ -3,52 +3,55 @@
  * 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/. */
 
 #ifndef mozilla_dom_workers_listenermanager_h__
 #define mozilla_dom_workers_listenermanager_h__
 
 #include "mozilla/dom/workers/Workers.h"
 
-#include "prclist.h"
+#include "mozilla/LinkedList.h"
 
 #include "mozilla/ErrorResult.h"
 
 BEGIN_WORKERS_NAMESPACE
 
 class EventTarget;
 
 // XXX Current impl doesn't divide into phases.
 // XXX Current impl doesn't handle event target chains.
 class EventListenerManager
 {
-  PRCList mCollectionHead;
+public:
+  struct ListenerCollection;
+
+private:
+  LinkedList<ListenerCollection> mCollections;
 
 public:
   EventListenerManager()
   {
-    PR_INIT_CLIST(&mCollectionHead);
   }
 
 #ifdef DEBUG
   ~EventListenerManager();
 #endif
 
   void
   _trace(JSTracer* aTrc) const
   {
-    if (!PR_CLIST_IS_EMPTY(&mCollectionHead)) {
+    if (!mCollections.isEmpty()) {
       TraceInternal(aTrc);
     }
   }
 
   void
   _finalize(JSFreeOp* aFop)
   {
-    if (!PR_CLIST_IS_EMPTY(&mCollectionHead)) {
+    if (!mCollections.isEmpty()) {
       FinalizeInternal(aFop);
     }
   }
 
   enum Phase
   {
     All = 0,
     Capturing,
@@ -63,17 +66,17 @@ public:
     Add(aCx, aType, aListener, aCapturing ? Capturing : Bubbling,
         aWantsUntrusted, aRv);
   }
 
   void
   RemoveEventListener(JSContext* aCx, const jsid& aType, JSObject* aListener,
                       bool aCapturing)
   {
-    if (PR_CLIST_IS_EMPTY(&mCollectionHead)) {
+    if (mCollections.isEmpty()) {
       return;
     }
     Remove(aCx, aType, aListener, aCapturing ? Capturing : Bubbling, true);
   }
 
   bool
   DispatchEvent(JSContext* aCx, const EventTarget& aTarget, JSObject* aEvent,
                 ErrorResult& aRv) const;
@@ -93,17 +96,17 @@ public:
     if (aListener) {
       Add(aCx, aType, aListener, Onfoo, false, aRv);
     }
   }
 
   bool
   HasListeners() const
   {
-    return !PR_CLIST_IS_EMPTY(&mCollectionHead);
+    return !mCollections.isEmpty();
   }
 
   bool
   HasListenersForType(JSContext* aCx, const jsid& aType) const
   {
     return HasListeners() && HasListenersForTypeInternal(aCx, aType);
   }