Backed out changeset 8e006947db44 (bug 1186780)
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 27 Jul 2015 08:00:29 +0200
changeset 254643 f388b16123561fa8305e432a66132c4ac397c625
parent 254642 1eb0af29f4c6bafe669e17ca1d85fb80b9004514
child 254644 d1df3bc0b4fda6e61fad6c6e96eedcb3b77cdae8
push id29108
push userryanvm@gmail.com
push dateMon, 27 Jul 2015 14:12:01 +0000
treeherdermozilla-central@27ae736ef960 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1186780
milestone42.0a1
backs out8e006947db44911314c3a936991be7eb84d2cb84
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
Backed out changeset 8e006947db44 (bug 1186780)
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,65 +331,96 @@ 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)
-  for (auto iter = tmp->mCustomDefinitions.ConstIter(); !iter.Done();
-       iter.Next()) {
-    aCallbacks.Trace(&iter.UserData()->mPrototype,
-                     "mCustomDefinitions prototype",
-                     aClosure);
-  }
+  CustomDefinitionTraceArgs customDefinitionArgs = { aCallbacks, aClosure };
+  tmp->mCustomDefinitions.EnumerateRead(CustomDefinitionTrace,
+                                        &customDefinitionArgs);
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Registry)
-  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));
-    }
-  }
+  tmp->mCustomDefinitions.EnumerateRead(CustomDefinitionsTraverse, &cb);
+  tmp->mCandidatesMap.EnumerateRead(CandidatesTraverse, &cb);
   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
 
@@ -906,70 +937,109 @@ 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)
 {
-  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
+  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
 {
   // mPendingLoads will get cleared out as the requests complete, so
   // no need to worry about those here.
-  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);
-  }
+  mMap.EnumerateRead(ExternalResourceTraverser, aCallback);
+}
+
+static PLDHashOperator
+ExternalResourceHider(nsIURI* aKey,
+                      nsExternalResourceMap::ExternalResource* aData,
+                      void* aClosure)
+{
+  if (aData->mViewer) {
+    aData->mViewer->Hide();
+  }
+  return PL_DHASH_NEXT;
 }
 
 void
 nsExternalResourceMap::HideViewers()
 {
-  for (auto iter = mMap.ConstIter(); !iter.Done(); iter.Next()) {
-    if (auto viewer = iter.UserData()->mViewer) {
-      viewer->Hide();
-    }
-  }
+  mMap.EnumerateRead(ExternalResourceHider, nullptr);
+}
+
+static PLDHashOperator
+ExternalResourceShower(nsIURI* aKey,
+                       nsExternalResourceMap::ExternalResource* aData,
+                       void* aClosure)
+{
+  if (aData->mViewer) {
+    aData->mViewer->Show();
+  }
+  return PL_DHASH_NEXT;
 }
 
 void
 nsExternalResourceMap::ShowViewers()
 {
-  for (auto iter = mMap.ConstIter(); !iter.Done(); iter.Next()) {
-    if (auto viewer = iter.UserData()->mViewer) {
-      viewer->Show();
-    }
-  }
+  mMap.EnumerateRead(ExternalResourceShower, nullptr);
 }
 
 void
 TransferZoomLevels(nsIDocument* aFromDoc,
                    nsIDocument* aToDoc)
 {
   MOZ_ASSERT(aFromDoc && aToDoc,
              "transferring zoom levels from/to null doc");
@@ -1528,16 +1598,25 @@ 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();
   }
@@ -1668,17 +1747,20 @@ nsDocument::~nsDocument()
   }
 
   if (mStyleImageLoader) {
     mStyleImageLoader->DropDocumentReference();
   }
 
   delete mHeaderData;
 
-  MaybeClearBoxObjectTable();
+  if (mBoxObjectTable) {
+    mBoxObjectTable->EnumerateRead(ClearAllBoxObjects, nullptr);
+    delete mBoxObjectTable;
+  }
 
   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();
 
@@ -1779,16 +1861,28 @@ 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)",
@@ -1860,21 +1954,17 @@ 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) {
-    for (auto iter = tmp->mBoxObjectTable->ConstIter(); !iter.Done();
-         iter.Next()) {
-      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mBoxObjectTable entry");
-      cb.NoteXPCOMChild(iter.UserData());
-    }
+    tmp->mBoxObjectTable->EnumerateRead(BoxObjectTraverser, &cb);
   }
 
   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)
