Bug 1186780: Replace EnumerateRead with new iterators in some DOM code. r=bkelly
☠☠ backed out by f388b1612356 ☠ ☠
authorKyle Huey <khuey@kylehuey.com>
Sun, 26 Jul 2015 19:34:29 -0700
changeset 286279 8e006947db44911314c3a936991be7eb84d2cb84
parent 286278 1ca5723f69d4af4cd3492c4bb8d3a06bd1fed774
child 286280 5f2e5a9fb54da77c775a924e5696b80bfcae1e99
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbkelly
bugs1186780
milestone42.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 1186780: Replace EnumerateRead with new iterators in some DOM code. r=bkelly
dom/base/nsDocument.cpp
dom/base/nsDocument.h
dom/base/nsFrameMessageManager.cpp
dom/xbl/nsXBLDocumentInfo.cpp
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -331,96 +331,65 @@ template<>
 struct nsIStyleRule::COMTypeInfo<css::Rule, void> {
   static const nsIID kIID;
 };
 const nsIID nsIStyleRule::COMTypeInfo<css::Rule, void>::kIID = NS_ISTYLE_RULE_IID;
 
 namespace mozilla {
 namespace dom {
 
-static PLDHashOperator
-CustomDefinitionsTraverse(CustomElementHashKey* aKey,
-                          CustomElementDefinition* aDefinition,
-                          void* aArg)
-{
-  nsCycleCollectionTraversalCallback* cb =
-    static_cast<nsCycleCollectionTraversalCallback*>(aArg);
-
-  nsAutoPtr<LifecycleCallbacks>& callbacks = aDefinition->mCallbacks;
-
-  if (callbacks->mAttributeChangedCallback.WasPassed()) {
-    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
-      "mCustomDefinitions->mCallbacks->mAttributeChangedCallback");
-    cb->NoteXPCOMChild(aDefinition->mCallbacks->mAttributeChangedCallback.Value());
-  }
-
-  if (callbacks->mCreatedCallback.WasPassed()) {
-    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
-      "mCustomDefinitions->mCallbacks->mCreatedCallback");
-    cb->NoteXPCOMChild(aDefinition->mCallbacks->mCreatedCallback.Value());
-  }
-
-  if (callbacks->mAttachedCallback.WasPassed()) {
-    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
-      "mCustomDefinitions->mCallbacks->mAttachedCallback");
-    cb->NoteXPCOMChild(aDefinition->mCallbacks->mAttachedCallback.Value());
-  }
-
-  if (callbacks->mDetachedCallback.WasPassed()) {
-    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
-      "mCustomDefinitions->mCallbacks->mDetachedCallback");
-    cb->NoteXPCOMChild(aDefinition->mCallbacks->mDetachedCallback.Value());
-  }
-
-  return PL_DHASH_NEXT;
-}
-
-static PLDHashOperator
-CandidatesTraverse(CustomElementHashKey* aKey,
-                   nsTArray<nsRefPtr<Element>>* aData,
-                   void* aArg)
-{
-  nsCycleCollectionTraversalCallback *cb =
-    static_cast<nsCycleCollectionTraversalCallback*>(aArg);
-  for (size_t i = 0; i < aData->Length(); ++i) {
-    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mCandidatesMap->Element");
-    cb->NoteXPCOMChild(aData->ElementAt(i));
-  }
-  return PL_DHASH_NEXT;
-}
-
-struct CustomDefinitionTraceArgs
-{
-  const TraceCallbacks& callbacks;
-  void* closure;
-};
-
-static PLDHashOperator
-CustomDefinitionTrace(CustomElementHashKey *aKey,
-                      CustomElementDefinition *aData,
-                      void *aArg)
-{
-  CustomDefinitionTraceArgs* traceArgs = static_cast<CustomDefinitionTraceArgs*>(aArg);
-  MOZ_ASSERT(aData, "Definition must not be null");
-  traceArgs->callbacks.Trace(&aData->mPrototype, "mCustomDefinitions prototype",
-                             traceArgs->closure);
-  return PL_DHASH_NEXT;
-}
-
 NS_IMPL_CYCLE_COLLECTION_CLASS(Registry)
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Registry)
-  CustomDefinitionTraceArgs customDefinitionArgs = { aCallbacks, aClosure };
-  tmp->mCustomDefinitions.EnumerateRead(CustomDefinitionTrace,
-                                        &customDefinitionArgs);
+  for (auto iter = tmp->mCustomDefinitions.ConstIter(); !iter.Done();
+       iter.Next()) {
+    aCallbacks.Trace(&iter.UserData()->mPrototype,
+                     "mCustomDefinitions prototype",
+                     aClosure);
+  }
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Registry)
-  tmp->mCustomDefinitions.EnumerateRead(CustomDefinitionsTraverse, &cb);
-  tmp->mCandidatesMap.EnumerateRead(CandidatesTraverse, &cb);
+  for (auto iter = tmp->mCustomDefinitions.ConstIter(); !iter.Done();
+       iter.Next()) {
+    CustomElementDefinition* definition = iter.UserData();
+    auto callbacks = definition->mCallbacks;
+
+    if (callbacks->mAttributeChangedCallback.WasPassed()) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
+        "mCustomDefinitions->mCallbacks->mAttributeChangedCallback");
+      cb.NoteXPCOMChild(callbacks->mAttributeChangedCallback.Value());
+    }
+
+    if (callbacks->mCreatedCallback.WasPassed()) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
+        "mCustomDefinitions->mCallbacks->mCreatedCallback");
+      cb.NoteXPCOMChild(callbacks->mCreatedCallback.Value());
+    }
+
+    if (callbacks->mAttachedCallback.WasPassed()) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
+        "mCustomDefinitions->mCallbacks->mAttachedCallback");
+      cb.NoteXPCOMChild(callbacks->mAttachedCallback.Value());
+    }
+
+    if (callbacks->mDetachedCallback.WasPassed()) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
+        "mCustomDefinitions->mCallbacks->mDetachedCallback");
+      cb.NoteXPCOMChild(callbacks->mDetachedCallback.Value());
+    }
+  }
+
+  for (auto iter = tmp->mCandidatesMap.ConstIter(); !iter.Done(); iter.Next()) {
+    auto data = iter.UserData();
+    for (size_t i = 0; i < data->Length(); ++i) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCandidatesMap->Element");
+      cb.NoteXPCOMChild(data->ElementAt(i));
+    }
+  }
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Registry)
   tmp->mCustomDefinitions.Clear();
   tmp->mCandidatesMap.Clear();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
