Bug 1184377 - Move nsDocShell::PopProfileTimelineMarkers logic to ObservedDocShell, r=smaug
authorVictor Porof <vporof@mozilla.com>
Sat, 18 Jul 2015 09:35:59 -0400
changeset 253564 7c8dd116e5835d6a6d3760833c59f522b4115a2c
parent 253563 577738eb609739ea893b84bd3421adffad20fc0d
child 253565 fdff9c45b9c96b75d624fa10cd76704751a28688
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
bugs1184377
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 1184377 - Move nsDocShell::PopProfileTimelineMarkers logic to ObservedDocShell, r=smaug
docshell/base/nsDocShell.cpp
docshell/base/timeline/ObservedDocShell.cpp
docshell/base/timeline/ObservedDocShell.h
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -2950,136 +2950,23 @@ NS_IMETHODIMP
 nsDocShell::GetRecordProfileTimelineMarkers(bool* aValue)
 {
   *aValue = IsObserved();
   return NS_OK;
 }
 
 nsresult
 nsDocShell::PopProfileTimelineMarkers(
-    JSContext* aCx,
-    JS::MutableHandle<JS::Value> aProfileTimelineMarkers)
-{
-  // Looping over all markers gathered so far at the docShell level, whenever a
-  // START marker is found, look for the corresponding END marker and build a
-  // {name,start,end} JS object.
-  // Paint markers are different because paint is handled at root docShell level
-  // in the information that a paint was done is then stored at each sub
-  // docShell level but we can only be sure that a paint did happen in a
-  // docShell if an Layer marker type was recorded too.
-
-  nsTArray<mozilla::dom::ProfileTimelineMarker> profileTimelineMarkers;
-  SequenceRooter<mozilla::dom::ProfileTimelineMarker> rooter(
-    aCx, &profileTimelineMarkers);
-
-  nsTArray<UniquePtr<TimelineMarker>>& markersStore = mObserved.get()->mTimelineMarkers;
-
-  // If we see an unpaired START, we keep it around for the next call
-  // to PopProfileTimelineMarkers.  We store the kept START objects in
-  // this array.
-  nsTArray<UniquePtr<TimelineMarker>> keptMarkers;
-
-  for (uint32_t i = 0; i < markersStore.Length(); ++i) {
-    UniquePtr<TimelineMarker>& startPayload = markersStore[i];
-    const char* startMarkerName = startPayload->GetName();
-
-    bool hasSeenPaintedLayer = false;
-    bool isPaint = strcmp(startMarkerName, "Paint") == 0;
-
-    // If we are processing a Paint marker, we append information from
-    // all the embedded Layer markers to this array.
-    dom::Sequence<dom::ProfileTimelineLayerRect> layerRectangles;
-
-    // If this is a TRACING_TIMESTAMP marker, there's no corresponding "end"
-    // marker, as it's a single unit of time, not a duration, create the final
-    // marker here.
-    if (startPayload->GetMetaData() == TRACING_TIMESTAMP) {
-      mozilla::dom::ProfileTimelineMarker* marker =
-        profileTimelineMarkers.AppendElement();
-
-      marker->mName = NS_ConvertUTF8toUTF16(startPayload->GetName());
-      marker->mStart = startPayload->GetTime();
-      marker->mEnd = startPayload->GetTime();
-      marker->mStack = startPayload->GetStack();
-      startPayload->AddDetails(aCx, *marker);
-      continue;
-    }
-
-    if (startPayload->GetMetaData() == TRACING_INTERVAL_START) {
-      bool hasSeenEnd = false;
-
-      // DOM events can be nested, so we must take care when searching
-      // for the matching end.  It doesn't hurt to apply this logic to
-      // all event types.
-      uint32_t markerDepth = 0;
-
-      // The assumption is that the devtools timeline flushes markers frequently
-      // enough for the amount of markers to always be small enough that the
-      // nested for loop isn't going to be a performance problem.
-      for (uint32_t j = i + 1; j < markersStore.Length(); ++j) {
-        UniquePtr<TimelineMarker>& endPayload = markersStore[j];
-        const char* endMarkerName = endPayload->GetName();
-
-        // Look for Layer markers to stream out paint markers.
-        if (isPaint && strcmp(endMarkerName, "Layer") == 0) {
-          hasSeenPaintedLayer = true;
-          endPayload->AddLayerRectangles(layerRectangles);
-        }
-
-        if (!startPayload->Equals(*endPayload)) {
-          continue;
-        }
-
-        // Pair start and end markers.
-        if (endPayload->GetMetaData() == TRACING_INTERVAL_START) {
-          ++markerDepth;
-        } else if (endPayload->GetMetaData() == TRACING_INTERVAL_END) {
-          if (markerDepth > 0) {
-            --markerDepth;
-          } else {
-            // But ignore paint start/end if no layer has been painted.
-            if (!isPaint || (isPaint && hasSeenPaintedLayer)) {
-              mozilla::dom::ProfileTimelineMarker* marker =
-                profileTimelineMarkers.AppendElement();
-
-              marker->mName = NS_ConvertUTF8toUTF16(startPayload->GetName());
-              marker->mStart = startPayload->GetTime();
-              marker->mEnd = endPayload->GetTime();
-              marker->mStack = startPayload->GetStack();
-              if (isPaint) {
-                marker->mRectangles.Construct(layerRectangles);
-              }
-              startPayload->AddDetails(aCx, *marker);
-              endPayload->AddDetails(aCx, *marker);
-            }
-
-            // We want the start to be dropped either way.
-            hasSeenEnd = true;
-
-            break;
-          }
-        }
-      }
-
-      // If we did not see the corresponding END, keep the START.
-      if (!hasSeenEnd) {
-        keptMarkers.AppendElement(Move(markersStore[i]));
-        markersStore.RemoveElementAt(i);
-        --i;
-      }
-    }
-  }
-
-  markersStore.SwapElements(keptMarkers);
-
-  if (!ToJSValue(aCx, profileTimelineMarkers, aProfileTimelineMarkers)) {
+  JSContext* aCx,
+  JS::MutableHandle<JS::Value> aStore)
+{
+  if (!mObserved->PopMarkers(aCx, aStore)) {
     JS_ClearPendingException(aCx);
     return NS_ERROR_UNEXPECTED;
   }
-
   return NS_OK;
 }
 
 nsresult
 nsDocShell::Now(DOMHighResTimeStamp* aWhen)
 {
   bool ignore;
   *aWhen =
--- a/docshell/base/timeline/ObservedDocShell.cpp
+++ b/docshell/base/timeline/ObservedDocShell.cpp
@@ -3,19 +3,24 @@
 /* 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"
 
 #include "TimelineMarker.h"
 #include "mozilla/Move.h"
+#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/ToJSValue.h"
 
 namespace mozilla {
 
+using dom::ProfileTimelineMarker;
+using dom::ProfileTimelineLayerRect;
+
 ObservedDocShell::ObservedDocShell(nsDocShell* aDocShell)
   : mDocShell(aDocShell)
 {}
 
 void
 ObservedDocShell::AddMarker(const char* aName, TracingMetadata aMetaData)
 {
   TimelineMarker* marker = new TimelineMarker(mDocShell, aName, aMetaData);
@@ -29,9 +34,111 @@ ObservedDocShell::AddMarker(UniquePtr<Ti
 }
 
 void
 ObservedDocShell::ClearMarkers()
 {
   mTimelineMarkers.Clear();
 }
 
+bool
+ObservedDocShell::PopMarkers(JSContext* aCx,
+                             JS::MutableHandle<JS::Value> aStore)
+{
+  nsTArray<ProfileTimelineMarker> webidlStore;
+  dom::SequenceRooter<ProfileTimelineMarker> rooter(aCx, &webidlStore);
+
+  // If we see an unpaired START, we keep it around for the next call
+  // to ObservedDocShell::PopMarkers. We store the kept START objects here.
+  nsTArray<UniquePtr<TimelineMarker>> keptStartMarkers;
+
+  for (uint32_t i = 0; i < mTimelineMarkers.Length(); ++i) {
+    UniquePtr<TimelineMarker>& startPayload = mTimelineMarkers[i];
+
+    // If this is a TRACING_TIMESTAMP marker, there's no corresponding END
+    // as it's a single unit of time, not a duration.
+    if (startPayload->GetMetaData() == TRACING_TIMESTAMP) {
+      ProfileTimelineMarker* marker = webidlStore.AppendElement();
+      marker->mName = NS_ConvertUTF8toUTF16(startPayload->GetName());
+      marker->mStart = startPayload->GetTime();
+      marker->mEnd = startPayload->GetTime();
+      marker->mStack = startPayload->GetStack();
+      startPayload->AddDetails(aCx, *marker);
+      continue;
+    }
+
+    // Whenever a START marker is found, look for the corresponding END
+    // and build a {name,start,end} JS object.
+    if (startPayload->GetMetaData() == TRACING_INTERVAL_START) {
+      bool hasSeenEnd = false;
+
+      // "Paint" markers are different because painting is handled at root
+      // docshell level. The information that a paint was done is stored at
+      // sub-docshell level, but we can only be sure that a paint did actually
+      // happen in if a "Layer" marker was recorded too.
+      bool startIsPaintType = strcmp(startPayload->GetName(), "Paint") == 0;
+      bool hasSeenLayerType = false;
+
+      // If we are processing a "Paint" marker, we append information from
+      // all the embedded "Layer" markers to this array.
+      dom::Sequence<ProfileTimelineLayerRect> layerRectangles;
+
+      // DOM events can be nested, so we must take care when searching
+      // for the matching end. It doesn't hurt to apply this logic to
+      // all event types.
+      uint32_t markerDepth = 0;
+
+      // The assumption is that the devtools timeline flushes markers frequently
+      // enough for the amount of markers to always be small enough that the
+      // nested for loop isn't going to be a performance problem.
+      for (uint32_t j = i + 1; j < mTimelineMarkers.Length(); ++j) {
+        UniquePtr<TimelineMarker>& endPayload = mTimelineMarkers[j];
+        bool endIsLayerType = strcmp(endPayload->GetName(), "Layer") == 0;
+
+        // Look for "Layer" markers to stream out "Paint" markers.
+        if (startIsPaintType && endIsLayerType) {
+          hasSeenLayerType = true;
+          endPayload->AddLayerRectangles(layerRectangles);
+        }
+        if (!startPayload->Equals(*endPayload)) {
+          continue;
+        }
+        if (endPayload->GetMetaData() == TRACING_INTERVAL_START) {
+          ++markerDepth;
+          continue;
+        }
+        if (endPayload->GetMetaData() == TRACING_INTERVAL_END) {
+          if (markerDepth > 0) {
+            --markerDepth;
+            continue;
+          }
+          if (!startIsPaintType || (startIsPaintType && hasSeenLayerType)) {
+            ProfileTimelineMarker* marker = webidlStore.AppendElement();
+            marker->mName = NS_ConvertUTF8toUTF16(startPayload->GetName());
+            marker->mStart = startPayload->GetTime();
+            marker->mEnd = endPayload->GetTime();
+            marker->mStack = startPayload->GetStack();
+            if (hasSeenLayerType) {
+              marker->mRectangles.Construct(layerRectangles);
+            }
+            startPayload->AddDetails(aCx, *marker);
+            endPayload->AddDetails(aCx, *marker);
+          }
+          hasSeenEnd = true;
+          break;
+        }
+      }
+
+      // If we did not see the corresponding END, keep the START.
+      if (!hasSeenEnd) {
+        keptStartMarkers.AppendElement(Move(mTimelineMarkers[i]));
+        mTimelineMarkers.RemoveElementAt(i);
+        --i;
+      }
+    }
+  }
+
+  mTimelineMarkers.SwapElements(keptStartMarkers);
+
+  return ToJSValue(aCx, webidlStore, aStore);
+}
+
 } // namespace mozilla
--- a/docshell/base/timeline/ObservedDocShell.h
+++ b/docshell/base/timeline/ObservedDocShell.h
@@ -19,25 +19,23 @@ 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;
+  nsTArray<UniquePtr<TimelineMarker>> mTimelineMarkers;
 
 public:
-  // FIXME: make this private once all marker-specific logic has been
-  // moved out of nsDocShell.
-  nsTArray<UniquePtr<TimelineMarker>> mTimelineMarkers;
-
   explicit ObservedDocShell(nsDocShell* aDocShell);
   nsDocShell* operator*() const { return mDocShell.get(); }
 
   void AddMarker(const char* aName, TracingMetadata aMetaData);
   void AddMarker(UniquePtr<TimelineMarker>&& aMarker);
   void ClearMarkers();
+  bool PopMarkers(JSContext* aCx, JS::MutableHandle<JS::Value> aStore);
 };
 
 } // namespace mozilla
 
 #endif /* ObservedDocShell_h_ */