Bug 1486480. Add memory reporting for custom element data. r=smaug
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 27 Aug 2018 19:20:53 +0000
changeset 488759 4292aeb328da7fa052bec34a635248e849400a58
parent 488758 0e03f055808cb2ed38381c1c1f7f1b2756a7c8a4
child 488760 7eb7606a2b12990e8ef5e470db27838d5f5af612
push id9734
push usershindli@mozilla.com
push dateThu, 30 Aug 2018 12:18:07 +0000
treeherdermozilla-beta@71c71ab3afae [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1486480
milestone63.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 1486480. Add memory reporting for custom element data. r=smaug Differential Revision: https://phabricator.services.mozilla.com/D4350
dom/base/CustomElementRegistry.cpp
dom/base/CustomElementRegistry.h
dom/base/FragmentOrElement.cpp
dom/base/FragmentOrElement.h
dom/base/nsIContent.h
--- a/dom/base/CustomElementRegistry.cpp
+++ b/dom/base/CustomElementRegistry.cpp
@@ -37,16 +37,23 @@ public:
   }
 
   virtual void Traverse(nsCycleCollectionTraversalCallback& aCb) const override
   {
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mDefinition");
     aCb.NoteNativeChild(mDefinition,
       NS_CYCLE_COLLECTION_PARTICIPANT(CustomElementDefinition));
   }
+
+  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
+  {
+    // We don't really own mDefinition.
+    return aMallocSizeOf(this);
+  }
+
 private:
   virtual void Invoke(Element* aElement, ErrorResult& aRv) override
   {
     CustomElementRegistry::Upgrade(aElement, mDefinition, aRv);
   }
 
   RefPtr<CustomElementDefinition> mDefinition;
 };
@@ -62,28 +69,47 @@ class CustomElementCallbackReaction fina
     {
     }
 
     virtual void Traverse(nsCycleCollectionTraversalCallback& aCb) const override
     {
       mCustomElementCallback->Traverse(aCb);
     }
 
+    size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
+    {
+      size_t n = aMallocSizeOf(this);
+
+      n += mCustomElementCallback->SizeOfIncludingThis(aMallocSizeOf);
+
+      return n;
+    }
+
   private:
     virtual void Invoke(Element* aElement, ErrorResult& aRv) override
     {
       mCustomElementCallback->Call();
     }
 
     UniquePtr<CustomElementCallback> mCustomElementCallback;
 };
 
 //-----------------------------------------------------
 // CustomElementCallback
 
