Bug 1699484 - Support Timer based bfcache eviction, r=peterv

The patch makes HistoryTracker rely on SHEntrySharedParentState instead of nsSHEntryShared.
nsSHEntryShared already extends SHEntrySharedParentState.

The test was modified a tiny bit to make it easier to see the results. The test does pass
with SHIP+BFCache.

Depends on D108851

Differential Revision: https://phabricator.services.mozilla.com/D108984
This commit is contained in:
Olli Pettay 2021-03-21 21:46:26 +00:00
parent b535d5b970
commit dc39236b97
9 changed files with 61 additions and 36 deletions

View File

@ -1041,9 +1041,8 @@ SessionHistoryEntry::HasDynamicallyAddedChild(bool* aHasDynamicallyAddedChild) {
}
NS_IMETHODIMP_(bool)
SessionHistoryEntry::HasBFCacheEntry(nsIBFCacheEntry* aEntry) {
MOZ_CRASH("This lives in the child process");
return false;
SessionHistoryEntry::HasBFCacheEntry(SHEntrySharedParentState* aEntry) {
return SharedInfo() == aEntry;
}
NS_IMETHODIMP
@ -1356,7 +1355,7 @@ void SessionHistoryEntry::SetFrameLoader(nsFrameLoader* aFrameLoader) {
MOZ_ASSERT_IF(aFrameLoader, !SharedInfo()->mFrameLoader);
// If the pref is disabled, we still allow evicting the existing entries.
MOZ_RELEASE_ASSERT(!aFrameLoader || mozilla::BFCacheInParent());
SharedInfo()->mFrameLoader = aFrameLoader;
SharedInfo()->SetFrameLoader(aFrameLoader);
if (aFrameLoader) {
if (BrowserParent* bp = aFrameLoader->GetBrowserParent()) {
bp->Deactivated();

View File

@ -42,6 +42,7 @@ struct EntriesAndBrowsingContextData;
[ref] native nsIntRect(nsIntRect);
[ptr] native nsDocShellEditorDataPtr(nsDocShellEditorData);
[ptr] native nsDocShellLoadStatePtr(nsDocShellLoadState);
[ptr] native SHEntrySharedParentStatePtr(mozilla::dom::SHEntrySharedParentState);
webidl BrowsingContext;
[builtinclass, scriptable, uuid(0dad26b8-a259-42c7-93f1-2fa7fc076e45)]
@ -358,7 +359,8 @@ interface nsISHEntry : nsISupports
* the BFCache entry will evict the SHEntry, since the two entries
* correspond to the same document.
*/
[noscript, notxpcom] boolean hasBFCacheEntry(in nsIBFCacheEntry aEntry);
[noscript, notxpcom]
boolean hasBFCacheEntry(in SHEntrySharedParentStatePtr aEntry);
/**
* Adopt aEntry's BFCacheEntry, so now both this and aEntry point to

View File

@ -15,10 +15,16 @@ webidl BrowsingContext;
#include "nsTArrayForwardDeclare.h"
#include "mozilla/Maybe.h"
struct EntriesAndBrowsingContextData;
namespace mozilla {
namespace dom {
class SHEntrySharedParentState;
} // namespace dom
} // namespace mozilla
%}
[ref] native nsDocshellIDArray(nsTArray<nsID>);
native MaybeInt32(mozilla::Maybe<int32_t>);
[ptr] native SHEntrySharedParentStatePtr(mozilla::dom::SHEntrySharedParentState);
/**
* An interface to the primary properties of the Session History
* component. In an embedded browser environment, the nsIWebBrowser
@ -197,7 +203,8 @@ interface nsISHistory: nsISupports
* Evict the content viewer associated with a bfcache entry that has timed
* out.
*/
void evictExpiredContentViewerForEntry(in nsIBFCacheEntry aEntry);
[noscript, notxpcom]
void evictExpiredContentViewerForEntry(in SHEntrySharedParentStatePtr aEntry);
/**
* Evict all the content viewers in this session history
@ -209,13 +216,13 @@ interface nsISHistory: nsISupports
* expiration.
*/
[noscript, notxpcom]
void addToExpirationTracker(in nsIBFCacheEntry aEntry);
void addToExpirationTracker(in SHEntrySharedParentStatePtr aEntry);
/**
* Remove a BFCache entry from expiration tracker.
*/
[noscript, notxpcom]
void removeFromExpirationTracker(in nsIBFCacheEntry aEntry);
void removeFromExpirationTracker(in SHEntrySharedParentStatePtr aEntry);
/**
* Remove dynamic entries found at given index.

View File

@ -1059,8 +1059,9 @@ bool nsSHEntry::HasDetachedEditor() {
return GetState()->mEditorData != nullptr;
}
bool nsSHEntry::HasBFCacheEntry(nsIBFCacheEntry* aEntry) {
return static_cast<nsIBFCacheEntry*>(GetState()) == aEntry;
bool nsSHEntry::HasBFCacheEntry(
mozilla::dom::SHEntrySharedParentState* aEntry) {
return GetState() == aEntry;
}
NS_IMETHODIMP

View File

@ -70,7 +70,8 @@ SHEntrySharedParentState::SHEntrySharedParentState(
SHEntrySharedParentState::~SHEntrySharedParentState() {
MOZ_ASSERT(mId != 0);
RefPtr<nsFrameLoader> loader = mFrameLoader.forget();
RefPtr<nsFrameLoader> loader = mFrameLoader;
SetFrameLoader(nullptr);
if (loader) {
loader->Destroy();
}
@ -117,7 +118,20 @@ void SHEntrySharedChildState::CopyFrom(SHEntrySharedChildState* aEntry) {
}
void SHEntrySharedParentState::SetFrameLoader(nsFrameLoader* aFrameLoader) {
// If expiration tracker is removing this object, IsTracked() returns false.
if (GetExpirationState()->IsTracked() && mFrameLoader) {
if (nsCOMPtr<nsISHistory> shistory = do_QueryReferent(mSHistory)) {
shistory->RemoveFromExpirationTracker(this);
}
}
mFrameLoader = aFrameLoader;
if (mFrameLoader) {
if (nsCOMPtr<nsISHistory> shistory = do_QueryReferent(mSHistory)) {
shistory->AddToExpirationTracker(this);
}
}
}
nsFrameLoader* SHEntrySharedParentState::GetFrameLoader() {

View File

@ -103,6 +103,8 @@ class SHEntrySharedParentState : public SHEntrySharedState {
void NotifyListenersContentViewerEvicted();
nsExpirationState* GetExpirationState() { return &mExpirationState; }
SHEntrySharedParentState();
SHEntrySharedParentState(nsIPrincipal* aTriggeringPrincipal,
nsIPrincipal* aPrincipalToInherit,
@ -137,6 +139,8 @@ class SHEntrySharedParentState : public SHEntrySharedState {
RefPtr<nsFrameLoader> mFrameLoader;
nsExpirationState mExpirationState;
bool mSticky = true;
bool mDynamicallyCreated = false;
@ -166,7 +170,6 @@ class SHEntrySharedChildState {
nsCOMPtr<nsISupports> mWindowState;
// FIXME Move to parent?
nsCOMPtr<nsIMutableArray> mRefreshURIList;
nsExpirationState mExpirationState;
UniquePtr<nsDocShellEditorData> mEditorData;
};
@ -202,8 +205,6 @@ class nsSHEntryShared final : public nsIBFCacheEntry,
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
nsExpirationState* GetExpirationState() { return &mExpirationState; }
private:
~nsSHEntryShared();

View File

@ -1595,7 +1595,7 @@ void nsSHistory::GloballyEvictContentViewers() {
}
}
nsresult nsSHistory::FindEntryForBFCache(nsIBFCacheEntry* aBFEntry,
nsresult nsSHistory::FindEntryForBFCache(SHEntrySharedParentState* aEntry,
nsISHEntry** aResult,
int32_t* aResultIndex) {
*aResult = nullptr;
@ -1608,7 +1608,7 @@ nsresult nsSHistory::FindEntryForBFCache(nsIBFCacheEntry* aBFEntry,
nsCOMPtr<nsISHEntry> shEntry = mEntries[i];
// Does shEntry have the same BFCacheEntry as the argument to this method?
if (shEntry->HasBFCacheEntry(aBFEntry)) {
if (shEntry->HasBFCacheEntry(aEntry)) {
shEntry.forget(aResult);
*aResultIndex = i;
return NS_OK;
@ -1617,27 +1617,25 @@ nsresult nsSHistory::FindEntryForBFCache(nsIBFCacheEntry* aBFEntry,
return NS_ERROR_FAILURE;
}
nsresult nsSHistory::EvictExpiredContentViewerForEntry(
nsIBFCacheEntry* aBFEntry) {
NS_IMETHODIMP_(void)
nsSHistory::EvictExpiredContentViewerForEntry(
SHEntrySharedParentState* aEntry) {
int32_t index;
nsCOMPtr<nsISHEntry> shEntry;
FindEntryForBFCache(aBFEntry, getter_AddRefs(shEntry), &index);
FindEntryForBFCache(aEntry, getter_AddRefs(shEntry), &index);
if (index == mIndex) {
NS_WARNING("How did the current SHEntry expire?");
return NS_OK;
}
if (shEntry) {
EvictContentViewerForEntry(shEntry);
}
return NS_OK;
}
NS_IMETHODIMP_(void)
nsSHistory::AddToExpirationTracker(nsIBFCacheEntry* aBFEntry) {
RefPtr<nsSHEntryShared> entry = static_cast<nsSHEntryShared*>(aBFEntry);
nsSHistory::AddToExpirationTracker(SHEntrySharedParentState* aEntry) {
RefPtr<SHEntrySharedParentState> entry = aEntry;
if (!mHistoryTracker || !entry) {
return;
}
@ -1647,8 +1645,8 @@ nsSHistory::AddToExpirationTracker(nsIBFCacheEntry* aBFEntry) {
}
NS_IMETHODIMP_(void)
nsSHistory::RemoveFromExpirationTracker(nsIBFCacheEntry* aBFEntry) {
RefPtr<nsSHEntryShared> entry = static_cast<nsSHEntryShared*>(aBFEntry);
nsSHistory::RemoveFromExpirationTracker(SHEntrySharedParentState* aEntry) {
RefPtr<SHEntrySharedParentState> entry = aEntry;
MOZ_ASSERT(mHistoryTracker && !mHistoryTracker->IsEmpty());
if (!mHistoryTracker || !entry) {
return;
@ -1874,7 +1872,8 @@ void nsSHistory::RemoveDynEntries(int32_t aIndex, nsISHEntry* aEntry) {
void nsSHistory::RemoveDynEntriesForBFCacheEntry(nsIBFCacheEntry* aBFEntry) {
int32_t index;
nsCOMPtr<nsISHEntry> shEntry;
FindEntryForBFCache(aBFEntry, getter_AddRefs(shEntry), &index);
FindEntryForBFCache(static_cast<nsSHEntryShared*>(aBFEntry),
getter_AddRefs(shEntry), &index);
if (shEntry) {
RemoveDynEntries(index, shEntry);
}

View File

@ -36,7 +36,8 @@ class nsSHistory : public mozilla::LinkedListElement<nsSHistory>,
public nsSupportsWeakReference {
public:
// The timer based history tracker is used to evict bfcache on expiration.
class HistoryTracker final : public nsExpirationTracker<nsSHEntryShared, 3> {
class HistoryTracker final
: public nsExpirationTracker<mozilla::dom::SHEntrySharedParentState, 3> {
public:
explicit HistoryTracker(nsSHistory* aSHistory, uint32_t aTimeout,
nsIEventTarget* aEventTarget)
@ -47,7 +48,8 @@ class nsSHistory : public mozilla::LinkedListElement<nsSHistory>,
}
protected:
virtual void NotifyExpired(nsSHEntryShared* aObj) override {
virtual void NotifyExpired(
mozilla::dom::SHEntrySharedParentState* aObj) override {
RemoveObject(aObj);
mSHistory->EvictExpiredContentViewerForEntry(aObj);
}
@ -226,8 +228,8 @@ class nsSHistory : public mozilla::LinkedListElement<nsSHistory>,
// Find the history entry for a given bfcache entry. It only looks up between
// the range where alive viewers may exist (i.e nsSHistory::VIEWER_WINDOW).
nsresult FindEntryForBFCache(nsIBFCacheEntry* aBFEntry, nsISHEntry** aResult,
int32_t* aResultIndex);
nsresult FindEntryForBFCache(mozilla::dom::SHEntrySharedParentState* aEntry,
nsISHEntry** aResult, int32_t* aResultIndex);
// Evict content viewers in this window which don't lie in the "safe" range
// around aIndex.

View File

@ -11,7 +11,7 @@ add_task(async function testValidCache() {
});
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "data:text/html;charset=utf-8,page1" },
{ gBrowser, url: "data:text/html;charset=utf-8,pageA1" },
async function(browser) {
// Make a simple modification for bfcache testing.
await SpecialPowers.spawn(browser, [], () => {
@ -19,7 +19,7 @@ add_task(async function testValidCache() {
});
// Load a random page.
BrowserTestUtils.loadURI(browser, "data:text/html;charset=utf-8,page2");
BrowserTestUtils.loadURI(browser, "data:text/html;charset=utf-8,pageA2");
await BrowserTestUtils.browserLoaded(browser);
// Go back and verify text content.
@ -44,7 +44,7 @@ add_task(async function testExpiredCache() {
});
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "data:text/html;charset=utf-8,page1" },
{ gBrowser, url: "data:text/html;charset=utf-8,pageB1" },
async function(browser) {
// Make a simple modification for bfcache testing.
await SpecialPowers.spawn(browser, [], () => {
@ -52,7 +52,7 @@ add_task(async function testExpiredCache() {
});
// Load a random page.
BrowserTestUtils.loadURI(browser, "data:text/html;charset=utf-8,page2");
BrowserTestUtils.loadURI(browser, "data:text/html;charset=utf-8,pageB2");
await BrowserTestUtils.browserLoaded(browser);
// Wait for 3 times of expiration timeout, hopefully it's evicted...
@ -70,7 +70,7 @@ add_task(async function testExpiredCache() {
browser.goBack();
await awaitPageShow;
await SpecialPowers.spawn(browser, [], () => {
is(content.document.body.textContent, "page1");
is(content.document.body.textContent, "pageB1");
});
}
);