Files
tubestation/docshell/base/BrowsingContext.cpp
Andreas Farre b80facf293 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.
2018-06-28 05:40:00 +03:00

243 lines
6.4 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "BrowsingContext.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/Assertions.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Logging.h"
#include "mozilla/StaticPtr.h"
#include "nsDataHashtable.h"
#include "nsRefPtrHashtable.h"
#include "nsIDocShell.h"
#include "nsContentUtils.h"
namespace mozilla {
namespace dom {
static LazyLogModule gBrowsingContextLog("BrowsingContext");
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()
{
if (!sRootBrowsingContexts) {
sRootBrowsingContexts = new BrowsingContext::Children();
ClearOnShutdown(&sRootBrowsingContexts);
}
if (!sBrowsingContexts) {
sBrowsingContexts =
new nsDataHashtable<nsUint64HashKey, BrowsingContext*>();
ClearOnShutdown(&sBrowsingContexts);
}
if (!sCachedBrowsingContexts) {
sCachedBrowsingContexts =
new nsRefPtrHashtable<nsUint64HashKey, BrowsingContext>();
ClearOnShutdown(&sCachedBrowsingContexts);
}
}
/* static */ LogModule*
BrowsingContext::GetLog()
{
return gBrowsingContextLog;
}
/* static */ already_AddRefed<BrowsingContext>
BrowsingContext::Get(uint64_t aId)
{
RefPtr<BrowsingContext> abc = sBrowsingContexts->Get(aId);
return abc.forget();
}
BrowsingContext::BrowsingContext(nsIDocShell* aDocShell)
: mBrowsingContextId(nsContentUtils::GenerateBrowsingContextId())
, mProcessId(Nothing())
, mDocShell(aDocShell)
{
sBrowsingContexts->Put(mBrowsingContextId, this);
}
BrowsingContext::BrowsingContext(uint64_t aBrowsingContextId,
const nsAString& aName,
const Maybe<uint64_t>& aProcessId)
: mBrowsingContextId(aBrowsingContextId)
, mProcessId(aProcessId)
, mName(aName)
{
// mProcessId only really has a meaning in the parent process, where
// it keeps track of which BrowsingContext is actually holding the
// nsDocShell.
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess() || aProcessId.isNothing());
sBrowsingContexts->Put(mBrowsingContextId, this);
}
void
BrowsingContext::Attach(BrowsingContext* aParent)
{
if (isInList()) {
MOZ_LOG(GetLog(),
LogLevel::Debug,
("%s: Connecting already existing 0x%08" PRIx64 " to 0x%08" PRIx64,
XRE_IsParentProcess() ? "Parent" : "Child",
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: %s 0x%08" PRIx64 " to 0x%08" PRIx64,
wasCached ? "Re-connecting" : "Connecting",
XRE_IsParentProcess() ? "Parent" : "Child",
Id(),
aParent ? aParent->Id() : 0));
auto* children = aParent ? &aParent->mChildren : sRootBrowsingContexts.get();
children->insertBack(this);
mParent = aParent;
if (!XRE_IsContentProcess()) {
return;
}
auto cc = dom::ContentChild::GetSingleton();
MOZ_DIAGNOSTIC_ASSERT(cc);
cc->SendAttachBrowsingContext(
dom::BrowsingContextId(mParent ? mParent->Id() : 0),
dom::BrowsingContextId(Id()),
mName);
}
void
BrowsingContext::Detach()
{
RefPtr<BrowsingContext> kungFuDeathGrip(this);
if (sCachedBrowsingContexts) {
sCachedBrowsingContexts->Remove(Id());
}
if (!isInList()) {
MOZ_LOG(GetLog(),
LogLevel::Debug,
("%s: Detaching already detached 0x%08" PRIx64,
XRE_IsParentProcess() ? "Parent" : "Child",
Id()));
return;
}
MOZ_LOG(GetLog(),
LogLevel::Debug,
("%s: Detaching 0x%08" PRIx64 " from 0x%08" PRIx64,
XRE_IsParentProcess() ? "Parent" : "Child",
Id(),
mParent ? mParent->Id() : 0));
remove();
if (!XRE_IsContentProcess()) {
return;
}
auto cc = dom::ContentChild::GetSingleton();
MOZ_DIAGNOSTIC_ASSERT(cc);
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
BrowsingContext::OwnerProcessId() const
{
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
return mProcessId.value();
}
BrowsingContext::~BrowsingContext()
{
MOZ_DIAGNOSTIC_ASSERT(!isInList());
if (sBrowsingContexts) {
sBrowsingContexts->Remove(mBrowsingContextId);
}
}
static void
ImplCycleCollectionUnlink(BrowsingContext::Children& aField)
{
aField.clear();
}
static void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
BrowsingContext::Children& aField,
const char* aName,
uint32_t aFlags = 0)
{
for (BrowsingContext* aContext : aField) {
aCallback.NoteNativeChild(aContext,
NS_CYCLE_COLLECTION_PARTICIPANT(BrowsingContext));
}
}
NS_IMPL_CYCLE_COLLECTION(BrowsingContext, mDocShell, mChildren)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(BrowsingContext, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(BrowsingContext, Release)
} // namespace dom
} // namespace mozilla