Bug 1484285 - Avoid loading XBL bindings for stuff that is very likely to be a custom-element. r=smaug
authorEmilio Cobos Álvarez <emilio@crisal.io>
Fri, 21 Sep 2018 21:29:25 +0000
changeset 493494 c7203fb6f1da54fbb3e54631d95da6d1f1008d6a
parent 493493 2efb7ae0315fa250f001d82a994e3eae60f36857
child 493495 5b433242973a2c5a310359e7e61b5066a949246b
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1484285
milestone64.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 1484285 - Avoid loading XBL bindings for stuff that is very likely to be a custom-element. r=smaug This should be more generic than hardcoding the tags, and be enough for our chrome to avoid regressions as they migrate more stuff to CE, avoiding calling into the GetComputedStyle machinery.. Differential Revision: https://phabricator.services.mozilla.com/D6537
dom/base/CustomElementRegistry.cpp
dom/base/CustomElementRegistry.h
dom/base/Element.cpp
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
--- a/dom/base/CustomElementRegistry.cpp
+++ b/dom/base/CustomElementRegistry.cpp
@@ -224,22 +224,16 @@ CustomElementDefinition*
 CustomElementData::GetCustomElementDefinition()
 {
   MOZ_ASSERT(mCustomElementDefinition ? mState == State::eCustom
                                       : mState != State::eCustom);
 
   return mCustomElementDefinition;
 }
 
-nsAtom*
-CustomElementData::GetCustomElementType()
-{
-  return mType;
-}
-
 void
 CustomElementData::Traverse(nsCycleCollectionTraversalCallback& aCb) const
 {
   for (uint32_t i = 0; i < mReactionQueue.Length(); i++) {
     if (mReactionQueue[i]) {
       mReactionQueue[i]->Traverse(aCb);
     }
   }
@@ -423,17 +417,17 @@ CustomElementRegistry::LookupCustomEleme
   if (!data) {
     RefPtr<CustomElementCreationCallback> callback;
     mElementCreationCallbacks.Get(aTypeAtom, getter_AddRefs(callback));
     if (callback) {
       mElementCreationCallbacks.Remove(aTypeAtom);
       mElementCreationCallbacksUpgradeCandidatesMap.LookupOrAdd(aTypeAtom);
       RefPtr<Runnable> runnable =
         new RunCustomElementCreationCallback(this, aTypeAtom, callback);
-      nsContentUtils::AddScriptRunner(runnable);
+      nsContentUtils::AddScriptRunner(runnable.forget());
       data = mCustomDefinitions.GetWeak(aTypeAtom);
     }
   }
 
   if (data && data->mLocalName == aNameAtom && data->mNamespaceID == aNameSpaceID) {
     return data;
   }
 
--- a/dom/base/CustomElementRegistry.h
+++ b/dom/base/CustomElementRegistry.h
@@ -124,23 +124,26 @@ struct CustomElementData
   // 2) it’s adopted into a new document, 3) its attributes are changed,
   // appended, removed, or replaced.
   // There are 3 reactions in reaction queue when doing upgrade operation,
   // e.g., create an element, insert a node.
   AutoTArray<UniquePtr<CustomElementReaction>, 3> mReactionQueue;
 
   void SetCustomElementDefinition(CustomElementDefinition* aDefinition);
   CustomElementDefinition* GetCustomElementDefinition();
-  nsAtom* GetCustomElementType();
+  nsAtom* GetCustomElementType() const
+  {
+    return mType;
+  }
 
   void Traverse(nsCycleCollectionTraversalCallback& aCb) const;
   void Unlink();
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
 
-  nsAtom* GetIs(Element* aElement)
+  nsAtom* GetIs(const Element* aElement) const
   {
     // If mType isn't the same as name atom, this is a customized built-in
     // element, which has 'is' value set.
     return aElement->NodeInfo()->NameAtom() == mType ? nullptr : mType.get();
   }
 private:
   virtual ~CustomElementData() {}
 
@@ -411,16 +414,27 @@ private:
     private:
       RefPtr<CustomElementRegistry> mRegistry;
       RefPtr<nsAtom> mAtom;
       RefPtr<CustomElementCreationCallback> mCallback;
   };
 
 public:
   /**
+   * Returns whether there's a definition that is likely to match this type
+   * atom. This is not exact, so should only be used for optimization, but it's
+   * good enough to prove that the chrome code doesn't need an XBL binding.
+   */
+  bool IsLikelyToBeCustomElement(nsAtom* aTypeAtom) const
+  {
+    return mCustomDefinitions.GetWeak(aTypeAtom) ||
+      mElementCreationCallbacks.GetWeak(aTypeAtom);
+  }
+
+  /**
    * Looking up a custom element definition.
    * https://html.spec.whatwg.org/#look-up-a-custom-element-definition
    */
   CustomElementDefinition* LookupCustomElementDefinition(
     nsAtom* aNameAtom, int32_t aNameSpaceID, nsAtom* aTypeAtom);
 
   CustomElementDefinition* LookupCustomElementDefinition(
     JSContext* aCx, JSObject *aConstructor) const;
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -522,31 +522,45 @@ Element::ClearStyleStateLocks()
 
   DeleteProperty(nsGkAtoms::lockedStyleStates);
   ClearHasLockedStyleStates();
 
   NotifyStyleStateChange(locks.mLocks);
 }
 
 static bool
