Bug 1440221 - Track stale computed values and style structs held by undisplayed maps in memory report. r?emilio,njn
MozReview-Commit-ID: 8eXowQvUjyi
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -426,16 +426,20 @@ CollectWindowReports(nsGlobalWindowInner
REPORT_SIZE("/layout/computed-values/non-dom", mLayoutComputedValuesNonDom,
"Memory used by ComputedValues objects not accessible from DOM "
"elements.");
REPORT_SIZE("/layout/computed-values/visited", mLayoutComputedValuesVisited,
"Memory used by ComputedValues objects used for visited styles.");
+ REPORT_SIZE("/layout/computed-values/stale", mLayoutComputedValuesStale,
+ "Memory used by ComputedValues and style structs it holds that "
+ "is no longer used but still alive.");
+
REPORT_SIZE("/property-tables", mPropertyTablesSize,
"Memory used for the property tables within a window.");
REPORT_SIZE("/bindings", mBindingsSize,
"Memory used by bindings within a window.");
REPORT_COUNT("/dom/event-targets", mDOMEventTargetsCount,
"Number of non-node event targets in the event targets table "
--- a/dom/base/nsWindowSizes.h
+++ b/dom/base/nsWindowSizes.h
@@ -189,16 +189,17 @@ class nsWindowSizes
macro(Style, mLayoutServoStyleSetsOther) \
macro(Style, mLayoutServoElementDataObjects) \
macro(Other, mLayoutTextRunsSize) \
macro(Other, mLayoutPresContextSize) \
macro(Other, mLayoutFramePropertiesSize) \
macro(Style, mLayoutComputedValuesDom) \
macro(Style, mLayoutComputedValuesNonDom) \
macro(Style, mLayoutComputedValuesVisited) \
+ macro(Style, mLayoutComputedValuesStale) \
macro(Other, mPropertyTablesSize) \
macro(Other, mBindingsSize) \
public:
explicit nsWindowSizes(mozilla::SizeOfState& aState)
:
FOR_EACH_SIZE(ZERO_SIZE)
mDOMEventTargetsCount(0),
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -10653,20 +10653,17 @@ PresShell::AddSizeOfIncludingThis(nsWind
StyleSet()->AsServo()->AddSizeOfIncludingThis(aSizes);
}
aSizes.mLayoutTextRunsSize += SizeOfTextRuns(mallocSizeOf);
aSizes.mLayoutPresContextSize +=
mPresContext->SizeOfIncludingThis(mallocSizeOf);
- nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
- if (rootFrame) {
- rootFrame->AddSizeOfExcludingThisForTree(aSizes);
- }
+ mFrameConstructor->AddSizeOfIncludingThis(aSizes);
}
size_t
PresShell::SizeOfTextRuns(MallocSizeOf aMallocSizeOf) const
{
nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
if (!rootFrame) {
return 0;
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -15,16 +15,17 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/HTMLDetailsElement.h"
#include "mozilla/dom/HTMLSelectElement.h"
#include "mozilla/dom/HTMLSummaryElement.h"
#include "mozilla/EventStates.h"
#include "mozilla/Likely.h"
#include "mozilla/LinkedList.h"
+#include "mozilla/MemoryReporting.h"
#include "mozilla/PresShell.h"
#include "mozilla/ServoBindings.h"
#include "nsAbsoluteContainingBlock.h"
#include "nsCSSPseudoElements.h"
#include "nsAtom.h"
#include "nsIFrameInlines.h"
#include "nsGkAtoms.h"
#include "nsPresContext.h"
@@ -13144,8 +13145,27 @@ nsCSSFrameConstructor::FreeFCItem(FrameC
mFCItemPool.Clear();
} else {
// Prepend it to the list of free items.
FreeFCItemLink* item = reinterpret_cast<FreeFCItemLink*>(aItem);
item->mNext = mFirstFreeFCItem;
mFirstFreeFCItem = item;
}
}
+
+void
+nsCSSFrameConstructor::AddSizeOfIncludingThis(nsWindowSizes& aSizes) const
+{
+ if (nsIFrame* rootFrame = GetRootFrame()) {
+ rootFrame->AddSizeOfExcludingThisForTree(aSizes);
+ }
+
+ // This must be done after measuring from the frame tree, since frame
+ // manager will measure sizes of staled computed values and style
+ // structs, which only make sense after we know what are being used.
+ nsFrameManager::AddSizeOfIncludingThis(aSizes);
+
+ // Measurement of the following members may be added later if DMD finds it
+ // is worthwhile:
+ // - mFCItemPool
+ // - mQuoteList
+ // - mCounterManager
+}
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -388,16 +388,18 @@ public:
// have a psuedo-element style
nsIFrame* GetRootElementStyleFrame() { return mRootElementStyleFrame; }
nsIFrame* GetPageSequenceFrame() { return mPageSequenceFrame; }
// Get the frame that is the parent of the root element.
nsContainerFrame* GetDocElementContainingBlock()
{ return mDocElementContainingBlock; }
+ void AddSizeOfIncludingThis(nsWindowSizes& aSizes) const;
+
private:
struct FrameConstructionItem;
class FrameConstructionItemList;
nsContainerFrame* ConstructPageFrame(nsIPresShell* aPresShell,
nsContainerFrame* aParentFrame,
nsIFrame* aPrevPageFrame,
nsContainerFrame*& aCanvasFrame);
--- a/layout/base/nsFrameManager.cpp
+++ b/layout/base/nsFrameManager.cpp
@@ -24,16 +24,18 @@
#include "nsAbsoluteContainingBlock.h"
#include "ChildIterator.h"
#include "nsFrameManager.h"
#include "GeckoProfiler.h"
#include "nsIStatefulFrame.h"
#include "nsContainerFrame.h"
+#include "mozilla/MemoryReporting.h"
+
// #define DEBUG_UNDISPLAYED_MAP
// #define DEBUG_DISPLAY_CONTENTS_MAP
using namespace mozilla;
using namespace mozilla::dom;
//----------------------------------------------------------------------
@@ -88,16 +90,18 @@ public:
*
* All functions that are entry points into code that handles "parent"
* objects (used as the hash table keys) must ensure that the parent objects
* that they act on (and pass to other code) have been normalized by calling
* this method.
*/
static nsIContent* GetApplicableParent(nsIContent* aParent);
+ void AddSizeOfIncludingThis(nsWindowSizes& aSizes, bool aIsServo) const;
+
protected:
LinkedList<UndisplayedNode>* GetListFor(nsIContent* aParentContent);
LinkedList<UndisplayedNode>* GetOrCreateListFor(nsIContent* aParentContent);
void AppendNodeFor(UndisplayedNode* aNode, nsIContent* aParentContent);
};
//----------------------------------------------------------------------
@@ -691,16 +695,29 @@ nsFrameManager::DestroyAnonymousContent(
// teardown code to determine whether to invoke ClearAllMapsFor or not.
// These maps will go away when we drop support for the old style system.
ClearAllMapsFor(content);
content->UnbindFromTree();
}
}
+void
+nsFrameManager::AddSizeOfIncludingThis(nsWindowSizes& aSizes) const
+{
+ bool isServo = mPresShell->StyleSet()->IsServo();
+ aSizes.mLayoutPresShellSize += aSizes.mState.mMallocSizeOf(this);
+ if (mDisplayNoneMap) {
+ mDisplayNoneMap->AddSizeOfIncludingThis(aSizes, isServo);
+ }
+ if (mDisplayContentsMap) {
+ mDisplayContentsMap->AddSizeOfIncludingThis(aSizes, isServo);
+ }
+}
+
//----------------------------------------------------------------------
nsFrameManagerBase::UndisplayedMap::UndisplayedMap()
{
MOZ_COUNT_CTOR(nsFrameManagerBase::UndisplayedMap);
}
nsFrameManagerBase::UndisplayedMap::~UndisplayedMap(void)
@@ -825,8 +842,36 @@ nsFrameManagerBase::UndisplayedMap::Remo
{
nsAutoPtr<LinkedList<UndisplayedNode>> list = UnlinkNodesFor(aParentContent);
if (list) {
while (auto* node = list->popFirst()) {
delete node;
}
}
}
+
+void
+nsFrameManagerBase::UndisplayedMap::
+AddSizeOfIncludingThis(nsWindowSizes& aSizes, bool aIsServo) const
+{
+ MallocSizeOf mallocSizeOf = aSizes.mState.mMallocSizeOf;
+ aSizes.mLayoutPresShellSize += ShallowSizeOfIncludingThis(mallocSizeOf);
+
+ nsWindowSizes staleSizes(aSizes.mState);
+ for (auto iter = ConstIter(); !iter.Done(); iter.Next()) {
+ const LinkedList<UndisplayedNode>* list = iter.UserData();
+ aSizes.mLayoutPresShellSize += list->sizeOfExcludingThis(mallocSizeOf);
+ if (!aIsServo) {
+ // Computed values and style structs can only be stale when using
+ // Servo style system.
+ continue;
+ }
+ for (const UndisplayedNode* node = list->getFirst();
+ node; node = node->getNext()) {
+ ServoStyleContext* sc = node->mStyle->AsServo();
+ if (!aSizes.mState.HaveSeenPtr(sc)) {
+ sc->AddSizeOfIncludingThis(
+ staleSizes, &aSizes.mLayoutComputedValuesStale);
+ }
+ }
+ }
+ aSizes.mLayoutComputedValuesStale += staleSizes.getTotalSize();
+}
--- a/layout/base/nsFrameManager.h
+++ b/layout/base/nsFrameManager.h
@@ -12,16 +12,17 @@
#include "nsFrameManagerBase.h"
#include "nsFrameList.h"
#include "nsIContent.h"
#include "nsStyleContext.h"
class nsContainerFrame;
class nsPlaceholderFrame;
+class nsWindowSizes;
namespace mozilla {
/**
* Node in a linked list, containing the style for an element that
* does not have a frame but whose parent does have a frame.
*/
struct UndisplayedNode : public LinkedListElement<UndisplayedNode>
{
@@ -195,16 +196,18 @@ public:
* Add/restore state for one frame
*/
void CaptureFrameStateFor(nsIFrame* aFrame, nsILayoutHistoryState* aState);
void RestoreFrameStateFor(nsIFrame* aFrame, nsILayoutHistoryState* aState);
void DestroyAnonymousContent(already_AddRefed<nsIContent> aContent);
+ void AddSizeOfIncludingThis(nsWindowSizes& aSizes) const;
+
protected:
static nsIContent* ParentForUndisplayedMap(const nsIContent* aContent);
void ClearAllMapsFor(nsIContent* aParentContent);
static nsStyleContext* GetStyleContextInMap(UndisplayedMap* aMap,
const nsIContent* aContent);
static mozilla::UndisplayedNode*