Bug 1183231 - Maintain a list of timeline-observed docshells outside of nsDocShell, r=smaug
authorVictor Porof <vporof@mozilla.com>
Sat, 18 Jul 2015 09:35:59 -0400
changeset 253561 e9c3cbdce3d577fcddcea3ce15c5c23199c284bb
parent 253560 080a2d9acd71d3bcc7e7fc0e3d0fb020fd1687eb
child 253562 a40f98f08e6b5bb959be8d12fdfd1c2f9824b795
push id29070
push userttaubert@mozilla.com
push dateMon, 20 Jul 2015 07:15:19 +0000
treeherdermozilla-central@202e9233d130 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1183231
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1183231 - Maintain a list of timeline-observed docshells outside of nsDocShell, r=smaug
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
docshell/base/timeline/AutoGlobalTimelineMarker.cpp
docshell/base/timeline/AutoGlobalTimelineMarker.h
docshell/base/timeline/AutoTimelineMarker.cpp
docshell/base/timeline/AutoTimelineMarker.h
docshell/base/timeline/ObservedDocShell.cpp
docshell/base/timeline/ObservedDocShell.h
docshell/base/timeline/TimelineConsumers.cpp
docshell/base/timeline/TimelineConsumers.h
docshell/base/timeline/moz.build
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -2924,36 +2924,27 @@ nsDocShell::HistoryTransactionRemoved(in
     if (shell) {
       static_cast<nsDocShell*>(shell.get())->HistoryTransactionRemoved(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();
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -30,16 +30,17 @@
 #include "nsCOMPtr.h"
 #include "nsPoint.h" // mCurrent/mDefaultScrollbarPreferences
 #include "nsString.h"
 #include "nsAutoPtr.h"
 #include "nsThreadUtils.h"
 #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
 
 // Interfaces Needed
 #include "nsIDocCharset.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIRefreshURI.h"
@@ -258,53 +259,22 @@ public:
   void NotifyAsyncPanZoomStopped();
 
   // Add new profile timeline markers to this docShell. This will only add
   // markers if the docShell is currently recording profile timeline markers.
   // See nsIDocShell::recordProfileTimelineMarkers
   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,
                           bool aInPrivateBrowsing);
 
 protected:
   virtual ~nsDocShell();
   virtual void DestroyChildren() override;
--- a/docshell/base/timeline/AutoGlobalTimelineMarker.cpp
+++ b/docshell/base/timeline/AutoGlobalTimelineMarker.cpp
@@ -7,63 +7,46 @@
 #include "mozilla/AutoGlobalTimelineMarker.h"
 
 #include "mozilla/TimelineConsumers.h"
 #include "MainThreadUtils.h"
 #include "nsDocShell.h"
 
 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());
 
   if (TimelineConsumers::IsEmpty()) {
     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;
   }
 
   for (Vector<nsRefPtr<nsDocShell>>::Range range = mDocShells.all();
        !range.empty();
        range.popFront()) {
     range.front()->AddProfileTimelineMarker(mName, TRACING_INTERVAL_START);
   }
 }
 
 AutoGlobalTimelineMarker::~AutoGlobalTimelineMarker()
 {
-  if (!mOk) {
+  if (!mDocShellsRetrieved) {
     return;
   }
 
   for (Vector<nsRefPtr<nsDocShell>>::Range range = mDocShells.all();
        !range.empty();
        range.popFront()) {
     range.front()->AddProfileTimelineMarker(mName, TRACING_INTERVAL_END);
   }
--- a/docshell/base/timeline/AutoGlobalTimelineMarker.h
+++ b/docshell/base/timeline/AutoGlobalTimelineMarker.h
@@ -29,31 +29,28 @@ namespace mozilla {
 //       nsCycleCollector* cc = GetCycleCollector();
 //       cc->Collect();
 //       ...
 //     }
 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;
   void operator=(const AutoGlobalTimelineMarker& aOther) = delete;
 };
 
 } // namespace mozilla
 
--- a/docshell/base/timeline/AutoTimelineMarker.cpp
+++ b/docshell/base/timeline/AutoTimelineMarker.cpp
@@ -6,36 +6,33 @@
 
 #include "mozilla/AutoTimelineMarker.h"
 
 #include "MainThreadUtils.h"
 #include "nsDocShell.h"
 
 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);
   }
 }
 
 AutoTimelineMarker::~AutoTimelineMarker()
 {
   if (mDocShell) {
--- a/docshell/base/timeline/AutoTimelineMarker.h
+++ b/docshell/base/timeline/AutoTimelineMarker.h
@@ -27,20 +27,21 @@ namespace mozilla {
 //       AutoTimelineMarker marker(mDocShell, "Parse CSS");
 //       nsresult rv = ParseTheCSSFile(mFile);
 //       ...
 //     }
 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
                               MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
   ~AutoTimelineMarker();
 
   AutoTimelineMarker(const AutoTimelineMarker& aOther) = delete;
   void operator=(const AutoTimelineMarker& aOther) = delete;
new file mode 100644
--- /dev/null
+++ b/docshell/base/timeline/ObservedDocShell.cpp
@@ -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
new file mode 100644
--- /dev/null
+++ b/docshell/base/timeline/ObservedDocShell.h
@@ -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_ */
--- a/docshell/base/timeline/TimelineConsumers.cpp
+++ b/docshell/base/timeline/TimelineConsumers.cpp
@@ -4,28 +4,62 @@
  * 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 "mozilla/TimelineConsumers.h"
 
 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
 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
--- a/docshell/base/timeline/TimelineConsumers.h
+++ b/docshell/base/timeline/TimelineConsumers.h
@@ -2,31 +2,36 @@
 /* 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 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
 
 #endif /* mozilla_TimelineConsumers_h_ */
--- a/docshell/base/timeline/moz.build
+++ b/docshell/base/timeline/moz.build
@@ -8,16 +8,17 @@ EXPORTS.mozilla += [
     'AutoGlobalTimelineMarker.h',
     'AutoTimelineMarker.h',
     'TimelineConsumers.h',
 ]
 
 UNIFIED_SOURCES += [
     'AutoGlobalTimelineMarker.cpp',
     'AutoTimelineMarker.cpp',
+    'ObservedDocShell.cpp',
     'TimelineConsumers.cpp',
     'TimelineMarker.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 FINAL_LIBRARY = 'xul'