+IsLikelyCustomElement(const nsXULElement& aElement)
+{
+  const CustomElementData* data = aElement.GetCustomElementData();
+  if (!data) {
+    return false;
+  }
+
+  const CustomElementRegistry* registry =
+    nsContentUtils::GetCustomElementRegistry(aElement.OwnerDoc());
+  if (!registry) {
+    return false;
+  }
+
+  return registry->IsLikelyToBeCustomElement(data->GetCustomElementType());
+}
+
+static bool
 MayNeedToLoadXBLBinding(const nsIDocument& aDocument, const Element& aElement)
 {
   // If we have a frame, the frame has already loaded the binding.
   // Otherwise, don't do anything else here unless we're dealing with
   // XUL or an HTML element that may have a plugin-related overlay
   // (i.e. object or embed).
   if (!aDocument.GetShell() || aElement.GetPrimaryFrame()) {
     return false;
   }
 
-  if (aElement.IsXULElement()) {
-    // We know dropmarkers don't have XBL bindings, and they get
-    // accessed while hidden when opening new windows. So skip
-    // looking up -moz-binding for performance reasons (bug 1478999).
-    return !aElement.IsXULElement(nsGkAtoms::dropMarker);
+  if (auto* xulElem = nsXULElement::FromNode(aElement)) {
+    return !IsLikelyCustomElement(*xulElem);
   }
 
   return aElement.IsAnyOfHTMLElements(nsGkAtoms::object, nsGkAtoms::embed);
 }
 
 bool
 Element::GetBindingURL(nsIDocument *aDocument, css::URLValue **aResult)
 {
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -10179,17 +10179,17 @@ nsContentUtils::NewXULOrHTMLElement(Elem
     (*aResult)->SetCustomElementData(new CustomElementData(typeAtom));
     nsContentUtils::RegisterCallbackUpgradeElement(*aResult, typeAtom);
   }
 
   return NS_OK;
 }
 
 CustomElementRegistry*
-GetCustomElementRegistry(nsIDocument* aDoc)
+nsContentUtils::GetCustomElementRegistry(nsIDocument* aDoc)
 {
   MOZ_ASSERT(aDoc);
 
   if (!aDoc->GetDocShell()) {
     return nullptr;
   }
 
   nsPIDOMWindowInner* window = aDoc->GetInnerWindow();
@@ -10206,17 +10206,17 @@ nsContentUtils::LookupCustomElementDefin
                                               uint32_t aNameSpaceID,
                                               nsAtom* aTypeAtom)
 {
   if (aNameSpaceID != kNameSpaceID_XUL &&
       aNameSpaceID != kNameSpaceID_XHTML) {
     return nullptr;
   }
 
-  RefPtr<CustomElementRegistry> registry(GetCustomElementRegistry(aDoc));
+  RefPtr<CustomElementRegistry> registry = GetCustomElementRegistry(aDoc);
   if (!registry) {
     return nullptr;
   }
 
   return registry->LookupCustomElementDefinition(aNameAtom, aNameSpaceID, aTypeAtom);
 }
 
 /* static */ void
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -3065,16 +3065,19 @@ public:
   /**
    * Creates a new XUL or XHTML element applying any appropriate custom element
    * definition.
    */
   static nsresult NewXULOrHTMLElement(Element** aResult, mozilla::dom::NodeInfo* aNodeInfo,
                                       mozilla::dom::FromParser aFromParser, nsAtom* aIsAtom,
                                       mozilla::dom::CustomElementDefinition* aDefinition);
 
+  static mozilla::dom::CustomElementRegistry*
+    GetCustomElementRegistry(nsIDocument*);
+
   /**
    * Looking up a custom element definition.
    * https://html.spec.whatwg.org/#look-up-a-custom-element-definition
    */
   static mozilla::dom::CustomElementDefinition*
     LookupCustomElementDefinition(nsIDocument* aDoc,
                                   nsAtom* aNameAtom,
                                   uint32_t aNameSpaceID,