Bug 1385533 - Reserve space for one pointer in the mMutationObservers array on node slots; r=smaug
authorEhsan Akhgari <ehsan@mozilla.com>
Sat, 29 Jul 2017 01:07:05 -0400
changeset 423257 559f7f92c891782597759947b89be636c2d4767b
parent 423256 274298ae4f2376884dec227fd1eea6c66efecd91
child 423258 1b8336b8d1df74590bda11899d1caca738fbae32
push id1517
push userjlorenzo@mozilla.com
push dateThu, 14 Sep 2017 16:50:54 +0000
treeherdermozilla-release@3b41fd564418 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1385533
milestone56.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 1385533 - Reserve space for one pointer in the mMutationObservers array on node slots; r=smaug This helps avoid allocations for the first mutation observer (for example, Range) created by a caller.
dom/base/nsINode.h
dom/base/nsNodeUtils.cpp
dom/base/nsNodeUtils.h
dom/svg/SVGFilterElement.cpp
xpcom/ds/nsTObserverArray.h
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -1092,17 +1092,17 @@ public:
     virtual ~nsSlots();
 
     void Traverse(nsCycleCollectionTraversalCallback &cb);
     void Unlink();
 
     /**
      * A list of mutation observers
      */
-    nsTObserverArray<nsIMutationObserver*> mMutationObservers;
+    nsAutoTObserverArray<nsIMutationObserver*, 1> mMutationObservers;
 
     /**
      * An object implementing nsIDOMNodeList for this content (childNodes)
      * @see nsIDOMNodeList
      * @see nsGenericHTMLElement::GetChildNodes
      */
     RefPtr<nsChildContentList> mChildNodes;
 
@@ -1949,17 +1949,17 @@ protected:
   {
     if (!HasSlots()) {
       mSlots = CreateSlots();
       MOZ_ASSERT(mSlots);
     }
     return GetExistingSlots();
   }
 