@@ -937,109 +906,70 @@ nsExternalResourceMap::RequestResource(n
     AddExternalResource(clone, nullptr, nullptr, aDisplayDocument);
   } else {
     load.forget(aPendingLoad);
   }
 
   return nullptr;
 }
 
-struct
-nsExternalResourceEnumArgs
-{
-  nsIDocument::nsSubDocEnumFunc callback;
-  void *data;
-};
-
-static PLDHashOperator
-ExternalResourceEnumerator(nsIURI* aKey,
-                           nsExternalResourceMap::ExternalResource* aData,
-                           void* aClosure)
-{
-  nsExternalResourceEnumArgs* args =
-    static_cast<nsExternalResourceEnumArgs*>(aClosure);
-  bool next =
-    aData->mDocument ? args->callback(aData->mDocument, args->data) : true;
-  return next ? PL_DHASH_NEXT : PL_DHASH_STOP;
-}
-
 void
 nsExternalResourceMap::EnumerateResources(nsIDocument::nsSubDocEnumFunc aCallback,
                                           void* aData)
 {
-  nsExternalResourceEnumArgs args = { aCallback, aData };
-  mMap.EnumerateRead(ExternalResourceEnumerator, &args);
-}
-
-static PLDHashOperator
-ExternalResourceTraverser(nsIURI* aKey,
-                          nsExternalResourceMap::ExternalResource* aData,
-                          void* aClosure)
-{
-  nsCycleCollectionTraversalCallback *cb =
-    static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
-
-  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
-                                     "mExternalResourceMap.mMap entry"
-                                     "->mDocument");
-  cb->NoteXPCOMChild(aData->mDocument);
-
-  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
-                                     "mExternalResourceMap.mMap entry"
-                                     "->mViewer");
-  cb->NoteXPCOMChild(aData->mViewer);
-
-  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
-                                     "mExternalResourceMap.mMap entry"
-                                     "->mLoadGroup");
-  cb->NoteXPCOMChild(aData->mLoadGroup);
-
-  return PL_DHASH_NEXT;
-}
-
-void
-nsExternalResourceMap::Traverse(nsCycleCollectionTraversalCallback* aCallback) const
+  for (auto iter = mMap.ConstIter(); !iter.Done(); iter.Next()) {
+    auto data = iter.UserData();
+    if (data->mDocument && !aCallback(data->mDocument, aData)) {
+      break;
+    }
+  }
+}
+
+void
+nsExternalResourceMap::Traverse(nsCycleCollectionTraversalCallback* cb) const
 {
   // mPendingLoads will get cleared out as the requests complete, so
   // no need to worry about those here.
-  mMap.EnumerateRead(ExternalResourceTraverser, aCallback);
-}
-
-static PLDHashOperator
-ExternalResourceHider(nsIURI* aKey,
-                      nsExternalResourceMap::ExternalResource* aData,
-                      void* aClosure)
-{
-  if (aData->mViewer) {
-    aData->mViewer->Hide();
-  }
-  return PL_DHASH_NEXT;
+  for (auto iter = mMap.ConstIter(); !iter.Done(); iter.Next()) {
+    auto data = iter.UserData();
+    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
+                                       "mExternalResourceMap.mMap entry"
+                                       "->mDocument");
+    cb->NoteXPCOMChild(data->mDocument);
+
+    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
+                                       "mExternalResourceMap.mMap entry"
+                                       "->mViewer");
+    cb->NoteXPCOMChild(data->mViewer);
+
+    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
+                                       "mExternalResourceMap.mMap entry"
+                                       "->mLoadGroup");
+    cb->NoteXPCOMChild(data->mLoadGroup);
+  }
 }
 
 void
 nsExternalResourceMap::HideViewers()
 {
-  mMap.EnumerateRead(ExternalResourceHider, nullptr);
-}
-
-static PLDHashOperator
-ExternalResourceShower(nsIURI* aKey,
-                       nsExternalResourceMap::ExternalResource* aData,
-                       void* aClosure)
-{
-  if (aData->mViewer) {
-    aData->mViewer->Show();
-  }
-  return PL_DHASH_NEXT;
+  for (auto iter = mMap.ConstIter(); !iter.Done(); iter.Next()) {
+    if (auto viewer = iter.UserData()->mViewer) {
+      viewer->Hide();
+    }
+  }
 }
 
 void
 nsExternalResourceMap::ShowViewers()
 {
-  mMap.EnumerateRead(ExternalResourceShower, nullptr);
+  for (auto iter = mMap.ConstIter(); !iter.Done(); iter.Next()) {
+    if (auto viewer = iter.UserData()->mViewer) {
+      viewer->Show();
+    }
+  }
 }
 
 void
 TransferZoomLevels(nsIDocument* aFromDoc,
                    nsIDocument* aToDoc)
 {
   MOZ_ASSERT(aFromDoc && aToDoc,
              "transferring zoom levels from/to null doc");
@@ -1598,25 +1528,16 @@ nsDocument::nsDocument(const char* aCont
 
   if (!sProcessingStack) {
     sProcessingStack.emplace();
     // Add the base queue sentinel to the processing stack.
     sProcessingStack->AppendElement((CustomElementData*) nullptr);
   }
 }
 
-static PLDHashOperator
-ClearAllBoxObjects(nsIContent* aKey, nsPIBoxObject* aBoxObject, void* aUserArg)
-{
-  if (aBoxObject) {
-    aBoxObject->Clear();
-  }
-  return PL_DHASH_NEXT;
-}
-
 nsIDocument::~nsIDocument()
 {
   MOZ_ASSERT(PR_CLIST_IS_EMPTY(&mDOMMediaQueryLists),
              "must not have media query lists left");
 
   if (mNodeInfoManager) {
     mNodeInfoManager->DropDocumentReference();
   }
@@ -1747,20 +1668,17 @@ nsDocument::~nsDocument()
   }
 
   if (mStyleImageLoader) {
     mStyleImageLoader->DropDocumentReference();
   }
 
   delete mHeaderData;
 
-  if (mBoxObjectTable) {
-    mBoxObjectTable->EnumerateRead(ClearAllBoxObjects, nullptr);
-    delete mBoxObjectTable;
-  }
+  MaybeClearBoxObjectTable();
 
   mPendingTitleChangeEvent.Revoke();
 
   // We don't want to leave residual locks on images. Make sure we're in an
   // unlocked state, and then clear the table.
   SetImageLockingState(false);
   mImageTracker.Clear();
 
@@ -1861,28 +1779,16 @@ RadioGroupsTraverser(const nsAString& aK
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
                                        "mRadioGroups entry->mRadioButtons[i]");
     cb->NoteXPCOMChild(aData->mRadioButtons[i]);
   }
 
   return PL_DHASH_NEXT;
 }
 
