Bug 1452074 - improve the performance related to unresolved custom elements, r=emilio
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Sat, 07 Apr 2018 12:50:01 +0300
changeset 457147 760dcfb2cca44358a66117c40eae2d4171968f15
parent 457146 e2a2139264a3562cacc422af8bfd1c4f05d60a8b
child 457205 a44f62799a10195778ea508881c38aa3169bcfef
push id153
push userfmarier@mozilla.com
push dateTue, 10 Apr 2018 02:28:40 +0000
reviewersemilio
bugs1452074
milestone61.0a1
Bug 1452074 - improve the performance related to unresolved custom elements, r=emilio
dom/base/CustomElementRegistry.cpp
dom/base/CustomElementRegistry.h
--- a/dom/base/CustomElementRegistry.cpp
+++ b/dom/base/CustomElementRegistry.cpp
@@ -350,36 +350,31 @@ CustomElementRegistry::RegisterUnresolve
   if (!typeName) {
     typeName = info->NameAtom();
   }
 
   if (mCustomDefinitions.GetWeak(typeName)) {
     return;
   }
 
-  nsTArray<nsWeakPtr>* unresolved = mCandidatesMap.LookupOrAdd(typeName);
-  nsWeakPtr* elem = unresolved->AppendElement();
-  *elem = do_GetWeakReference(aElement);
+  nsTHashtable<nsRefPtrHashKey<nsIWeakReference>>* unresolved =
+    mCandidatesMap.LookupOrAdd(typeName);
+  nsWeakPtr elem = do_GetWeakReference(aElement);
+  unresolved->PutEntry(elem);
 }
 
 void
 CustomElementRegistry::UnregisterUnresolvedElement(Element* aElement,
                                                    nsAtom* aTypeName)
 {
-  nsTArray<nsWeakPtr>* candidates;
+  nsTHashtable<nsRefPtrHashKey<nsIWeakReference>>* candidates = nullptr;
   if (mCandidatesMap.Get(aTypeName, &candidates)) {
     MOZ_ASSERT(candidates);
-    // We don't need to iterate the candidates array and remove the element from
-    // the array for performance reason. It'll be handled by bug 1396620.
-    for (size_t i = 0; i < candidates->Length(); ++i) {
-      nsCOMPtr<Element> elem = do_QueryReferent(candidates->ElementAt(i));
-      if (elem && elem.get() == aElement) {
-        candidates->RemoveElementAt(i);
-      }
-    }
+    nsWeakPtr weak = do_GetWeakReference(aElement);
+    candidates->RemoveEntry(weak);
   }
 }
 
 /* static */ UniquePtr<CustomElementCallback>
 CustomElementRegistry::CreateCustomElementCallback(
   nsIDocument::ElementCallbackType aType, Element* aCustomElement,
   LifecycleCallbackArgs* aArgs,
   LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs,
@@ -482,34 +477,35 @@ CustomElementRegistry::EnqueueLifecycleC
   reactionsStack->EnqueueCallbackReaction(aCustomElement, Move(callback));
 }
 
 namespace {
 
 class CandidateFinder
 {
 public:
-  CandidateFinder(nsTArray<nsWeakPtr>&& aCandidates, nsIDocument* aDoc);
+  CandidateFinder(nsTHashtable<nsRefPtrHashKey<nsIWeakReference>>& aCandidates,
+                  nsIDocument* aDoc);
   nsTArray<nsCOMPtr<Element>> OrderedCandidates();
 
 private:
   bool Traverse(Element* aRoot, nsTArray<nsCOMPtr<Element>>& aOrderedElements);
 
   nsCOMPtr<nsIDocument> mDoc;
   nsInterfaceHashtable<nsPtrHashKey<Element>, Element> mCandidates;
 };
 
-CandidateFinder::CandidateFinder(nsTArray<nsWeakPtr>&& aCandidates,
+CandidateFinder::CandidateFinder(nsTHashtable<nsRefPtrHashKey<nsIWeakReference>>& aCandidates,
                                  nsIDocument* aDoc)
   : mDoc(aDoc)
-  , mCandidates(aCandidates.Length())
+  , mCandidates(aCandidates.Count())
 {
   MOZ_ASSERT(mDoc);
-  for (auto& candidate : aCandidates) {
-    nsCOMPtr<Element> elem = do_QueryReferent(candidate);
+  for (auto iter = aCandidates.Iter(); !iter.Done(); iter.Next()) {
+    nsCOMPtr<Element> elem = do_QueryReferent(iter.Get()->GetKey());
     if (!elem) {
       continue;
     }
 
     Element* key = elem.get();
     mCandidates.Put(key, elem.forget());
   }
 }
@@ -576,23 +572,23 @@ CustomElementRegistry::UpgradeCandidates
                                          ErrorResult& aRv)
 {
   DocGroup* docGroup = mWindow->GetDocGroup();
   if (!docGroup) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
 
-  nsAutoPtr<nsTArray<nsWeakPtr>> candidates;
+  nsAutoPtr<nsTHashtable<nsRefPtrHashKey<nsIWeakReference>>> candidates;
   if (mCandidatesMap.Remove(aKey, &candidates)) {
     MOZ_ASSERT(candidates);
     CustomElementReactionsStack* reactionsStack =
       docGroup->CustomElementReactionsStack();
 
-    CandidateFinder finder(Move(*candidates), mWindow->GetExtantDoc());
+    CandidateFinder finder(*candidates, mWindow->GetExtantDoc());
     for (auto& elem : finder.OrderedCandidates()) {
       reactionsStack->EnqueueUpgradeReaction(elem, aDefinition);
     }
   }
 }
 
 JSObject*
 CustomElementRegistry::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
--- a/dom/base/CustomElementRegistry.h
+++ b/dom/base/CustomElementRegistry.h
@@ -416,17 +416,18 @@ private:
     CustomElementDefinition* aDefinition);
 
   void UpgradeCandidates(nsAtom* aKey,
                          CustomElementDefinition* aDefinition,
                          ErrorResult& aRv);
 
   typedef nsRefPtrHashtable<nsRefPtrHashKey<nsAtom>, CustomElementDefinition>
     DefinitionMap;
-  typedef nsClassHashtable<nsRefPtrHashKey<nsAtom>, nsTArray<nsWeakPtr>>
+  typedef nsClassHashtable<nsRefPtrHashKey<nsAtom>,
+                           nsTHashtable<nsRefPtrHashKey<nsIWeakReference>>>
     CandidateMap;
   typedef JS::GCHashMap<JS::Heap<JSObject*>,
                         RefPtr<nsAtom>,
                         js::MovableCellHasher<JS::Heap<JSObject*>>,
                         js::SystemAllocPolicy> ConstructorMap;
 
   // Hashtable for custom element definitions in web components.
   // Custom prototypes are stored in the compartment where definition was