Merge m-c to inbound
authorWes Kocher <wkocher@mozilla.com>
Fri, 11 Oct 2013 18:58:44 -0700
changeset 164376 f52aa208d2ea94457693aa95b5f79f9679ae0dd5
parent 164375 a195c8d3b537aa406a3c920b55da75ccc1ea3548 (current diff)
parent 164362 73f37c7a386094cfb79205529ef72ba1966509f4 (diff)
child 164377 266d6c937ebb42bae048bebd6cd49d565147f335
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone27.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
Merge m-c to inbound
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1113,16 +1113,17 @@ pref("devtools.debugger.enabled", true);
 pref("devtools.debugger.chrome-enabled", true);
 pref("devtools.debugger.chrome-debugging-host", "localhost");
 pref("devtools.debugger.chrome-debugging-port", 6080);
 pref("devtools.debugger.remote-host", "localhost");
 pref("devtools.debugger.remote-timeout", 20000);
 pref("devtools.debugger.pause-on-exceptions", false);
 pref("devtools.debugger.ignore-caught-exceptions", true);
 pref("devtools.debugger.source-maps-enabled", true);
+pref("devtools.debugger.pretty-print-enabled", true);
 
 // The default Debugger UI settings
 pref("devtools.debugger.ui.panes-sources-width", 200);
 pref("devtools.debugger.ui.panes-instruments-width", 300);
 pref("devtools.debugger.ui.panes-visible-on-startup", false);
 pref("devtools.debugger.ui.variables-sorting-enabled", true);
 pref("devtools.debugger.ui.variables-only-enum-visible", false);
 pref("devtools.debugger.ui.variables-searchbox-visible", false);
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -1851,16 +1851,17 @@ let Prefs = new ViewHelpers.Prefs("devto
   instrumentsWidth: ["Int", "debugger.ui.panes-instruments-width"],
   panesVisibleOnStartup: ["Bool", "debugger.ui.panes-visible-on-startup"],
   variablesSortingEnabled: ["Bool", "debugger.ui.variables-sorting-enabled"],
   variablesOnlyEnumVisible: ["Bool", "debugger.ui.variables-only-enum-visible"],
   variablesSearchboxVisible: ["Bool", "debugger.ui.variables-searchbox-visible"],
   pauseOnExceptions: ["Bool", "debugger.pause-on-exceptions"],
   ignoreCaughtExceptions: ["Bool", "debugger.ignore-caught-exceptions"],
   sourceMapsEnabled: ["Bool", "debugger.source-maps-enabled"],
+  prettyPrintEnabled: ["Bool", "debugger.pretty-print-enabled"],
   editorTabSize: ["Int", "editor.tabsize"]
 });
 
 /**
  * Returns true if this is a chrome debugger instance.
  * @return boolean
  */
 XPCOMUtils.defineLazyGetter(window, "_isChromeDebugger", function() {
--- a/browser/devtools/debugger/debugger-panes.js
+++ b/browser/devtools/debugger/debugger-panes.js
@@ -49,16 +49,20 @@ SourcesView.prototype = Heritage.extend(
     this._popupset = document.getElementById("debuggerPopupset");
     this._cmPopup = document.getElementById("sourceEditorContextMenu");
     this._cbPanel = document.getElementById("conditional-breakpoint-panel");
     this._cbTextbox = document.getElementById("conditional-breakpoint-panel-textbox");
     this._editorDeck = document.getElementById("editor-deck");
     this._stopBlackBoxButton = document.getElementById("black-boxed-message-button");
     this._prettyPrintButton = document.getElementById("pretty-print");
 
+    if (Prefs.prettyPrintEnabled) {
+      this._prettyPrintButton.removeAttribute("hidden");
+    }
+
     window.on(EVENTS.EDITOR_LOADED, this._onEditorLoad, false);
     window.on(EVENTS.EDITOR_UNLOADED, this._onEditorUnload, false);
     this.widget.addEventListener("select", this._onSourceSelect, false);
     this.widget.addEventListener("click", this._onSourceClick, false);
     this.widget.addEventListener("check", this._onSourceCheck, false);
     this._stopBlackBoxButton.addEventListener("click", this._onStopBlackBoxing, false);
     this._prettyPrintButton.addEventListener("click", this.prettyPrint, false);
     this._cbPanel.addEventListener("popupshowing", this._onConditionalPopupShowing, false);
--- a/browser/devtools/debugger/debugger.xul
+++ b/browser/devtools/debugger/debugger.xul
@@ -323,17 +323,18 @@
           <vbox id="sources-pane" flex="1">
             <vbox id="sources" flex="1"/>
           </vbox>
           <toolbar id="sources-toolbar" class="devtools-toolbar">
             <toolbarbutton id="pretty-print"
                            label="{}"
                            tooltiptext="&debuggerUI.sources.prettyPrint;"
                            class="devtools-toolbarbutton devtools-monospace"
-                           command="prettyPrintCommand"/>
+                           command="prettyPrintCommand"
+                           hidden="true"/>
           </toolbar>
         </vbox>
         <splitter class="devtools-side-splitter"/>
         <deck id="editor-deck" flex="1" selectedIndex="0">
           <vbox id="editor"/>
           <vbox id="black-boxed-message" align="center">
             <label id="black-boxed-message-label">
               &debuggerUI.blackBoxMessage.label;
--- a/toolkit/devtools/server/actors/script.js
+++ b/toolkit/devtools/server/actors/script.js
@@ -462,16 +462,23 @@ ThreadActor.prototype = {
   get sources() {
     if (!this._sources) {
       this._sources = new ThreadSources(this, this._options.useSourceMaps,
                                         this._allowSource, this.onNewSource);
     }
     return this._sources;
   },
 
+  get youngestFrame() {
+    if (!this.state == "paused") {
+      return null;
+    }
+    return this.dbg.getNewestFrame();
+  },
+
   _prettyPrintWorker: null,
   get prettyPrintWorker() {
     if (!this._prettyPrintWorker) {
       this._prettyPrintWorker = new ChromeWorker(
         "resource://gre/modules/devtools/server/actors/pretty-print-worker.js");
 
       this._prettyPrintWorker.addEventListener(
         "error", this._onPrettyPrintError, false);
@@ -1174,20 +1181,16 @@ ThreadActor.prototype = {
                message: "Evaluation frame not found" };
     }
 
     if (!frame.environment) {
       return { error: "notDebuggee",
                message: "cannot access the environment of this frame." };
     }
 
-    // We'll clobber the youngest frame if the eval causes a pause, so
-    // save our frame now to be restored after eval returns.
-    // XXX: or we could just start using dbg.getNewestFrame() now that it
-    // works as expected.
     let youngest = this.youngestFrame;
 
     // Put ourselves back in the running state and inform the client.
     let resumedPacket = this._resumed();
     this.conn.send(resumedPacket);
 
     // Run the expression.
     // XXX: test syntax errors
@@ -1733,20 +1736,16 @@ ThreadActor.prototype = {
       for (let [,bp] of this._hiddenBreakpoints) {
         bp.onDelete();
       }
       this._hiddenBreakpoints.clear();
     }
 
     this._state = "paused";
 
-    // Save the pause frame (if any) as the youngest frame for
-    // stack viewing.
-    this.youngestFrame = aFrame;
-
     // Create the actor pool that will hold the pause actor and its
     // children.
     dbg_assert(!this._pausePool, "No pause pool should exist yet");
     this._pausePool = new ActorPool(this.conn);
     this.conn.addActorPool(this._pausePool);
 
     // Give children of the pause pool a quick link back to the
     // thread...
@@ -1778,17 +1777,16 @@ ThreadActor.prototype = {
   _resumed: function TA_resumed() {
     this._state = "running";
 
     // Drop the actors in the pause actor pool.
     this.conn.removeActorPool(this._pausePool);
 
     this._pausePool = null;
     this._pauseActor = null;
-    this.youngestFrame = null;
 
     return { from: this.actorID, type: "resumed" };
   },
 
   /**
    * Expire frame actors for frames that have been popped.
    *
    * @returns A list of actor IDs whose frames have been popped.
@@ -4019,17 +4017,17 @@ function getOffsetColumn(aOffset, aScrip
  * frame does not have a script, the location's properties are all null.
  *
  * @param Debugger.Frame aFrame
  *        The frame whose location we are getting.
  * @returns Object
  *          Returns an object of the form { url, line, column }
  */
 function getFrameLocation(aFrame) {
-  if (!aFrame.script) {
+  if (!aFrame || !aFrame.script) {
     return { url: null, line: null, column: null };
   }
   return {
     url: aFrame.script.url,
     line: aFrame.script.getOffsetLine(aFrame.offset),
     column: getOffsetColumn(aFrame.offset, aFrame.script)
   }
 }
--- a/toolkit/devtools/server/actors/tracer.js
+++ b/toolkit/devtools/server/actors/tracer.js
@@ -271,28 +271,38 @@ TraceActor.prototype = {
 
     this.conn.send(packet);
   },
 
   /**
    * Called by the engine when a frame is exited. Sends an unsolicited packet to
    * the client carrying requested trace information.
    *
-   * @param aValue object
+   * @param aCompletion object
    *        The debugger completion value for the frame.
    */
-  onExitFrame: function(aValue) {
+  onExitFrame: function(aCompletion) {
     let packet = {
       from: this.actorID,
       type: "exitedFrame",
-      sequence: this._sequence++
+      sequence: this._sequence++,
     };
 
+    if (!aCompletion) {
+      packet.why = "terminated";
+    } else if (aCompletion.hasOwnProperty("return")) {
+      packet.why = "return";
+    } else if (aCompletion.hasOwnProperty("yield")) {
+      packet.why = "yield";
+    } else {
+      packet.why = "throw";
+    }
+
     this._handleEvent(TraceTypes.Events.exitFrame, packet, {
-      value: aValue,
+      value: aCompletion,
       startTime: this._startTime
     });
 
     this.conn.send(packet);
   }
 };
 
 /**
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/server/tests/unit/test_trace_actor-07.js
@@ -0,0 +1,96 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests that the exit frame packets get the correct `why` value.
+ */
+
+let { defer } = devtools.require("sdk/core/promise");
+
+var gDebuggee;
+var gClient;
+var gTraceClient;
+
+function run_test()
+{
+  initTestTracerServer();
+  gDebuggee = addTestGlobal("test-tracer-actor");
+  gClient = new DebuggerClient(DebuggerServer.connectPipe());
+  gClient.connect(function() {
+    attachTestTab(gClient, "test-tracer-actor", function(aResponse, aTabClient) {
+      gClient.attachTracer(aResponse.traceActor, function(aResponse, aTraceClient) {
+        gTraceClient = aTraceClient;
+        test_exit_frame_whys();
+      });
+    });
+  });
+  do_test_pending();
+}
+
+function test_exit_frame_whys()
+{
+  gTraceClient.addListener("exitedFrame", check_packet);
+
+  start_trace()
+    .then(eval_code)
+    .then(stop_trace)
+    .then(function() {
+      finishClient(gClient);
+    }).then(null, error => {
+      do_check_true(false, "Should not get an error, got: " + error);
+    });
+}
+
+function start_trace()
+{
+  let deferred = defer();
+  gTraceClient.startTrace(["name"], null, function() { deferred.resolve(); });
+  return deferred.promise;
+}
+
+function eval_code()
+{
+  gDebuggee.eval("(" + function() {
+    function thrower() {
+      throw new Error();
+    }
+
+    function* yielder() {
+      yield 1;
+    }
+
+    function returner() {
+      return 1;
+    }
+
+    try {
+      thrower();
+    } catch(e) {}
+
+    // XXX bug 923729: Can't test yielding yet.
+    // for (let x of yielder()) {
+    //   break;
+    // }
+
+    returner();
+  } + ")()");
+}
+
+function stop_trace()
+{
+  let deferred = defer();
+  gTraceClient.stopTrace(null, function() { deferred.resolve(); });
+  return deferred.promise;
+}
+
+function check_packet(aEvent, { sequence, why })
+{
+  switch(sequence) {
+  case 3:
+    do_check_eq(why, "throw");
+    break;
+  case 5:
+    do_check_eq(why, "return");
+    break;
+  }
+}
--- a/toolkit/devtools/server/tests/unit/xpcshell.ini
+++ b/toolkit/devtools/server/tests/unit/xpcshell.ini
@@ -180,10 +180,11 @@ reason = bug 820380
 [test_unsafeDereference.js]
 [test_add_actors.js]
 [test_trace_actor-01.js]
 [test_trace_actor-02.js]
 [test_trace_actor-03.js]
 [test_trace_actor-04.js]
 [test_trace_actor-05.js]
 [test_trace_actor-06.js]
+[test_trace_actor-07.js]
 [test_ignore_caught_exceptions.js]
 [test_trace_client-01.js]