-static PLDHashOperator
-BoxObjectTraverser(nsIContent* key, nsPIBoxObject* boxObject, void* userArg)
-{
-  nsCycleCollectionTraversalCallback *cb =
-    static_cast<nsCycleCollectionTraversalCallback*>(userArg);
-
-  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mBoxObjectTable entry");
-  cb->NoteXPCOMChild(boxObject);
-
-  return PL_DHASH_NEXT;
-}
-
 static const char* kNSURIs[] = {
   "([none])",
   "(xmlns)",
   "(xml)",
   "(xhtml)",
   "(XLink)",
   "(XSLT)",
   "(XBL)",
@@ -1954,17 +1860,21 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMasterDocument)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImportManager)
 
   tmp->mRadioGroups.EnumerateRead(RadioGroupsTraverser, &cb);
 
   // The boxobject for an element will only exist as long as it's in the
   // document, so we'll traverse the table here instead of from the element.
   if (tmp->mBoxObjectTable) {
-    tmp->mBoxObjectTable->EnumerateRead(BoxObjectTraverser, &cb);
+    for (auto iter = tmp->mBoxObjectTable->ConstIter(); !iter.Done();
+         iter.Next()) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mBoxObjectTable entry");
+      cb.NoteXPCOMChild(iter.UserData());
+    }
   }
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannel)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleAttrStyleSheet)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mXPathEvaluator)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLayoutHistoryState)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnloadBlocker)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFirstBaseNodeWithHref)
@@ -2073,22 +1983,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mImportManager)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSubImportLinks)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
 
   tmp->mParentDocument = nullptr;
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPreloadingImages)
 
