Bug 1519861 - Improve mozilla::GetTabSizes - r=smaug

Introduces a generation number in dom::base::Document as well
as a cached version of TabSizes we can Get and Set.
When the document is changed, the cache is invalidated.

This change improves about:performance speed by avoiding
a heavy recursive call on big DOM trees via GetTabSizes() calls.
If the page does not change, the cached values are returned.

Differential Revision: https://phabricator.services.mozilla.com/D20526

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Tarek Ziadé 2019-02-25 16:39:46 +00:00
parent 120c38f502
commit 48840088a2
4 changed files with 71 additions and 6 deletions

View File

@ -1341,7 +1341,9 @@ Document::Document(const char* aContentType)
mIgnoreOpensDuringUnloadCounter(0),
mDocLWTheme(Doc_Theme_Uninitialized),
mSavedResolution(1.0f),
mPendingInitialTranslation(false) {
mPendingInitialTranslation(false),
mGeneration(0),
mCachedTabSizeGeneration(0) {
MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug, ("DOCUMENT %p created", this));
SetIsInDocument();
@ -12549,6 +12551,24 @@ bool Document::StorageAccessSandboxed() const {
(GetSandboxFlags() & SANDBOXED_STORAGE_ACCESS) != 0;
}
bool Document::GetCachedSizes(nsTabSizes* aSizes) {
if (mCachedTabSizeGeneration == 0 ||
GetGeneration() != mCachedTabSizeGeneration) {
return false;
}
aSizes->mDom += mCachedTabSizes.mDom;
aSizes->mStyle += mCachedTabSizes.mStyle;
aSizes->mOther += mCachedTabSizes.mOther;
return true;
}
void Document::SetCachedSizes(nsTabSizes* aSizes) {
mCachedTabSizes.mDom = aSizes->mDom;
mCachedTabSizes.mStyle = aSizes->mStyle;
mCachedTabSizes.mOther = aSizes->mOther;
mCachedTabSizeGeneration = GetGeneration();
}
already_AddRefed<nsAtom> Document::GetContentLanguageAsAtomForStyle() const {
nsAutoString contentLang;
GetContentLanguage(contentLang);

View File

@ -1490,6 +1490,21 @@ class Document : public nsINode,
// flag.
bool StorageAccessSandboxed() const;
// Increments the document generation.
inline void Changed() { ++mGeneration; }
// Returns the current generation.
inline int32_t GetGeneration() const { return mGeneration; }
// Adds cached sizes values to aSizes if there's any
// cached value and if the document generation hasn't
// changed since the cache was created.
// Returns true if sizes were added.
bool GetCachedSizes(nsTabSizes* aSizes);
// Sets the cache sizes for the current generation.
void SetCachedSizes(nsTabSizes* aSizes);
protected:
friend class nsUnblockOnloadEvent;
@ -4641,6 +4656,13 @@ class Document : public nsINode,
bool mPendingInitialTranslation;
// Document generation. Gets incremented everytime it changes.
int32_t mGeneration;
// Cached TabSizes values for the document.
int32_t mCachedTabSizeGeneration;
nsTabSizes mCachedTabSizes;
public:
// Needs to be public because the bindings code pokes at it.
js::ExpandoAndGeneration mExpandoAndGeneration;

View File

@ -136,6 +136,7 @@ void nsNodeUtils::CharacterDataWillChange(
void nsNodeUtils::CharacterDataChanged(nsIContent* aContent,
const CharacterDataChangeInfo& aInfo) {
Document* doc = aContent->OwnerDoc();
doc->Changed();
IMPL_MUTATION_NOTIFICATION(CharacterDataChanged, aContent, (aContent, aInfo),
IsRemoveNotification::No);
}
@ -152,6 +153,7 @@ void nsNodeUtils::AttributeChanged(Element* aElement, int32_t aNameSpaceID,
nsAtom* aAttribute, int32_t aModType,
const nsAttrValue* aOldValue) {
Document* doc = aElement->OwnerDoc();
doc->Changed();
IMPL_MUTATION_NOTIFICATION(
AttributeChanged, aElement,
(aElement, aNameSpaceID, aAttribute, aModType, aOldValue),
@ -170,7 +172,7 @@ void nsNodeUtils::AttributeSetToCurrentValue(Element* aElement,
void nsNodeUtils::ContentAppended(nsIContent* aContainer,
nsIContent* aFirstNewContent) {
Document* doc = aContainer->OwnerDoc();
doc->Changed();
IMPL_MUTATION_NOTIFICATION(ContentAppended, aContainer, (aFirstNewContent),
IsRemoveNotification::No);
}
@ -188,6 +190,7 @@ void nsNodeUtils::ContentInserted(nsINode* aContainer, nsIContent* aChild) {
MOZ_ASSERT(aContainer->IsContent() || aContainer->IsDocument(),
"container must be an nsIContent or an Document");
Document* doc = aContainer->OwnerDoc();
doc->Changed();
IMPL_MUTATION_NOTIFICATION(ContentInserted, aContainer, (aChild),
IsRemoveNotification::No);
}
@ -197,6 +200,7 @@ void nsNodeUtils::ContentRemoved(nsINode* aContainer, nsIContent* aChild,
MOZ_ASSERT(aContainer->IsContent() || aContainer->IsDocument(),
"container must be an nsIContent or an Document");
Document* doc = aContainer->OwnerDoc();
doc->Changed();
MOZ_ASSERT(aChild->GetParentNode() == aContainer,
"We expect the parent link to be still around at this point");
IMPL_MUTATION_NOTIFICATION(ContentRemoved, aContainer,

View File

@ -60,22 +60,41 @@ nsTArray<RefPtr<PerformanceInfoPromise>> CollectPerformanceInfo() {
return promises;
}
nsresult GetTabSizes(nsGlobalWindowOuter* aWindow, nsTabSizes* aSizes) {
void AddWindowTabSizes(nsGlobalWindowOuter* aWindow, nsTabSizes* aSizes) {
Document* document = aWindow->GetDocument();
if (document && document->GetCachedSizes(aSizes)) {
// We got a cached version
return;
}
// We measure the sizes on a fresh nsTabSizes instance
// because we want to cache the value and aSizes might
// already have some values from other windows.
nsTabSizes sizes;
// Measure the window.
SizeOfState state(moz_malloc_size_of);
nsWindowSizes windowSizes(state);
aWindow->AddSizeOfIncludingThis(windowSizes);
// Measure the inner window, if there is one.
nsGlobalWindowInner* inner = aWindow->GetCurrentInnerWindowInternal();
if (inner != nullptr) {
inner->AddSizeOfIncludingThis(windowSizes);
}
windowSizes.addToTabSizes(&sizes);
if (document) {
document->SetCachedSizes(&sizes);
}
aSizes->mDom += sizes.mDom;
aSizes->mStyle += sizes.mStyle;
aSizes->mOther += sizes.mOther;
}
nsresult GetTabSizes(nsGlobalWindowOuter* aWindow, nsTabSizes* aSizes) {
// Add the window (and inner window) sizes. Might be cached.
AddWindowTabSizes(aWindow, aSizes);
windowSizes.addToTabSizes(aSizes);
nsDOMWindowList* frames = aWindow->GetFrames();
uint32_t length = frames->GetLength();
// Measure this window's descendents.
for (uint32_t i = 0; i < length; i++) {
nsCOMPtr<nsPIDOMWindowOuter> child = frames->IndexedGetter(i);