Bug 1392408 Part 5 - Listen for alternate stack traces in StackTraceCollector, r=ochameau.
☠☠ backed out by 9dbf4a541fff ☠ ☠
authorBrian Hackett <bhackett1024@gmail.com>
Thu, 02 May 2019 08:35:34 -1000
changeset 531265 855b8dd227f92048824ff83ee46855f6f9bf010f
parent 531264 9c3b9f800a0ce8207d7716582206a2a4b2fe67e5
child 531266 ac9c08f90cd070b591211a51419b8e301470a911
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersochameau
bugs1392408
milestone68.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 1392408 Part 5 - Listen for alternate stack traces in StackTraceCollector, r=ochameau.
devtools/server/actors/network-monitor/stack-trace-collector.js
--- a/devtools/server/actors/network-monitor/stack-trace-collector.js
+++ b/devtools/server/actors/network-monitor/stack-trace-collector.js
@@ -20,65 +20,110 @@ function StackTraceCollector(filters, ne
   this.filters = filters;
   this.stacktracesById = new Map();
   this.netmonitors = netmonitors;
 }
 
 StackTraceCollector.prototype = {
   init() {
     Services.obs.addObserver(this, "http-on-opening-request");
+    Services.obs.addObserver(this, "network-monitor-alternate-stack");
     ChannelEventSinkFactory.getService().registerCollector(this);
     this.onGetStack = this.onGetStack.bind(this);
     for (const { messageManager } of this.netmonitors) {
       messageManager.addMessageListener("debug:request-stack:request", this.onGetStack);
     }
   },
 
   destroy() {
     Services.obs.removeObserver(this, "http-on-opening-request");
+    Services.obs.removeObserver(this, "network-monitor-alternate-stack");
     ChannelEventSinkFactory.getService().unregisterCollector(this);
     for (const { messageManager } of this.netmonitors) {
       messageManager.removeMessageListener("debug:request-stack:request",
         this.onGetStack);
     }
   },
 
   _saveStackTrace(channel, stacktrace) {
+    if (this.stacktracesById.has(channel.channelId)) {
+      // We can get up to two stack traces for the same channel: one each from
+      // the two observer topics we are listening to. Use the first stack trace
+      // which is specified, and ignore any later one.
+      return;
+    }
     for (const { messageManager } of this.netmonitors) {
       messageManager.sendAsyncMessage("debug:request-stack-available", {
         channelId: channel.channelId,
         stacktrace: stacktrace && stacktrace.length > 0,
       });
     }
     this.stacktracesById.set(channel.channelId, stacktrace);
   },
 
-  observe(subject) {
+  observe(subject, topic, data) {
     const channel = subject.QueryInterface(Ci.nsIHttpChannel);
 
     if (!matchRequest(channel, this.filters)) {
       return;
     }
 
-    // Convert the nsIStackFrame XPCOM objects to a nice JSON that can be
-    // passed around through message managers etc.
-    let frame = components.stack;
     const stacktrace = [];
-    if (frame && frame.caller) {
-      frame = frame.caller;
-      while (frame) {
-        stacktrace.push({
-          filename: frame.filename,
-          lineNumber: frame.lineNumber,
-          columnNumber: frame.columnNumber,
-          functionName: frame.name,
-          asyncCause: frame.asyncCause,
-        });
-        frame = frame.caller || frame.asyncCaller;
+    switch (topic) {
+      case "http-on-opening-request": {
+        // The channel is being opened on the main thread, associate the current
+        // stack with it.
+        //
+        // Convert the nsIStackFrame XPCOM objects to a nice JSON that can be
+        // passed around through message managers etc.
+        let frame = components.stack;
+        if (frame && frame.caller) {
+          frame = frame.caller;
+          while (frame) {
+            stacktrace.push({
+              filename: frame.filename,
+              lineNumber: frame.lineNumber,
+              columnNumber: frame.columnNumber,
+              functionName: frame.name,
+              asyncCause: frame.asyncCause,
+            });
+            frame = frame.caller || frame.asyncCaller;
+          }
+        }
+        break;
       }
+      case "network-monitor-alternate-stack": {
+        // An alternate stack trace is being specified for this channel.
+        // The topic data is the JSON for the saved frame stack we should use,
+        // so convert this into the expected format.
+        //
+        // This topic is used in the following cases:
+        //
+        // - The HTTP channel is opened asynchronously or on a different thread
+        //   from the code which triggered its creation, in which case the stack
+        //   from components.stack will be empty. The alternate stack will be
+        //   for the point we want to associate with the channel.
+        //
+        // - The channel is not a nsIHttpChannel, and we will receive no
+        //   opening request notification for it.
+        let frame = JSON.parse(data);
+        while (frame) {
+          stacktrace.push({
+            filename: frame.source,
+            lineNumber: frame.line,
+            columnNumber: frame.column,
+            functionName: frame.functionDisplayName,
+            asyncCause: frame.asyncCause,
+          });
+          frame = frame.parent || frame.asyncParent;
+        }
+        break;
+      }
+      default:
+        throw new Error("Unexpected observe() topic");
     }
 
     this._saveStackTrace(channel, stacktrace);
   },
 
   // eslint-disable-next-line no-shadow
   onChannelRedirect(oldChannel, newChannel, flags) {
     // We can be called with any nsIChannel, but are interested only in HTTP channels