-
-  if (tmp->mBoxObjectTable) {
-   tmp->mBoxObjectTable->EnumerateRead(ClearAllBoxObjects, nullptr);
-   delete tmp->mBoxObjectTable;
-   tmp->mBoxObjectTable = nullptr;
- }
+  tmp->MaybeClearBoxObjectTable();
 
   if (tmp->mListenerManager) {
     tmp->mListenerManager->Disconnect();
     tmp->UnsetFlags(NODE_HAS_LISTENERMANAGER);
     tmp->mListenerManager = nullptr;
   }
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
@@ -3847,16 +3752,33 @@ nsDocument::MaybeRescheduleAnimationFram
 
   nsRefreshDriver* rd = mPresShell->GetPresContext()->RefreshDriver();
   if (!mFrameRequestCallbacks.IsEmpty()) {
     rd->ScheduleFrameRequestCallbacks(this);
   }
 }
 
 void
+nsDocument::MaybeClearBoxObjectTable()
+{
+  if (!mBoxObjectTable) {
+    return;
+  }
+
+  for (auto iter = mBoxObjectTable->ConstIter(); !iter.Done(); iter.Next()) {
+    if (auto boxObject = iter.UserData()) {
+      boxObject->Clear();
+    }
+  }
+
+  delete mBoxObjectTable;
+  mBoxObjectTable = nullptr;
+}
+
+void
 nsIDocument::TakeFrameRequestCallbacks(FrameRequestCallbackList& aCallbacks)
 {
   aCallbacks.AppendElements(mFrameRequestCallbacks);
   mFrameRequestCallbacks.Clear();
 }
 
 bool
 nsIDocument::ShouldThrottleFrameRequests()
@@ -3894,39 +3816,33 @@ nsIDocument::ShouldThrottleFrameRequests
     // platforms and is unlikely to be human-perceivable on non-APZ platforms.
     return true;
   }
 
   // We got painted during the last paint, so run at full speed.
   return false;
 }
 
