diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp index a85d3e0bb9f4c..c0494f7ccc74d 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -1307,6 +1307,7 @@ Document::Document(const char* aContentType) mIsInitialDocumentInWindow(false), mIgnoreDocGroupMismatches(false), mLoadedAsData(false), + mAddedToMemoryReportingAsDataDocument(false), mMayStartLayout(true), mHaveFiredTitleChange(false), mIsShowing(false), @@ -2239,6 +2240,8 @@ Document::~Document() { } UnlinkOriginalDocumentIfStatic(); + + UnregisterFromMemoryReportingForDataDocument(); } NS_INTERFACE_TABLE_HEAD(Document) @@ -2585,6 +2588,9 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Document) tmp->mResizeObserverController->Unlink(); } tmp->mMetaViewports.Clear(); + + tmp->UnregisterFromMemoryReportingForDataDocument(); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mL10nProtoElements) NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE @@ -3267,6 +3273,7 @@ nsresult Document::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel, if (nsCRT::strcmp(kLoadAsData, aCommand) == 0) { mLoadedAsData = true; + SetLoadedAsData(true, /* aConsiderForMemoryReporting */ true); // We need to disable script & style loading in this case. // We leave them disabled even in EndLoad(), and let anyone // who puts the document on display to worry about enabling. @@ -3436,6 +3443,20 @@ nsresult Document::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel, return NS_OK; } +void Document::SetLoadedAsData(bool aLoadedAsData, + bool aConsiderForMemoryReporting) { + mLoadedAsData = aLoadedAsData; + if (aConsiderForMemoryReporting) { + nsIGlobalObject* global = GetScopeObject(); + if (global) { + if (nsPIDOMWindowInner* window = global->AsInnerWindow()) { + nsGlobalWindowInner::Cast(window) + ->RegisterDataDocumentForMemoryReporting(this); + } + } + } +} + nsIContentSecurityPolicy* Document::GetCsp() const { return mCSP; } void Document::SetCsp(nsIContentSecurityPolicy* aCSP) { mCSP = aCSP; } @@ -11722,7 +11743,9 @@ nsresult Document::CloneDocHelper(Document* clone) const { clone->SetScopeObject(GetScopeObject()); } // Make the clone a data document - clone->SetLoadedAsData(true); + clone->SetLoadedAsData( + true, + /* aConsiderForMemoryReporting */ !mCreatingStaticClone); // Misc state @@ -17279,4 +17302,17 @@ void Document::RemoveMediaElementWithMSE() { } } +void Document::UnregisterFromMemoryReportingForDataDocument() { + if (!mAddedToMemoryReportingAsDataDocument) { + return; + } + mAddedToMemoryReportingAsDataDocument = false; + nsIGlobalObject* global = GetScopeObject(); + if (global) { + if (nsPIDOMWindowInner* win = global->AsInnerWindow()) { + nsGlobalWindowInner::Cast(win)->UnregisterDataDocumentForMemoryReporting( + this); + } + } +} } // namespace mozilla::dom diff --git a/dom/base/Document.h b/dom/base/Document.h index dda4b70a0d93d..619484ceb2d07 100644 --- a/dom/base/Document.h +++ b/dom/base/Document.h @@ -1048,7 +1048,7 @@ class Document : public nsINode, */ void SetIsInitialDocument(bool aIsInitialDocument); - void SetLoadedAsData(bool aLoadedAsData) { mLoadedAsData = aLoadedAsData; } + void SetLoadedAsData(bool aLoadedAsData, bool aConsiderForMemoryReporting); /** * Normally we assert if a runnable labeled with one DocGroup touches data @@ -2519,6 +2519,12 @@ class Document : public nsINode, bool IsLoadedAsData() { return mLoadedAsData; } + void SetAddedToMemoryReportAsDataDocument() { + mAddedToMemoryReportingAsDataDocument = true; + } + + void UnregisterFromMemoryReportingForDataDocument(); + bool MayStartLayout() { return mMayStartLayout; } void SetMayStartLayout(bool aMayStartLayout); @@ -4486,6 +4492,10 @@ class Document : public nsINode, // as scripts and plugins, disabled. bool mLoadedAsData : 1; + // True if the document is considered for memory reporting as a + // data document + bool mAddedToMemoryReportingAsDataDocument : 1; + // If true, whoever is creating the document has gotten it to the // point where it's safe to start layout on it. bool mMayStartLayout : 1; diff --git a/dom/base/nsGlobalWindowInner.cpp b/dom/base/nsGlobalWindowInner.cpp index 96749d44b9b20..fc3827e90511a 100644 --- a/dom/base/nsGlobalWindowInner.cpp +++ b/dom/base/nsGlobalWindowInner.cpp @@ -6646,6 +6646,29 @@ void nsGlobalWindowInner::AddSizeOfIncludingThis( } } +void nsGlobalWindowInner::RegisterDataDocumentForMemoryReporting( + Document* aDocument) { + aDocument->SetAddedToMemoryReportAsDataDocument(); + mDataDocumentsForMemoryReporting.AppendElement( + do_GetWeakReference(aDocument)); +} + +void nsGlobalWindowInner::UnregisterDataDocumentForMemoryReporting( + Document* aDocument) { + nsWeakPtr doc = do_GetWeakReference(aDocument); + MOZ_ASSERT(mDataDocumentsForMemoryReporting.Contains(doc)); + mDataDocumentsForMemoryReporting.RemoveElement(doc); +} + +void nsGlobalWindowInner::CollectDOMSizesForDataDocuments( + nsWindowSizes& aSize) const { + for (const nsWeakPtr& ptr : mDataDocumentsForMemoryReporting) { + if (nsCOMPtr doc = do_QueryReferent(ptr)) { + doc->DocAddSizeOfIncludingThis(aSize); + } + } +} + void nsGlobalWindowInner::AddGamepad(GamepadHandle aHandle, Gamepad* aGamepad) { // Create the index we will present to content based on which indices are // already taken, as required by the spec. diff --git a/dom/base/nsGlobalWindowInner.h b/dom/base/nsGlobalWindowInner.h index 5555f9f065db1..dc42df8287566 100644 --- a/dom/base/nsGlobalWindowInner.h +++ b/dom/base/nsGlobalWindowInner.h @@ -474,6 +474,10 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget, void AddSizeOfIncludingThis(nsWindowSizes& aWindowSizes) const; + void CollectDOMSizesForDataDocuments(nsWindowSizes&) const; + void RegisterDataDocumentForMemoryReporting(Document*); + void UnregisterDataDocumentForMemoryReporting(Document*); + enum SlowScriptResponse { ContinueSlowScript = 0, ContinueSlowScriptAndKeepNotifying, @@ -1500,6 +1504,8 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget, nsTArray mScrollMarks; + nsTArray mDataDocumentsForMemoryReporting; + static InnerWindowByIdTable* sInnerWindowsById; // Members in the mChromeFields member should only be used in chrome windows. diff --git a/dom/base/nsWindowMemoryReporter.cpp b/dom/base/nsWindowMemoryReporter.cpp index 268c7cac4b61b..24c0799b86534 100644 --- a/dom/base/nsWindowMemoryReporter.cpp +++ b/dom/base/nsWindowMemoryReporter.cpp @@ -330,6 +330,13 @@ static void CollectWindowReports(nsGlobalWindowInner* aWindow, ReportDOMSize(windowPath, aWindowTotalSizes->mDOMSizes, aHandleReport, aData, windowSizes.mDOMSizes); + nsCString dataDocumentPath(windowPath); + dataDocumentPath += "/data-documents"; + nsWindowSizes dataDocumentSizes(state); + aWindow->CollectDOMSizesForDataDocuments(dataDocumentSizes); + ReportDOMSize(dataDocumentPath, aWindowTotalSizes->mDOMSizes, aHandleReport, + aData, dataDocumentSizes.mDOMSizes); + REPORT_SIZE("/layout/style-sheets", mLayoutStyleSheetsSize, "Memory used by document style sheets within a window."); diff --git a/dom/base/test/browser.ini b/dom/base/test/browser.ini index c8797954bb5a1..fcebe8d715519 100644 --- a/dom/base/test/browser.ini +++ b/dom/base/test/browser.ini @@ -89,3 +89,4 @@ support-files = [browser_bug1703472.js] support-files = file_bug1703472.html +[browser_data_documents_aboutmemory.js] diff --git a/dom/base/test/browser_data_documents_aboutmemory.js b/dom/base/test/browser_data_documents_aboutmemory.js new file mode 100644 index 0000000000000..a960ecb806879 --- /dev/null +++ b/dom/base/test/browser_data_documents_aboutmemory.js @@ -0,0 +1,20 @@ +add_task(async function() { + const doc = new DOMParser().parseFromString("

dadada

", "text/html"); + + let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].getService( + Ci.nsIMemoryReporterManager + ); + + let amount = 0; + const handleReport = (aProcess, aPath, aKind, aUnits, aAmount) => { + const regex = new RegExp(".*/window-objects/.*/data-documents/.*"); + if (regex.test(aPath)) { + amount += aAmount; + } + }; + + await new Promise(r => + mgr.getReports(handleReport, null, r, null, /* anonymized = */ false) + ); + ok(amount > 0, "Got data documents amount"); +}); diff --git a/dom/html/nsHTMLDocument.cpp b/dom/html/nsHTMLDocument.cpp index 675d32bbb15cb..723af36a0bef4 100644 --- a/dom/html/nsHTMLDocument.cpp +++ b/dom/html/nsHTMLDocument.cpp @@ -115,7 +115,7 @@ nsresult NS_NewHTMLDocument(Document** aInstancePtrResult, bool aLoadedAsData) { return rv; } - doc->SetLoadedAsData(aLoadedAsData); + doc->SetLoadedAsData(aLoadedAsData, /* aConsiderForMemoryReporting */ true); doc.forget(aInstancePtrResult); return NS_OK; diff --git a/dom/xml/XMLDocument.cpp b/dom/xml/XMLDocument.cpp index bf33993f7987b..c76adeaf925be 100644 --- a/dom/xml/XMLDocument.cpp +++ b/dom/xml/XMLDocument.cpp @@ -118,7 +118,7 @@ nsresult NS_NewDOMDocument(Document** aInstancePtrResult, d->SetCompatibilityMode(eCompatibility_FullStandards); d->AsHTMLDocument()->SetIsXHTML(isXHTML); } - d->SetLoadedAsData(aLoadedAsData); + d->SetLoadedAsData(aLoadedAsData, /* aConsiderForMemoryReporting */ true); d->SetDocumentURI(aDocumentURI); // Must set the principal first, since SetBaseURI checks it. d->SetPrincipals(aPrincipal, aPrincipal); @@ -185,7 +185,7 @@ nsresult NS_NewXMLDocument(Document** aInstancePtrResult, bool aLoadedAsData, return rv; } - doc->SetLoadedAsData(aLoadedAsData); + doc->SetLoadedAsData(aLoadedAsData, /* aConsiderForMemoryReporting */ true); doc->mIsPlainDocument = aIsPlainDocument; doc.forget(aInstancePtrResult);