Bug 1183231 - Maintain a list of timeline-observed docshells outside of nsDocShell, r=smaug

This commit is contained in:
Victor Porof 2015-07-18 09:35:59 -04:00
parent 2f1e820cee
commit 18ba8c2e6d
11 changed files with 125 additions and 99 deletions

View File

@ -2929,26 +2929,17 @@ nsDocShell::HistoryTransactionRemoved(int32_t aIndex)
return NS_OK;
}
mozilla::LinkedList<nsDocShell::ObservedDocShell>* nsDocShell::gObservedDocShells = nullptr;
NS_IMETHODIMP
nsDocShell::SetRecordProfileTimelineMarkers(bool aValue)
{
bool currentValue = nsIDocShell::GetRecordProfileTimelineMarkers();
if (currentValue != aValue) {
if (aValue) {
TimelineConsumers::AddConsumer();
TimelineConsumers::AddConsumer(this, mObserved);
UseEntryScriptProfiling();
MOZ_ASSERT(!mObserved);
mObserved.reset(new ObservedDocShell(this));
GetOrCreateObservedDocShells().insertFront(mObserved.get());
} else {
TimelineConsumers::RemoveConsumer();
TimelineConsumers::RemoveConsumer(this, mObserved);
UnuseEntryScriptProfiling();
mObserved.reset(nullptr);
ClearProfileTimelineMarkers();
}
}

View File

@ -35,6 +35,7 @@
#include "nsContentUtils.h"
#include "timeline/TimelineMarker.h"
#include "timeline/TimelineConsumers.h"
#include "timeline/ObservedDocShell.h"
// Threshold value in ms for META refresh based redirects
#define REFRESH_REDIRECT_TIMER 15000
@ -263,43 +264,12 @@ public:
void AddProfileTimelineMarker(const char* aName, TracingMetadata aMetaData);
void AddProfileTimelineMarker(mozilla::UniquePtr<TimelineMarker>&& aMarker);
class ObservedDocShell : public mozilla::LinkedListElement<ObservedDocShell>
{
public:
explicit ObservedDocShell(nsDocShell* aDocShell)
: mDocShell(aDocShell)
{ }
nsDocShell* operator*() const { return mDocShell.get(); }
private:
nsRefPtr<nsDocShell> mDocShell;
};
private:
static mozilla::LinkedList<ObservedDocShell>* gObservedDocShells;
static mozilla::LinkedList<ObservedDocShell>& GetOrCreateObservedDocShells()
{
if (!gObservedDocShells) {
gObservedDocShells = new mozilla::LinkedList<ObservedDocShell>();
}
return *gObservedDocShells;
}
// Never null if timeline markers are being observed.
mozilla::UniquePtr<ObservedDocShell> mObserved;
// Return true if timeline markers are being observed for this docshell. False
// otherwise.
// An observed docshell wrapper is created when recording markers is enabled.
mozilla::UniquePtr<mozilla::ObservedDocShell> mObserved;
bool IsObserved() const { return !!mObserved; }
public:
static const mozilla::LinkedList<ObservedDocShell>& GetObservedDocShells()
{
return GetOrCreateObservedDocShells();
}
// Tell the favicon service that aNewURI has the same favicon as aOldURI.
static void CopyFavicon(nsIURI* aOldURI,
nsIURI* aNewURI,

View File

@ -12,28 +12,11 @@
namespace mozilla {
void
AutoGlobalTimelineMarker::PopulateDocShells()
{
const LinkedList<nsDocShell::ObservedDocShell>& docShells =
nsDocShell::GetObservedDocShells();
MOZ_ASSERT(!docShells.isEmpty());
for (const nsDocShell::ObservedDocShell* ds = docShells.getFirst();
ds;
ds = ds->getNext()) {
mOk = mDocShells.append(**ds);
if (!mOk) {
return;
}
}
}
AutoGlobalTimelineMarker::AutoGlobalTimelineMarker(const char* aName
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
: mOk(true)
: mName(aName)
, mDocShells()
, mName(aName)
, mDocShellsRetrieved(false)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
MOZ_ASSERT(NS_IsMainThread());
@ -42,8 +25,8 @@ AutoGlobalTimelineMarker::AutoGlobalTimelineMarker(const char* aName
return;
}
PopulateDocShells();
if (!mOk) {
mDocShellsRetrieved = TimelineConsumers::GetKnownDocShells(mDocShells);
if (!mDocShellsRetrieved) {
// If we don't successfully populate our vector with *all* docshells being
// observed, don't add markers to *any* of them.
return;
@ -58,7 +41,7 @@ AutoGlobalTimelineMarker::AutoGlobalTimelineMarker(const char* aName
AutoGlobalTimelineMarker::~AutoGlobalTimelineMarker()
{
if (!mOk) {
if (!mDocShellsRetrieved) {
return;
}

View File

@ -34,21 +34,18 @@ class MOZ_STACK_CLASS AutoGlobalTimelineMarker
{
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER;
// True as long as no operation has failed, eg due to OOM.
bool mOk;
// The set of docshells that are being observed and will get markers.
mozilla::Vector<nsRefPtr<nsDocShell>> mDocShells;
// The name of the marker we are adding.
const char* mName;
void PopulateDocShells();
// The set of docshells that will get the marker.
Vector<nsRefPtr<nsDocShell>> mDocShells;
// True as long as no operation has failed, eg due to OOM.
bool mDocShellsRetrieved;
public:
explicit AutoGlobalTimelineMarker(const char* aName
MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
~AutoGlobalTimelineMarker();
AutoGlobalTimelineMarker(const AutoGlobalTimelineMarker& aOther) = delete;

View File

@ -11,26 +11,23 @@
namespace mozilla {
bool
AutoTimelineMarker::DocShellIsRecording(nsDocShell& aDocShell)
{
bool isRecording = false;
if (!TimelineConsumers::IsEmpty()) {
aDocShell.GetRecordProfileTimelineMarkers(&isRecording);
}
return isRecording;
}
AutoTimelineMarker::AutoTimelineMarker(nsIDocShell* aDocShell, const char* aName
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
: mDocShell(nullptr)
, mName(aName)
: mName(aName)
, mDocShell(nullptr)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
MOZ_ASSERT(NS_IsMainThread());
if (TimelineConsumers::IsEmpty()) {
return;
}
bool isRecordingEnabledForDocShell = false;
nsDocShell* docShell = static_cast<nsDocShell*>(aDocShell);
if (docShell && DocShellIsRecording(*docShell)) {
aDocShell->GetRecordProfileTimelineMarkers(&isRecordingEnabledForDocShell);
if (isRecordingEnabledForDocShell) {
mDocShell = docShell;
mDocShell->AddProfileTimelineMarker(mName, TRACING_INTERVAL_START);
}

View File

@ -32,10 +32,11 @@ class MOZ_STACK_CLASS AutoTimelineMarker
{
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER;
nsRefPtr<nsDocShell> mDocShell;
// The name of the marker we are adding.
const char* mName;
bool DocShellIsRecording(nsDocShell& aDocShell);
// The docshell that is associated with this marker.
nsRefPtr<nsDocShell> mDocShell;
public:
explicit AutoTimelineMarker(nsIDocShell* aDocShell, const char* aName

View File

@ -0,0 +1,15 @@
/* -*- 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 "ObservedDocShell.h"
namespace mozilla {
ObservedDocShell::ObservedDocShell(nsDocShell* aDocShell)
: mDocShell(aDocShell)
{}
} // namespace mozilla

View File

@ -0,0 +1,32 @@
/* -*- 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/. */
#ifndef ObservedDocShell_h_
#define ObservedDocShell_h_
#include "nsRefPtr.h"
class nsDocShell;
namespace mozilla {
// # ObservedDocShell
//
// A wrapper around a docshell for which docshell-specific markers are
// allowed to exist. See TimelineConsumers for register/unregister logic.
class ObservedDocShell : public LinkedListElement<ObservedDocShell>
{
private:
nsRefPtr<nsDocShell> mDocShell;
public:
explicit ObservedDocShell(nsDocShell* aDocShell);
nsDocShell* operator*() const { return mDocShell.get(); }
};
} // namespace mozilla
#endif /* ObservedDocShell_h_ */

View File

@ -9,17 +9,35 @@
namespace mozilla {
unsigned long TimelineConsumers::sActiveConsumers = 0;
LinkedList<ObservedDocShell>* TimelineConsumers::sObservedDocShells = nullptr;
void
TimelineConsumers::AddConsumer()
LinkedList<ObservedDocShell>&
TimelineConsumers::GetOrCreateObservedDocShellsList()
{
sActiveConsumers++;
if (!sObservedDocShells) {
sObservedDocShells = new LinkedList<ObservedDocShell>();
}
return *sObservedDocShells;
}
void
TimelineConsumers::RemoveConsumer()
TimelineConsumers::AddConsumer(nsDocShell* aDocShell,
UniquePtr<ObservedDocShell>& aObservedPtr)
{
MOZ_ASSERT(!aObservedPtr);
sActiveConsumers++;
aObservedPtr.reset(new ObservedDocShell(aDocShell));
GetOrCreateObservedDocShellsList().insertFront(aObservedPtr.get());
}
void
TimelineConsumers::RemoveConsumer(nsDocShell* aDocShell,
UniquePtr<ObservedDocShell>& aObservedPtr)
{
MOZ_ASSERT(aObservedPtr);
sActiveConsumers--;
aObservedPtr.get()->remove();
aObservedPtr.reset(nullptr);
}
bool
@ -28,4 +46,20 @@ TimelineConsumers::IsEmpty()
return sActiveConsumers == 0;
}
bool
TimelineConsumers::GetKnownDocShells(Vector<nsRefPtr<nsDocShell>>& aStore)
{
const LinkedList<ObservedDocShell>& docShells = GetOrCreateObservedDocShellsList();
for (const ObservedDocShell* rds = docShells.getFirst();
rds != nullptr;
rds = rds->getNext()) {
if (!aStore.append(**rds)) {
return false;
}
}
return true;
}
} // namespace mozilla

View File

@ -7,24 +7,29 @@
#ifndef mozilla_TimelineConsumers_h_
#define mozilla_TimelineConsumers_h_
#include "mozilla/LinkedList.h"
#include "mozilla/UniquePtr.h"
#include "timeline/ObservedDocShell.h"
class nsDocShell;
namespace mozilla {
// # TimelineConsumers
//
// A class to trace how many frontends are interested in markers. Whenever
// interest is expressed in markers, these fields will keep track of that.
class TimelineConsumers
{
private:
// Counter for how many timelines are currently interested in markers.
static unsigned long sActiveConsumers;
static LinkedList<ObservedDocShell>* sObservedDocShells;
static LinkedList<ObservedDocShell>& GetOrCreateObservedDocShellsList();
public:
static void AddConsumer();
static void RemoveConsumer();
static void AddConsumer(nsDocShell* aDocShell,
UniquePtr<ObservedDocShell>& aObservedPtr);
static void RemoveConsumer(nsDocShell* aDocShell,
UniquePtr<ObservedDocShell>& aObservedPtr);
static bool IsEmpty();
static bool GetKnownDocShells(Vector<nsRefPtr<nsDocShell>>& aStore);
};
} // namespace mozilla

View File

@ -13,6 +13,7 @@ EXPORTS.mozilla += [
UNIFIED_SOURCES += [
'AutoGlobalTimelineMarker.cpp',
'AutoTimelineMarker.cpp',
'ObservedDocShell.cpp',
'TimelineConsumers.cpp',
'TimelineMarker.cpp',
]