+size_t
+LifecycleCallbackArgs::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
+{
+  size_t n = name.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+  n += oldValue.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+  n += newValue.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+  n += namespaceURI.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+  return n;
+}
+
 void
 CustomElementCallback::Call()
 {
   switch (mType) {
     case nsIDocument::eConnected:
       static_cast<LifecycleConnectedCallback *>(mCallback.get())->Call(mThisObject);
       break;
     case nsIDocument::eDisconnected:
@@ -108,16 +134,34 @@ CustomElementCallback::Traverse(nsCycleC
 {
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mThisObject");
   aCb.NoteXPCOMChild(mThisObject);
 
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mCallback");
   aCb.NoteXPCOMChild(mCallback);
 }
 
+size_t
+CustomElementCallback::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+
+  // We don't uniquely own mThisObject.
+
+  // We own mCallback but it doesn't have any special memory reporting we can do
+  // for it other than report its own size.
+  n += aMallocSizeOf(mCallback);
+
+  n += mArgs.SizeOfExcludingThis(aMallocSizeOf);
+
+  // mAdoptedCallbackArgs doesn't really uniquely own its members.
+
+  return n;
+}
+
 CustomElementCallback::CustomElementCallback(Element* aThisObject,
                                              nsIDocument::ElementCallbackType aCallbackType,
                                              mozilla::dom::CallbackFunction* aCallback)
   : mThisObject(aThisObject),
     mCallback(aCallback),
     mType(aCallbackType)
 {
 }
@@ -209,16 +253,30 @@ CustomElementData::Traverse(nsCycleColle
 
 void
 CustomElementData::Unlink()
 {
   mReactionQueue.Clear();
   mCustomElementDefinition = nullptr;
 }
 
+size_t
+CustomElementData::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+
+  n += mReactionQueue.ShallowSizeOfExcludingThis(aMallocSizeOf);
+
+  for (auto& reaction : mReactionQueue) {
+    n += reaction->SizeOfIncludingThis(aMallocSizeOf);
+  }
+
+  return n;
+}
+
 //-----------------------------------------------------
 // CustomElementRegistry
 
 namespace {
 
 class MOZ_RAII AutoConstructionStackEntry final
 {
 public:
--- a/dom/base/CustomElementRegistry.h
+++ b/dom/base/CustomElementRegistry.h
@@ -36,31 +36,34 @@ class Function;
 class Promise;
 
 struct LifecycleCallbackArgs
 {
   nsString name;
   nsString oldValue;
   nsString newValue;
   nsString namespaceURI;
+
+  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
 };
 
 struct LifecycleAdoptedCallbackArgs
 {
   nsCOMPtr<nsIDocument> mOldDocument;
   nsCOMPtr<nsIDocument> mNewDocument;
 };
 
 class CustomElementCallback
 {
 public:
   CustomElementCallback(Element* aThisObject,
                         nsIDocument::ElementCallbackType aCallbackType,
                         CallbackFunction* aCallback);
   void Traverse(nsCycleCollectionTraversalCallback& aCb) const;
+  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
   void Call();
   void SetArgs(LifecycleCallbackArgs& aArgs)
   {
     MOZ_ASSERT(mType == nsIDocument::eAttributeChanged,
                "Arguments are only used by attribute changed callback.");
     mArgs = aArgs;
   }
 
@@ -125,16 +128,17 @@ struct CustomElementData
   AutoTArray<UniquePtr<CustomElementReaction>, 3> mReactionQueue;
 
   void SetCustomElementDefinition(CustomElementDefinition* aDefinition);
   CustomElementDefinition* GetCustomElementDefinition();
   nsAtom* GetCustomElementType();
 
   void Traverse(nsCycleCollectionTraversalCallback& aCb) const;
   void Unlink();
+  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
 
   nsAtom* GetIs(Element* aElement)
   {
     // 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:
@@ -203,16 +207,17 @@ private:
 };
 
 class CustomElementReaction
 {
 public:
   virtual ~CustomElementReaction() = default;
   virtual void Invoke(Element* aElement, ErrorResult& aRv) = 0;
   virtual void Traverse(nsCycleCollectionTraversalCallback& aCb) const = 0;
+  virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const = 0;
 
   bool IsUpgradeReaction()
   {
     return mIsUpgradeReaction;
   }
 
 protected:
   bool mIsUpgradeReaction = false;
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -669,16 +669,24 @@ nsIContent::nsExtendedContentSlots::Trav
 }
 
 nsIContent::nsExtendedContentSlots::nsExtendedContentSlots()
 {
 }
 
 nsIContent::nsExtendedContentSlots::~nsExtendedContentSlots() = default;
 
+size_t
+nsIContent::nsExtendedContentSlots::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
+{
+  // For now, nothing to measure here.  We don't actually own any of our
+  // members.
+  return 0;
+}
+
 FragmentOrElement::nsDOMSlots::nsDOMSlots()
   : nsIContent::nsContentSlots(),
     mDataset(nullptr)
 {
   MOZ_COUNT_CTOR(nsDOMSlots);
 }
 
 FragmentOrElement::nsDOMSlots::~nsDOMSlots()
@@ -720,18 +728,24 @@ FragmentOrElement::nsDOMSlots::Unlink()
   mChildrenList = nullptr;
   mClassList = nullptr;
 }
 
 size_t
 FragmentOrElement::nsDOMSlots::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
 {
   size_t n = aMallocSizeOf(this);
-  if (OwnsExtendedSlots()) {
-    n += aMallocSizeOf(GetExtendedContentSlots());
+
+  nsExtendedContentSlots* extendedSlots = GetExtendedContentSlots();
+  if (extendedSlots) {
+    if (OwnsExtendedSlots()) {
+      n += aMallocSizeOf(extendedSlots);
+    }
+
+    n += extendedSlots->SizeOfExcludingThis(aMallocSizeOf);
   }
 
   if (mAttributeMap) {
     n += mAttributeMap->SizeOfIncludingThis(aMallocSizeOf);
   }
 
   // Measurement of the following members may be added later if DMD finds it is
   // worthwhile:
@@ -795,16 +809,59 @@ FragmentOrElement::nsExtendedDOMSlots::T
   aCb.NoteNativeChild(mXBLBinding,
                      NS_CYCLE_COLLECTION_PARTICIPANT(nsXBLBinding));
 
   if (mCustomElementData) {
     mCustomElementData->Traverse(aCb);
   }
 }
 
+size_t
+FragmentOrElement::nsExtendedDOMSlots::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
+{
+  size_t n = nsIContent::nsExtendedContentSlots::SizeOfExcludingThis(aMallocSizeOf);
+
+  // We own mSMILOverrideStyle but there seems to be no memory reporting on CSS
+  // declarations?  At least report the memory the declaration takes up
+  // directly.
+  if (mSMILOverrideStyle) {
+    n += aMallocSizeOf(mSMILOverrideStyle);
+  }
+
+  // We don't really own mSMILOverrideStyleDeclaration.  mSMILOverrideStyle owns
+  // it.
+
+  // We don't seem to have memory reporting for nsXULControllers.  At least
+  // report the memory it's using directly.
+  if (mControllers) {
+    n += aMallocSizeOf(mControllers);
+  }
+
+  // We don't seem to have memory reporting for nsLabelsNodeList.  At least
+  // report the memory it's using directly.
+  if (mLabelsList) {
+    n += aMallocSizeOf(mLabelsList);
+  }
+
+  // mShadowRoot should be handled during normal DOM tree memory reporting, just
+  // like kids, siblings, etc.
+
+  // We don't seem to have memory reporting for nsXBLBinding.  At least
+  // report the memory it's using directly.
+  if (mXBLBinding) {
+    n += aMallocSizeOf(mXBLBinding);
+  }
+
+  if (mCustomElementData) {
+    n += mCustomElementData->SizeOfIncludingThis(aMallocSizeOf);
+  }
+
+  return n;
+}
+
 FragmentOrElement::FragmentOrElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
   : nsIContent(aNodeInfo)
 {
 }
 
 FragmentOrElement::FragmentOrElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
   : nsIContent(aNodeInfo)
 {
--- a/dom/base/FragmentOrElement.h
+++ b/dom/base/FragmentOrElement.h
@@ -169,16 +169,18 @@ public:
   {
   public:
     nsExtendedDOMSlots();
     ~nsExtendedDOMSlots();
 
     void TraverseExtendedSlots(nsCycleCollectionTraversalCallback&) final;
     void UnlinkExtendedSlots() final;
 
+    size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const final;
+
     /**
      * SMIL Overridde style rules (for SMIL animation of CSS properties)
      * @see Element::GetSMILOverrideStyle
      */
     RefPtr<nsDOMCSSAttributeDeclaration> mSMILOverrideStyle;
 
     /**
      * Holds any SMIL override style declaration for this element.
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -792,16 +792,18 @@ protected:
   {
   public:
     nsExtendedContentSlots();
     virtual ~nsExtendedContentSlots();
 
     virtual void TraverseExtendedSlots(nsCycleCollectionTraversalCallback&);
     virtual void UnlinkExtendedSlots();
 
+    virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
+
     /**
      * The nearest enclosing content node with a binding that created us.
      * TODO(emilio): This should be an Element*.
      *
      * @see nsIContent::GetBindingParent
      */
     nsCOMPtr<nsIContent> mBindingParent;
 
@@ -856,16 +858,18 @@ protected:
     void SetExtendedContentSlots(nsExtendedContentSlots* aSlots, bool aOwning)
     {
       mExtendedSlots = reinterpret_cast<uintptr_t>(aSlots);
       if (!aOwning) {
         mExtendedSlots |= sNonOwningExtendedSlotsFlag;
       }
     }
 
+    // OwnsExtendedSlots returns true if we have no extended slots or if we
+    // have extended slots and own them.
     bool OwnsExtendedSlots() const
     {
       return !(mExtendedSlots & sNonOwningExtendedSlotsFlag);
     }
 
     nsExtendedContentSlots* GetExtendedContentSlots() const
     {
       return reinterpret_cast<nsExtendedContentSlots*>(