-  nsTObserverArray<nsIMutationObserver*> *GetMutationObservers()
+  nsAutoTObserverArray<nsIMutationObserver*, 1> *GetMutationObservers()
   {
     return HasSlots() ? &GetExistingSlots()->mMutationObservers : nullptr;
   }
 
   bool IsEditableInternal() const;
   virtual bool IsEditableExternal() const
   {
     return IsEditableInternal();
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -54,18 +54,18 @@ using mozilla::AutoJSContext;
   if (doc) {                                                      \
     doc->BindingManager()->func_ params_;                         \
   }                                                               \
   do {                                                            \
     nsINode::nsSlots* slots = node->GetExistingSlots();           \
     if (slots && !slots->mMutationObservers.IsEmpty()) {          \
       /* No need to explicitly notify the first observer first    \
          since that'll happen anyway. */                          \
-      NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(                         \
-        slots->mMutationObservers, nsIMutationObserver,           \
+      NS_OBSERVER_AUTO_ARRAY_NOTIFY_OBSERVERS(                    \
+        slots->mMutationObservers, nsIMutationObserver, 1,        \
         func_, params_);                                          \
     }                                                             \
     ShadowRoot* shadow = ShadowRoot::FromNode(node);              \
     if (shadow) {                                                 \
       node = shadow->GetPoolHost();                               \
     } else {                                                      \
       node = node->GetParentNode();                               \
     }                                                             \
@@ -82,18 +82,18 @@ using mozilla::AutoJSContext;
     nsDOMMutationObserver::EnterMutationHandling();               \
   }                                                               \
   nsINode* node = content_;                                       \
   do {                                                            \
     nsINode::nsSlots* slots = node->GetExistingSlots();           \
     if (slots && !slots->mMutationObservers.IsEmpty()) {          \
       /* No need to explicitly notify the first observer first    \
          since that'll happen anyway. */                          \
-      NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS_WITH_QI(                 \
-        slots->mMutationObservers, nsIMutationObserver,           \
+      NS_OBSERVER_AUTO_ARRAY_NOTIFY_OBSERVERS_WITH_QI(            \
+        slots->mMutationObservers, nsIMutationObserver, 1,        \
         nsIAnimationObserver, func_, params_);                    \
     }                                                             \
     ShadowRoot* shadow = ShadowRoot::FromNode(node);              \
     if (shadow) {                                                 \
       node = shadow->GetPoolHost();                               \
     } else {                                                      \
       node = node->GetParentNode();                               \
     }                                                             \
@@ -287,19 +287,19 @@ nsNodeUtils::AnimationRemoved(Animation*
 }
 
 void
 nsNodeUtils::LastRelease(nsINode* aNode)
 {
   nsINode::nsSlots* slots = aNode->GetExistingSlots();
   if (slots) {
     if (!slots->mMutationObservers.IsEmpty()) {
-      NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(slots->mMutationObservers,
-                                         nsIMutationObserver,
-                                         NodeWillBeDestroyed, (aNode));
+      NS_OBSERVER_AUTO_ARRAY_NOTIFY_OBSERVERS(slots->mMutationObservers,
+                                              nsIMutationObserver, 1,
+                                              NodeWillBeDestroyed, (aNode));
     }
 
     if (aNode->IsElement()) {
       Element* elem = aNode->AsElement();
       FragmentOrElement::nsDOMSlots* domSlots =
         static_cast<FragmentOrElement::nsDOMSlots*>(slots);
       if (domSlots->mExtendedSlots) {
         for (auto iter = domSlots->mExtendedSlots->mRegisteredIntersectionObservers.Iter();
--- a/dom/base/nsNodeUtils.h
+++ b/dom/base/nsNodeUtils.h
@@ -132,20 +132,20 @@ public:
    * Send ParentChainChanged notifications to nsIMutationObservers
    * @param aContent  The piece of content that had its parent changed.
    * @see nsIMutationObserver::ParentChainChanged
    */
   static inline void ParentChainChanged(nsIContent *aContent)
   {
     nsINode::nsSlots* slots = aContent->GetExistingSlots();
     if (slots && !slots->mMutationObservers.IsEmpty()) {
-      NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(slots->mMutationObservers,
-                                         nsIMutationObserver,
-                                         ParentChainChanged,
-                                         (aContent));
+      NS_OBSERVER_AUTO_ARRAY_NOTIFY_OBSERVERS(slots->mMutationObservers,
+                                              nsIMutationObserver, 1,
+                                              ParentChainChanged,
+                                              (aContent));
     }
   }
 
   /**
    * Utility function to get the target (pseudo-)element associated with an
    * animation.
    * @param aAnimation The animation whose target is what we want.
    */
--- a/dom/svg/SVGFilterElement.cpp
+++ b/dom/svg/SVGFilterElement.cpp
@@ -128,20 +128,20 @@ SVGFilterElement::IsAttributeMapped(cons
   };
   return FindAttributeDependence(name, map) ||
     SVGFilterElementBase::IsAttributeMapped(name);
 }
 
 void
 SVGFilterElement::Invalidate()
 {
-  nsTObserverArray<nsIMutationObserver*> *observers = GetMutationObservers();
+  nsAutoTObserverArray<nsIMutationObserver*, 1> *observers = GetMutationObservers();
 
   if (observers && !observers->IsEmpty()) {
-    nsTObserverArray<nsIMutationObserver*>::ForwardIterator iter(*observers);
+    nsAutoTObserverArray<nsIMutationObserver*, 1>::ForwardIterator iter(*observers);
     while (iter.HasMore()) {
       nsCOMPtr<nsIMutationObserver> obs(iter.GetNext());
       nsCOMPtr<nsISVGFilterReference> filter = do_QueryInterface(obs);
       if (filter)
         filter->Invalidate();
     }
   }
 }
--- a/xpcom/ds/nsTObserverArray.h
+++ b/xpcom/ds/nsTObserverArray.h
@@ -515,21 +515,45 @@ ImplCycleCollectionTraverse(nsCycleColle
     nsTObserverArray<obstype_ *>::ForwardIterator iter_(array_);             \
     obstype_* obs_;                                                          \
     while (iter_.HasMore()) {                                                \
       obs_ = iter_.GetNext();                                                \
       obs_ -> func_ params_ ;                                                \
     }                                                                        \
   } while(0)
 
+// Note that this macro only works if the array holds pointers to XPCOM objects.
+#define NS_OBSERVER_AUTO_ARRAY_NOTIFY_OBSERVERS(array_, obstype_, num_, func_, params_) \
+  do {                                                                       \
+    nsAutoTObserverArray<obstype_ *, num_>::ForwardIterator iter_(array_);   \
+    obstype_* obs_;                                                          \
+    while (iter_.HasMore()) {                                                \
+      obs_ = iter_.GetNext();                                                \
+      obs_ -> func_ params_ ;                                                \
+    }                                                                        \
+  } while(0)
+
 #define NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS_WITH_QI(array_, basetype_, obstype_, func_, params_) \
   do {                                                                       \
     nsTObserverArray<basetype_ *>::ForwardIterator iter_(array_);            \
     basetype_* obsbase_;                                                     \
     while (iter_.HasMore()) {                                                \
       obsbase_ = iter_.GetNext();                                            \
       nsCOMPtr<obstype_> obs_ = do_QueryInterface(obsbase_);                 \
       if (obs_) {                                                            \
         obs_ -> func_ params_ ;                                              \
       }                                                                      \
     }                                                                        \
   } while(0)
+
+#define NS_OBSERVER_AUTO_ARRAY_NOTIFY_OBSERVERS_WITH_QI(array_, basetype_, num_, obstype_, func_, params_) \
+  do {                                                                       \
+    nsAutoTObserverArray<basetype_ *, num_>::ForwardIterator iter_(array_);  \
+    basetype_* obsbase_;                                                     \
+    while (iter_.HasMore()) {                                                \
+      obsbase_ = iter_.GetNext();                                            \
+      nsCOMPtr<obstype_> obs_ = do_QueryInterface(obsbase_);                 \
+      if (obs_) {                                                            \
+        obs_ -> func_ params_ ;                                              \
+      }                                                                      \
+    }                                                                        \
+  } while(0)
 #endif // nsTObserverArray_h___