-PLDHashOperator RequestDiscardEnumerator(imgIRequest* aKey,
-                                         uint32_t aData,
-                                         void* userArg)
-{
-  aKey->RequestDiscard();
-  return PL_DHASH_NEXT;
-}
-
 void
 nsDocument::DeleteShell()
 {
   mExternalResourceMap.HideViewers();
   if (IsEventHandlingEnabled()) {
     RevokeAnimationFrameNotifications();
   }
   if (nsPresContext* presContext = mPresShell->GetPresContext()) {
     presContext->RefreshDriver()->CancelPendingEvents(this);
   }
 
   // When our shell goes away, request that all our images be immediately
   // discarded, so we don't carry around decoded image data for a document we
   // no longer intend to paint.
-  mImageTracker.EnumerateRead(RequestDiscardEnumerator, nullptr);
+  for (auto iter = mImageTracker.ConstIter(); !iter.Done(); iter.Next()) {
+    iter.Key()->RequestDiscard();
+  }
 
   // Now that we no longer have a shell, we need to forget about any FontFace
   // objects for @font-face rules that came from the style set.
   RebuildUserFontSet();
 
   mPresShell = nullptr;
 }
 
@@ -10624,84 +10540,61 @@ nsDocument::NotifyMediaFeatureValuesChan
     nsCOMPtr<nsIContent> content = iter.Get()->GetKey();
     if (content->IsHTMLElement(nsGkAtoms::img)) {
       auto* imageElement = static_cast<HTMLImageElement*>(content.get());
       imageElement->MediaFeatureValuesChanged();
     }
   }
 }
 
-PLDHashOperator LockEnumerator(imgIRequest* aKey,
-                               uint32_t aData,
-                               void*    userArg)
-{
-  aKey->LockImage();
-  aKey->RequestDecode();
-  return PL_DHASH_NEXT;
-}
-
-PLDHashOperator UnlockEnumerator(imgIRequest* aKey,
-                                 uint32_t aData,
-                                 void*    userArg)
-{
-  aKey->UnlockImage();
-  return PL_DHASH_NEXT;
-}
-
-
 nsresult
 nsDocument::SetImageLockingState(bool aLocked)
 {
   if (XRE_IsContentProcess() &&
       !Preferences::GetBool("image.mem.allow_locking_in_content_processes", true)) {
     return NS_OK;
   }
 
   // If there's no change, there's nothing to do.
   if (mLockingImages == aLocked)
     return NS_OK;
 
   // Otherwise, iterate over our images and perform the appropriate action.
-  mImageTracker.EnumerateRead(aLocked ? LockEnumerator
-                                      : UnlockEnumerator,
-                              nullptr);
+  for (auto iter = mImageTracker.ConstIter(); !iter.Done(); iter.Next()) {
+    imgIRequest* image = iter.Key();
+    if (aLocked) {
+      image->LockImage();
+      image->RequestDecode();
+    } else {
+      image->UnlockImage();
+    }
+  }
 
   // Update state.
   mLockingImages = aLocked;
 
   return NS_OK;
 }
 
-PLDHashOperator IncrementAnimationEnumerator(imgIRequest* aKey,
-                                             uint32_t aData,
-                                             void*    userArg)
-{
-  aKey->IncrementAnimationConsumers();
-  return PL_DHASH_NEXT;
-}
-
-PLDHashOperator DecrementAnimationEnumerator(imgIRequest* aKey,
-                                             uint32_t aData,
-                                             void*    userArg)
-{
-  aKey->DecrementAnimationConsumers();
-  return PL_DHASH_NEXT;
-}
-
 void
 nsDocument::SetImagesNeedAnimating(bool aAnimating)
 {
   // If there's no change, there's nothing to do.
   if (mAnimatingImages == aAnimating)
     return;
 
   // Otherwise, iterate over our images and perform the appropriate action.
-  mImageTracker.EnumerateRead(aAnimating ? IncrementAnimationEnumerator
-                                         : DecrementAnimationEnumerator,
-                              nullptr);
+  for (auto iter = mImageTracker.ConstIter(); !iter.Done(); iter.Next()) {
+    imgIRequest* image = iter.Key();
+    if (aAnimating) {
+      image->IncrementAnimationConsumers();
+    } else {
+      image->DecrementAnimationConsumers();
+    }
+  }
 
   // Update state.
   mAnimatingImages = aAnimating;
 }
 
 already_AddRefed<Touch>
 nsIDocument::CreateTouch(nsIDOMWindow* aView,
                          EventTarget* aTarget,
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -1732,16 +1732,18 @@ private:
                                        bool aUpdateCSSLoader);
 
   // Revoke any pending notifications due to requestAnimationFrame calls
   void RevokeAnimationFrameNotifications();
   // Reschedule any notifications we need to handle
   // requestAnimationFrame, if it's OK to do so.
   void MaybeRescheduleAnimationFrameNotifications();
 
