Bug 1445659 - Make BrowsingContext interact with bfcache. r=peterv

Have BrowsingContext keep its own cache to enable caching of
BrowsingContexts, especially in the parent process.

This isn't really optimal, since it effectively duplicates the
cache in the child process. BFcache keeps a list of strong pointers to
the list of cached nsDocShells, where each nsDocShell in turn keeps a
reciprocated strong pointer to its BrowsingContext, which in turn is
held in the BrowsingContexts list of cached contexts. Ideally these
caches should be merged.

--HG--
extra : histedit_source : 094370f6d54d83728e8433ec5c47003086146476
This commit is contained in:
Andreas Farre 2018-06-28 05:40:00 +03:00
parent 1d151a57c8
commit cbc727cdcf
6 changed files with 79 additions and 8 deletions

View File

@ -13,6 +13,7 @@
#include "mozilla/StaticPtr.h"
#include "nsDataHashtable.h"
#include "nsRefPtrHashtable.h"
#include "nsIDocShell.h"
#include "nsContentUtils.h"
@ -26,6 +27,11 @@ static StaticAutoPtr<BrowsingContext::Children> sRootBrowsingContexts;
static StaticAutoPtr<nsDataHashtable<nsUint64HashKey, BrowsingContext*>>
sBrowsingContexts;
// TODO(farre): This duplicates some of the work performed by the
// bfcache. This should be unified. [Bug 1471601]
static StaticAutoPtr<nsRefPtrHashtable<nsUint64HashKey, BrowsingContext>>
sCachedBrowsingContexts;
/* static */ void
BrowsingContext::Init()
{
@ -39,6 +45,12 @@ BrowsingContext::Init()
new nsDataHashtable<nsUint64HashKey, BrowsingContext*>();
ClearOnShutdown(&sBrowsingContexts);
}
if (!sCachedBrowsingContexts) {
sCachedBrowsingContexts =
new nsRefPtrHashtable<nsUint64HashKey, BrowsingContext>();
ClearOnShutdown(&sCachedBrowsingContexts);
}
}
/* static */ LogModule*
@ -87,12 +99,16 @@ BrowsingContext::Attach(BrowsingContext* aParent)
Id(),
aParent ? aParent->Id() : 0));
MOZ_DIAGNOSTIC_ASSERT(sBrowsingContexts->Contains(Id()));
MOZ_DIAGNOSTIC_ASSERT(!IsCached());
return;
}
bool wasCached = sCachedBrowsingContexts->Remove(Id());
MOZ_LOG(GetLog(),
LogLevel::Debug,
("%s: Connecting 0x%08" PRIx64 " to 0x%08" PRIx64 "\n",
("%s: %s 0x%08" PRIx64 " to 0x%08" PRIx64,
wasCached ? "Re-connecting" : "Connecting",
XRE_IsParentProcess() ? "Parent" : "Child",
Id(),
aParent ? aParent->Id() : 0));
@ -118,6 +134,10 @@ BrowsingContext::Detach()
{
RefPtr<BrowsingContext> kungFuDeathGrip(this);
if (sCachedBrowsingContexts) {
sCachedBrowsingContexts->Remove(Id());
}
if (!isInList()) {
MOZ_LOG(GetLog(),
LogLevel::Debug,
@ -142,7 +162,42 @@ BrowsingContext::Detach()
auto cc = dom::ContentChild::GetSingleton();
MOZ_DIAGNOSTIC_ASSERT(cc);
cc->SendDetachBrowsingContext(dom::BrowsingContextId(Id()));
cc->SendDetachBrowsingContext(dom::BrowsingContextId(Id()),
false /* aMoveToBFCache */);
}
void
BrowsingContext::CacheChildren()
{
if (mChildren.isEmpty()) {
return;
}
MOZ_LOG(GetLog(),
LogLevel::Debug,
("%s: Caching children of 0x%08" PRIx64 "",
XRE_IsParentProcess() ? "Parent" : "Child",
Id()));
while (!mChildren.isEmpty()) {
RefPtr<BrowsingContext> child = mChildren.popFirst();
sCachedBrowsingContexts->Put(child->Id(), child);
}
if (!XRE_IsContentProcess()) {
return;
}
auto cc = dom::ContentChild::GetSingleton();
MOZ_DIAGNOSTIC_ASSERT(cc);
cc->SendDetachBrowsingContext(dom::BrowsingContextId(Id()),
true /* aMoveToBFCache */);
}
bool
BrowsingContext::IsCached()
{
return sCachedBrowsingContexts->Contains(Id());
}
uint64_t

View File

@ -66,6 +66,12 @@ public:
// child and the parent process.
void Detach();
// Remove all children from the current BrowsingContext and cache
// them to allow them to be attached again.
void CacheChildren();
bool IsCached();
void SetName(const nsAString& aName) { mName = aName; }
void GetName(nsAString& aName) { aName = mName; }
bool NameEquals(const nsAString& aName) { return mName.Equals(aName); }

View File

@ -7763,6 +7763,8 @@ nsDocShell::CaptureState()
mOSHE->AddChildShell(childShell);
}
mBrowsingContext->CacheChildren();
return NS_OK;
}

View File

@ -6028,7 +6028,7 @@ ContentParent::RecvAttachBrowsingContext(
}
RefPtr<BrowsingContext> child = BrowsingContext::Get(aChildId);
if (child) {
if (child && !child->IsCached()) {
// This is highly suspicious. BrowsingContexts should only be
// attached at most once, but finding one indicates that someone
// is doing something they shouldn't.
@ -6081,7 +6081,11 @@ ContentParent::RecvDetachBrowsingContext(const BrowsingContextId& aContextId,
return IPC_OK();
}
context->Detach();
if (aMoveToBFCache) {
context->CacheChildren();
} else {
context->Detach();
}
return IPC_OK();
}

View File

@ -688,7 +688,8 @@ public:
const nsString& aName) override;
virtual mozilla::ipc::IPCResult RecvDetachBrowsingContext(
const BrowsingContextId& aContextId) override;
const BrowsingContextId& aContextId,
const bool& aMoveToBFCache) override;
protected:
void OnChannelConnected(int32_t pid) override;

View File

@ -1200,10 +1200,13 @@ parent:
* node. Calling DetachBrowsingContext with an already detached
* BrowsingContext effectively does nothing. Note that it is not
* an error to call DetachBrowsingContext on a BrowsingContext
* belonging to an already detached subtree.
* belonging to an already detached subtree. The 'aMoveToBFCache'
* paramater controls if detaching a BrowsingContext should move
* it to the bfcache allowing it to be re-attached if navigated
* to.
*/
async DetachBrowsingContext(BrowsingContextId aContextId);
async DetachBrowsingContext(BrowsingContextId aContextId,
bool aMoveToBFCache);
both:
async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
Principal aPrincipal, ClonedMessageData aData);