Bug 1697838, explictly evict bfcache when doing a frameloader swap r=peterv

This is in practice the behavior already, because swap is really a move and removing the old tab, and
when removing the other tab, the bfcached frameloaders are destroyed. But they stay still in the session history.
So this patch clears session history explicitly.

As long as we have message managers, we can't really support bfcache in this case, since we can't swap message managers,
there are no corresponding managers on the other side.
Message managers need to stay always in the original window, since the listeners are from there.

WindowActors do move with frameloader/browsingcontext, but that leads easily to memory leaks.
https://bugzilla.mozilla.org/show_bug.cgi?id=1697918 is about that and it has nothing to do with bfcache.

Differential Revision: https://phabricator.services.mozilla.com/D108273
This commit is contained in:
Olli Pettay 2021-03-24 18:57:14 +00:00
Родитель 9c99ace8f3
Коммит 67eda3a866
3 изменённых файлов: 76 добавлений и 0 удалений

Просмотреть файл

@ -142,6 +142,7 @@ skip-if = (verify && debug && (os == 'win'))
[browser_data_load_inherit_csp.js]
[browser_dataURI_unique_opaque_origin.js]
[browser_fission_maxOrigins.js]
[browser_frameloader_swap_with_bfcache.js]
[browser_uriFixupIntegration.js]
[browser_uriFixupAlternateRedirects.js]
support-files =

Просмотреть файл

@ -0,0 +1,37 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
add_task(async function test() {
if (
!SpecialPowers.Services.appinfo.sessionHistoryInParent ||
!SpecialPowers.Services.prefs.getBoolPref("fission.bfcacheInParent")
) {
ok(
true,
"This test is currently only for the bfcache in the parent process."
);
return;
}
const uri =
"data:text/html,<script>onpageshow = function(e) { document.documentElement.setAttribute('persisted', e.persisted); }; </script>";
let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, uri, true);
let browser1 = tab1.linkedBrowser;
let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, uri, true);
let browser2 = tab2.linkedBrowser;
BrowserTestUtils.loadURI(browser2, uri + "nextpage");
await BrowserTestUtils.browserLoaded(browser2, false);
gBrowser.swapBrowsersAndCloseOther(tab1, tab2);
is(tab1.linkedBrowser, browser1, "Tab's browser should stay the same.");
browser1.goBack(false);
await BrowserTestUtils.browserLoaded(browser1, false);
let persisted = await SpecialPowers.spawn(browser1, [], async function() {
return content.document.documentElement.getAttribute("persisted");
});
is(persisted, "false", "BFCache should be evicted when swapping browsers.");
BrowserTestUtils.removeTab(tab1);
});

Просмотреть файл

@ -87,6 +87,7 @@
#include "mozilla/dom/FrameLoaderBinding.h"
#include "mozilla/dom/MozFrameLoaderOwnerBinding.h"
#include "mozilla/dom/PBrowser.h"
#include "mozilla/dom/SessionHistoryEntry.h"
#include "mozilla/dom/SessionStoreListener.h"
#include "mozilla/dom/WindowGlobalParent.h"
#include "mozilla/dom/XULFrameElement.h"
@ -1309,6 +1310,23 @@ nsresult nsFrameLoader::SwapWithOtherRemoteLoader(
MaybeUpdatePrimaryBrowserParent(eBrowserParentRemoved);
aOther->MaybeUpdatePrimaryBrowserParent(eBrowserParentRemoved);
if (mozilla::BFCacheInParent() && XRE_IsParentProcess()) {
// nsFrameLoaders in session history can't be moved to another owner since
// there are no corresponging message managers on which swap can be done.
// See the line mMessageManager.swap(aOther->mMessageManager); below.
auto evict = [](nsFrameLoader* aFrameLoader) {
if (BrowsingContext* bc =
aFrameLoader->GetMaybePendingBrowsingContext()) {
nsCOMPtr<nsISHistory> shistory = bc->Canonical()->GetSessionHistory();
if (shistory) {
shistory->EvictAllContentViewers();
}
}
};
evict(this);
evict(aOther);
}
SetOwnerContent(otherContent);
aOther->SetOwnerContent(ourContent);
@ -1339,6 +1357,9 @@ nsresult nsFrameLoader::SwapWithOtherRemoteLoader(
}
mMessageManager.swap(aOther->mMessageManager);
// XXXsmaug what should be done to JSWindowActorParent objects when swapping
// frameloaders? Currently they leak very easily, bug 1697918.
// Perform the actual swap of the internal refptrs. We keep a strong reference
// to ourselves to make sure we don't die while we overwrite our reference to
// ourself.
@ -2066,6 +2087,23 @@ void nsFrameLoader::SetOwnerContent(Element* aContent) {
if (RefPtr<nsFrameLoaderOwner> owner = do_QueryObject(mOwnerContent)) {
owner->AttachFrameLoader(this);
#ifdef NIGHTLY_BUILD
if (mozilla::BFCacheInParent() && XRE_IsParentProcess()) {
if (BrowsingContext* bc = GetMaybePendingBrowsingContext()) {
nsISHistory* shistory = bc->Canonical()->GetSessionHistory();
if (shistory) {
uint32_t count = shistory->GetCount();
for (uint32_t i = 0; i < count; ++i) {
nsCOMPtr<nsISHEntry> entry;
shistory->GetEntryAtIndex(i, getter_AddRefs(entry));
nsCOMPtr<SessionHistoryEntry> she = do_QueryInterface(entry);
MOZ_RELEASE_ASSERT(!she || !she->GetFrameLoader());
}
}
}
}
#endif
}
if (mSessionStoreListener && mOwnerContent) {