+  void MaybeClearBoxObjectTable();
+
   // These are not implemented and not supported.
   nsDocument(const nsDocument& aOther);
   nsDocument& operator=(const nsDocument& aOther);
 
   // The layout history state that should be used by nodes in this
   // document.  We only actually store a pointer to it when:
   // 1)  We have no script global object.
   // 2)  We haven't had Destroy() called on us yet.
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -115,36 +115,28 @@ nsFrameMessageManager::~nsFrameMessageMa
       delete mozilla::dom::SameProcessMessageQueue::Get();
     }
     if (this == sSameProcessParentManager) {
       sSameProcessParentManager = nullptr;
     }
   }
 }
 
-static PLDHashOperator
-CycleCollectorTraverseListeners(const nsAString& aKey,
-                                nsAutoTObserverArray<nsMessageListenerInfo, 1>* aListeners,
-                                void* aCb)
-{
-  nsCycleCollectionTraversalCallback* cb =
-    static_cast<nsCycleCollectionTraversalCallback*> (aCb);
-  uint32_t count = aListeners->Length();
-  for (uint32_t i = 0; i < count; ++i) {
-    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "listeners[i] mStrongListener");
-    cb->NoteXPCOMChild(aListeners->ElementAt(i).mStrongListener.get());
-  }
-  return PL_DHASH_NEXT;
-}
-
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsFrameMessageManager)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFrameMessageManager)
-  tmp->mListeners.EnumerateRead(CycleCollectorTraverseListeners,
-                                static_cast<void*>(&cb));
+  for (auto iter = tmp->mListeners.ConstIter(); !iter.Done(); iter.Next()) {
+    auto listeners = iter.UserData();
+    const uint32_t count = listeners->Length();
+
+    for (uint32_t i = 0; i < count; ++i) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "listeners[i] mStrongListener");
+      cb.NoteXPCOMChild(listeners->ElementAt(i).mStrongListener.get());
+    }
+  }
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildManagers)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsFrameMessageManager)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mInitialProcessData)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
@@ -410,62 +402,42 @@ nsFrameMessageManager::RemoveMessageList
     if (listeners->ElementAt(i).mStrongListener == aListener) {
       listeners->RemoveElementAt(i);
       return NS_OK;
     }
   }
   return NS_OK;
 }
 
