Bug 1184377 - Move nsDocShell::PopProfileTimelineMarkers logic to ObservedDocShell, r=smaug

This commit is contained in:
Victor Porof
2015-07-18 09:35:59 -04:00
parent 9b3c3dd952
commit 97b6400fba
3 changed files with 108 additions and 123 deletions

View File

@@ -2953,129 +2953,16 @@ nsDocShell::GetRecordProfileTimelineMarkers(bool* aValue)
nsresult
nsDocShell::PopProfileTimelineMarkers(
JSContext* aCx,
JS::MutableHandle<JS::Value> aProfileTimelineMarkers)
JS::MutableHandle<JS::Value> aOut)
{
// 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<dom::ProfileTimelineMarker> store;
SequenceRooter<dom::ProfileTimelineMarker> rooter(aCx, &store);
nsTArray<mozilla::dom::ProfileTimelineMarker> profileTimelineMarkers;
SequenceRooter<mozilla::dom::ProfileTimelineMarker> rooter(
aCx, &profileTimelineMarkers);
if (!IsObserved()) {
if (!ToJSValue(aCx, profileTimelineMarkers, aProfileTimelineMarkers)) {
JS_ClearPendingException(aCx);
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
if (IsObserved()) {
mObserved->PopMarkers(aCx, store);
}
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)) {
if (!ToJSValue(aCx, store, aOut)) {
JS_ClearPendingException(aCx);
return NS_ERROR_UNEXPECTED;
}