Bug 1486480. Add memory reporting for custom element data. r=smaug
☠☠ backed out by edb57a49546f ☠ ☠
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 27 Aug 2018 19:20:53 +0000
changeset 491285 9dc25841ff4f96a31bb150fee517a589c02aa7c6
parent 491284 0192efea1b664db8d20a691401ec5d3f9d3a2122
child 491286 4548d4980eecc4a9527c4da315ea1c9b7c056d53
push id1815
push userffxbld-merge
push dateMon, 15 Oct 2018 10:40:45 +0000
treeherdermozilla-release@18d4c09e9378 [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,25 @@ FragmentOrElement::nsDOMSlots::Unlink()
   mChildrenList = nullptr;
   mClassList = nullptr;
 }
 
 size_t
 FragmentOrElement::nsDOMSlots::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
 {
   size_t n = aMallocSizeOf(this);
+
+  nsExtendedContentSlots* extendedSlots = GetExtendedContentSlots();
   if (OwnsExtendedSlots()) {
-    n += aMallocSizeOf(GetExtendedContentSlots());
+    MOZ_ASSERT(extendedSlots);
+    n += aMallocSizeOf(extendedSlots);
+  }
+
+  if (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 +810,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;