-#ifdef DEBUG
-typedef struct
-{
-  nsCOMPtr<nsISupports> mCanonical;
-  nsWeakPtr mWeak;
-} CanonicalCheckerParams;
-
-static PLDHashOperator
-CanonicalChecker(const nsAString& aKey,
-                 nsAutoTObserverArray<nsMessageListenerInfo, 1>* aListeners,
-                 void* aParams)
-{
-  CanonicalCheckerParams* params =
-    static_cast<CanonicalCheckerParams*> (aParams);
-
-  uint32_t count = aListeners->Length();
-  for (uint32_t i = 0; i < count; i++) {
-    if (!aListeners->ElementAt(i).mWeakListener) {
-      continue;
-    }
-    nsCOMPtr<nsISupports> otherCanonical =
-      do_QueryReferent(aListeners->ElementAt(i).mWeakListener);
-    MOZ_ASSERT((params->mCanonical == otherCanonical) ==
-               (params->mWeak == aListeners->ElementAt(i).mWeakListener));
-  }
-  return PL_DHASH_NEXT;
-}
-#endif
-
 NS_IMETHODIMP
 nsFrameMessageManager::AddWeakMessageListener(const nsAString& aMessage,
                                               nsIMessageListener* aListener)
 {
   nsWeakPtr weak = do_GetWeakReference(aListener);
   NS_ENSURE_TRUE(weak, NS_ERROR_NO_INTERFACE);
 
 #ifdef DEBUG
-  // It's technically possible that one object X could give two different
-  // nsIWeakReference*'s when you do_GetWeakReference(X).  We really don't want
-  // this to happen; it will break e.g. RemoveWeakMessageListener.  So let's
-  // check that we're not getting ourselves into that situation.
-  nsCOMPtr<nsISupports> canonical = do_QueryInterface(aListener);
-  CanonicalCheckerParams params;
-  params.mCanonical = canonical;
-  params.mWeak = weak;
-  mListeners.EnumerateRead(CanonicalChecker, (void*)&params);
+  {
+    // It's technically possible that one object X could give two different
+    // nsIWeakReference*'s when you do_GetWeakReference(X).  We really don't
+    // want this to happen; it will break e.g. RemoveWeakMessageListener.  So
+    // let's check that we're not getting ourselves into that situation.
+    nsCOMPtr<nsISupports> canonical = do_QueryInterface(aListener);
+
+    for (auto iter = mListeners.ConstIter(); !iter.Done(); iter.Next()) {
+      auto listeners = iter.UserData();
+      const uint32_t count = listeners->Length();
+      for (uint32_t i = 0; i < count; i++) {
+        if (auto listener = listeners->ElementAt(i).mWeakListener) {
+          nsCOMPtr<nsISupports> otherCanonical = do_QueryReferent(listener);
+          MOZ_ASSERT((canonical == otherCanonical) == (weak == listener));
+        }
+      }
+    }
+  }
 #endif
 
   nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners =
     mListeners.Get(aMessage);
   if (!listeners) {
     listeners = new nsAutoTObserverArray<nsMessageListenerInfo, 1>();
     mListeners.Put(aMessage, listeners);
   } else {
@@ -1467,65 +1439,55 @@ public:
   static const size_t kSuspectReferentCount = 300;
 protected:
   void CountReferents(nsFrameMessageManager* aMessageManager,
                       MessageManagerReferentCount* aReferentCount);
 };
 
 NS_IMPL_ISUPPORTS(MessageManagerReporter, nsIMemoryReporter)
 
-static PLDHashOperator
-CollectMessageListenerData(const nsAString& aKey,
-                           nsAutoTObserverArray<nsMessageListenerInfo, 1>* aListeners,
-                           void* aData)
-{
-  MessageManagerReferentCount* referentCount =
-    static_cast<MessageManagerReferentCount*>(aData);
-
-  uint32_t listenerCount = aListeners->Length();
-  if (!listenerCount) {
-    return PL_DHASH_NEXT;
-  }
-
-  nsString key(aKey);
-  uint32_t oldCount = 0;
-  referentCount->mMessageCounter.Get(key, &oldCount);
-  uint32_t currentCount = oldCount + listenerCount;
-  referentCount->mMessageCounter.Put(key, currentCount);
-
-  // Keep track of messages that have a suspiciously large
-  // number of referents (symptom of leak).
-  if (currentCount == MessageManagerReporter::kSuspectReferentCount) {
-    referentCount->mSuspectMessages.AppendElement(key);
-  }
-
-  for (uint32_t i = 0; i < listenerCount; ++i) {
-    const nsMessageListenerInfo& listenerInfo =
-      aListeners->ElementAt(i);
-    if (listenerInfo.mWeakListener) {
-      nsCOMPtr<nsISupports> referent =
-        do_QueryReferent(listenerInfo.mWeakListener);
-      if (referent) {
-        referentCount->mWeakAlive++;
-      } else {
-        referentCount->mWeakDead++;
-      }
-    } else {
-      referentCount->mStrong++;
-    }
-  }
-  return PL_DHASH_NEXT;
-}
-
 void
 MessageManagerReporter::CountReferents(nsFrameMessageManager* aMessageManager,
                                        MessageManagerReferentCount* aReferentCount)
 {
-  aMessageManager->mListeners.EnumerateRead(CollectMessageListenerData,
-                                            aReferentCount);
+  for (auto iter = aMessageManager->mListeners.ConstIter();
+       !iter.Done(); iter.Next()) {
+    auto listeners = iter.UserData();
+    const uint32_t listenerCount = listeners->Length();
+    if (!listenerCount) {
+      continue;
+    }
+
+    nsString key(iter.Key());
+    uint32_t oldCount = 0;
+    aReferentCount->mMessageCounter.Get(key, &oldCount);
+    uint32_t currentCount = oldCount + listenerCount;
+    aReferentCount->mMessageCounter.Put(key, currentCount);
+
+    // Keep track of messages that have a suspiciously large
+    // number of referents (symptom of leak).
+    if (currentCount == MessageManagerReporter::kSuspectReferentCount) {
+      aReferentCount->mSuspectMessages.AppendElement(key);
+    }
+
+    for (uint32_t i = 0; i < listenerCount; ++i) {
+      const nsMessageListenerInfo& listenerInfo = listeners->ElementAt(i);
+      if (listenerInfo.mWeakListener) {
+        nsCOMPtr<nsISupports> referent =
+          do_QueryReferent(listenerInfo.mWeakListener);
+        if (referent) {
+          aReferentCount->mWeakAlive++;
+        } else {
+          aReferentCount->mWeakDead++;
+        }
+      } else {
+        aReferentCount->mStrong++;
+      }
+    }
+  }
 
   // Add referent count in child managers because the listeners
   // participate in messages dispatched from parent message manager.
   for (uint32_t i = 0; i < aMessageManager->mChildManagers.Length(); ++i) {
     nsRefPtr<nsFrameMessageManager> mm =
       static_cast<nsFrameMessageManager*>(aMessageManager->mChildManagers[i]);
     CountReferents(mm, aReferentCount);
   }
@@ -2162,34 +2124,29 @@ NS_NewChildProcessMessageManager(nsISync
   nsFrameMessageManager::SetChildProcessManager(mm);
   nsRefPtr<ProcessGlobal> global = new ProcessGlobal(mm);
   NS_ENSURE_TRUE(global->Init(), NS_ERROR_UNEXPECTED);
   global.forget(aResult);
   return NS_OK;
 
 }
 
-static PLDHashOperator
-CycleCollectorMarkListeners(const nsAString& aKey,
-                            nsAutoTObserverArray<nsMessageListenerInfo, 1>* aListeners,
-                            void* aData)
-{
-  uint32_t count = aListeners->Length();
-  for (uint32_t i = 0; i < count; i++) {
-    if (aListeners->ElementAt(i).mStrongListener) {
-      xpc_TryUnmarkWrappedGrayObject(aListeners->ElementAt(i).mStrongListener);
-    }
-  }
-  return PL_DHASH_NEXT;
-}
-
 bool
 nsFrameMessageManager::MarkForCC()
 {
-  mListeners.EnumerateRead(CycleCollectorMarkListeners, nullptr);
+  for (auto iter = mListeners.ConstIter(); !iter.Done(); iter.Next()) {
+    auto listeners = iter.UserData();
+    const uint32_t count = listeners->Length();
+
+    for (uint32_t i = 0; i < count; i++) {
+      if (auto listener = listeners->ElementAt(i).mStrongListener) {
+        xpc_TryUnmarkWrappedGrayObject(listener);
+      }
+    }
+  }
 
   if (mRefCnt.IsPurple()) {
     mRefCnt.RemovePurple();
   }
   return true;
 }
 
 nsSameProcessAsyncMessageBase::nsSameProcessAsyncMessageBase(JSContext* aCx,
--- a/dom/xbl/nsXBLDocumentInfo.cpp
+++ b/dom/xbl/nsXBLDocumentInfo.cpp
@@ -311,28 +311,23 @@ nsXBLDocumentInfo::WritePrototypeBinding
 }
 
 void
 nsXBLDocumentInfo::SetFirstPrototypeBinding(nsXBLPrototypeBinding* aBinding)
 {
   mFirstBinding = aBinding;
 }
 
-static PLDHashOperator
-FlushScopedSkinSheets(const nsACString &aKey, nsXBLPrototypeBinding *aProto, void* aClosure)
-{
-  aProto->FlushSkinSheets();
-  return PL_DHASH_NEXT;
-}
-
 void
 nsXBLDocumentInfo::FlushSkinStylesheets()
 {
   if (mBindingTable) {
-    mBindingTable->EnumerateRead(FlushScopedSkinSheets, nullptr);
+    for (auto iter = mBindingTable->ConstIter(); !iter.Done(); iter.Next()) {
+      iter.UserData()->FlushSkinSheets();
+    }
   }
 }
 
 #ifdef DEBUG
 void
 AssertInCompilationScope()
 {
   AutoJSContext cx;