@@ -1983,17 +2073,22 @@ 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)
 
-  tmp->MaybeClearBoxObjectTable();
+
+  if (tmp->mBoxObjectTable) {
+   tmp->mBoxObjectTable->EnumerateRead(ClearAllBoxObjects, nullptr);
+   delete tmp->mBoxObjectTable;
+   tmp->mBoxObjectTable = nullptr;
+ }
 
   if (tmp->mListenerManager) {
     tmp->mListenerManager->Disconnect();
     tmp->UnsetFlags(NODE_HAS_LISTENERMANAGER);
     tmp->mListenerManager = nullptr;
   }
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
@@ -3752,33 +3847,16 @@ 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()
@@ -3816,33 +3894,39 @@ 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.
-  for (auto iter = mImageTracker.ConstIter(); !iter.Done(); iter.Next()) {
-    iter.Key()->RequestDiscard();
-  }
+  mImageTracker.EnumerateRead(RequestDiscardEnumerator, nullptr);
 
   // 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;
 }
 
@@ -10540,61 +10624,84 @@ 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.
-  for (auto iter = mImageTracker.ConstIter(); !iter.Done(); iter.Next()) {
-    imgIRequest* image = iter.Key();
-    if (aLocked) {
-      image->LockImage();
-      image->RequestDecode();
-    } else {
-      image->UnlockImage();
-    }
-  }
+  mImageTracker.EnumerateRead(aLocked ? LockEnumerator
+                                      : UnlockEnumerator,
+                              nullptr);
 
   // 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.
-  for (auto iter = mImageTracker.ConstIter(); !iter.Done(); iter.Next()) {
-    imgIRequest* image = iter.Key();
-    if (aAnimating) {
-      image->IncrementAnimationConsumers();
-    } else {
-      image->DecrementAnimationConsumers();
-    }
-  }
+  mImageTracker.EnumerateRead(aAnimating ? IncrementAnimationEnumerator
+                                         : DecrementAnimationEnumerator,
+                              nullptr);
 
   // Update state.
   mAnimatingImages = aAnimating;
 }
 
 already_AddRefed<Touch>
 nsIDocument::CreateTouch(nsIDOMWindow* aView,
                          EventTarget* aTarget,
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -1732,18 +1732,16 @@ 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,28 +115,36 @@ 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)
-  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());
-    }
-  }
+  tmp->mListeners.EnumerateRead(CycleCollectorTraverseListeners,
+                                static_cast<void*>(&cb));
   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
@@ -402,42 +410,62 @@ 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);
-
-    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));
-        }
-      }
-    }
-  }
+  // 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);
 #endif
 
   nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners =
     mListeners.Get(aMessage);
   if (!listeners) {
     listeners = new nsAutoTObserverArray<nsMessageListenerInfo, 1>();
     mListeners.Put(aMessage, listeners);
   } else {
@@ -1439,55 +1467,65 @@ 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)
 {
-  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++;
-      }
-    }
-  }
+  aMessageManager->mListeners.EnumerateRead(CollectMessageListenerData,
+                                            aReferentCount);
 
   // 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);
   }
@@ -2124,29 +2162,34 @@ 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()
 {
-  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);
-      }
-    }
-  }
+  mListeners.EnumerateRead(CycleCollectorMarkListeners, nullptr);
 
   if (mRefCnt.IsPurple()) {
     mRefCnt.RemovePurple();
   }
   return true;
 }
 
 nsSameProcessAsyncMessageBase::nsSameProcessAsyncMessageBase(JSContext* aCx,
--- a/dom/xbl/nsXBLDocumentInfo.cpp
+++ b/dom/xbl/nsXBLDocumentInfo.cpp
@@ -311,23 +311,28 @@ 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) {
-    for (auto iter = mBindingTable->ConstIter(); !iter.Done(); iter.Next()) {
-      iter.UserData()->FlushSkinSheets();
-    }
+    mBindingTable->EnumerateRead(FlushScopedSkinSheets, nullptr);
   }
 }
 
 #ifdef DEBUG
 void
 AssertInCompilationScope()
 {
   AutoJSContext cx;