Bug 729576 - Update the remote debugging protocol to reflect the recent spec changes; r=dcamp,jimb
authorPanos Astithas <past@mozilla.com>
Tue, 13 Mar 2012 09:13:02 +0200
changeset 88814 cc44d26d718bfc5bf9c5cafe50aaeebdd70239d5
parent 88813 7c8fff2651f5988493826a6ec6b137aa528fbba8
child 88925 ee4e0c98cb02323c040f439eea81a98b217d3003
push id602
push userpastithas@mozilla.com
push dateTue, 13 Mar 2012 10:13:16 +0000
treeherderfx-team@cc44d26d718b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdcamp, jimb
bugs729576
milestone13.0a1
Bug 729576 - Update the remote debugging protocol to reflect the recent spec changes; r=dcamp,jimb
toolkit/devtools/debugger/server/dbg-script-actors.js
toolkit/devtools/debugger/tests/unit/test_eval-01.js
toolkit/devtools/debugger/tests/unit/test_eval-02.js
toolkit/devtools/debugger/tests/unit/test_eval-03.js
toolkit/devtools/debugger/tests/unit/test_eval-04.js
toolkit/devtools/debugger/tests/unit/test_framearguments-01.js
toolkit/devtools/debugger/tests/unit/test_functiongrips-01.js
toolkit/devtools/debugger/tests/unit/test_nativewrappers.js
toolkit/devtools/debugger/tests/unit/test_objectgrips-01.js
toolkit/devtools/debugger/tests/unit/test_objectgrips-02.js
toolkit/devtools/debugger/tests/unit/test_objectgrips-03.js
toolkit/devtools/debugger/tests/unit/test_objectgrips-04.js
toolkit/devtools/debugger/tests/unit/test_pauselifetime-01.js
toolkit/devtools/debugger/tests/unit/test_pauselifetime-02.js
toolkit/devtools/debugger/tests/unit/test_pauselifetime-03.js
toolkit/devtools/debugger/tests/unit/test_pauselifetime-04.js
toolkit/devtools/debugger/tests/unit/test_threadlifetime-01.js
toolkit/devtools/debugger/tests/unit/test_threadlifetime-02.js
toolkit/devtools/debugger/tests/unit/test_threadlifetime-03.js
--- a/toolkit/devtools/debugger/server/dbg-script-actors.js
+++ b/toolkit/devtools/debugger/server/dbg-script-actors.js
@@ -200,27 +200,30 @@ ThreadActor.prototype = {
   onResume: function TA_onResume(aRequest) {
     let packet = this._resumed();
     DebuggerServer.xpcInspector.exitNestedEventLoop();
     return packet;
   },
 
   onClientEvaluate: function TA_onClientEvaluate(aRequest) {
     if (this.state !== "paused") {
-      return { type: "wrongState",
+      return { error: "wrongState",
                message: "Debuggee must be paused to evaluate code." };
     };
 
     let frame = this._requestFrame(aRequest.frame);
     if (!frame) {
-      // XXXspec
-      return { type: "unknownFrame",
+      return { error: "unknownFrame",
                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.
@@ -228,28 +231,20 @@ ThreadActor.prototype = {
     this.conn.send(resumedPacket);
 
     // Run the expression.
     // XXX: test syntax errors
     let completion = frame.eval(aRequest.expression);
 
     // Put ourselves back in the pause state.
     let packet = this._paused(youngest);
-    packet.why = { type: "clientEvaluated" };
-    if ("return" in completion) {
-      packet.why.value = this.createValueGrip(completion["return"]);
-    } else if ("throw" in completion) {
-      packet.why.exception = this.createValueGrip(completion["throw"]);
-    } else {
-      // XXXspec
-      packet.why.terminated = true;
-    }
+    packet.why = { type: "clientEvaluated",
+                   frameFinished: this.createProtocolCompletionValue(completion) };
 
     // Return back to our previous pause's event loop.
-
     return packet;
   },
 
   onFrames: function TA_onFrames(aRequest) {
     if (this.state !== "paused") {
       return { error: "wrongState",
                message: "Stack frames are only available while the debuggee is paused."};
     }
@@ -264,26 +259,31 @@ ThreadActor.prototype = {
       frame = frame.older;
       i++;
     }
 
     // Return request.count frames, or all remaining
     // frames if count is not defined.
     let frames = [];
     for (; frame && (!count || i < (start + count)); i++) {
-      let grip = this._createFrameActor(frame).grip();
-      grip.depth = i;
-      frames.push(grip);
+      let form = this._createFrameActor(frame).form();
+      form.depth = i;
+      frames.push(form);
       frame = frame.older;
     }
 
     return { frames: frames };
   },
 
   onReleaseMany: function TA_onReleaseMany(aRequest) {
+    if (!aRequest.actors) {
+      return { error: "missingParameter",
+               message: "no actors were specified" };
+    }
+
     for each (let actorID in aRequest.actors) {
       let actor = this.threadLifetimePool.get(actorID);
       this.threadLifetimePool.objectActors.delete(actor.obj);
       this.threadLifetimePool.removeActor(actorID);
     }
     return {};
   },
 
@@ -444,34 +444,31 @@ ThreadActor.prototype = {
       return { error: "notInterrupted", message: e.toString() };
     }
   },
 
   /**
    * Return the Debug.Frame for a frame mentioned by the protocol.
    */
   _requestFrame: function TA_requestFrame(aFrameID) {
-    // XXXspec: doesn't actually specify how frames are named.  By
-    // depth?  By actor?  Both?
     if (!aFrameID) {
       return this._youngestFrame;
     }
 
     if (this._framePool.has(aFrameID)) {
       return this._framePool.get(aFrameID).frame;
     }
 
     return undefined;
   },
 
   _paused: function TA_paused(aFrame) {
-    // XXX: We don't handle nested pauses correctly.  Don't try - if we're
+    // We don't handle nested pauses correctly.  Don't try - if we're
     // paused, just continue running whatever code triggered the pause.
-
-    // We don't want to actually have nested pauses (although we will
+    // We don't want to actually have nested pauses (although we
     // have nested event loops).  If code runs in the debuggee during
     // a pause, it should cause the actor to resume (dropping
     // pause-lifetime actors etc) and then repause when complete.
 
     if (this.state === "paused") {
       return undefined;
     }
 
@@ -499,17 +496,17 @@ ThreadActor.prototype = {
     // Update the list of frames.
     let poppedFrames = this._updateFrames();
 
     // Send off the paused packet and spin an event loop.
     let packet = { from: this.actorID,
                    type: "paused",
                    actor: this._pauseActor.actorID };
     if (aFrame) {
-      packet.frame = this._createFrameActor(aFrame).grip();
+      packet.frame = this._createFrameActor(aFrame).form();
     }
 
     if (poppedFrames) {
       packet.poppedFrames = poppedFrames;
     }
 
     return packet;
   },
@@ -593,23 +590,21 @@ ThreadActor.prototype = {
 
   /**
    * Create and return an environment actor that corresponds to the
    * Debugger.Environment for the provided object.
    * @param Debugger.Object aObject
    *        The object whose lexical environment we want to extract.
    * @param object aPool
    *        The pool where the newly-created actor will be placed.
-   * @return The EnvironmentActor for aObject.
+   * @return The EnvironmentActor for aObject or undefined for host functions or
+   *         functions scoped to a non-debuggee global.
    */
   createEnvironmentActor: function TA_createEnvironmentActor(aObject, aPool) {
     let environment = aObject.environment;
-    // XXX: need to spec this: when the object is a function proxy or not a
-    // function implemented in JavaScript, we don't return a scope property at
-    // all.
     if (!environment) {
       return undefined;
     }
 
     if (environment.actor) {
       return environment.actor;
     }
 
@@ -643,16 +638,35 @@ ThreadActor.prototype = {
       return this.pauseObjectGrip(aValue);
     }
 
     dbg_assert(false, "Failed to provide a grip for: " + aValue);
     return null;
   },
 
   /**
+   * Return a protocol completion value representing the given
+   * Debugger-provided completion value.
+   */
+  createProtocolCompletionValue:
+  function TA_createProtocolCompletionValue(aCompletion) {
+    let protoValue = {};
+    if ("return" in aCompletion) {
+      protoValue.return = this.createValueGrip(aCompletion.return);
+    } else if ("yield" in aCompletion) {
+      protoValue.return = this.createValueGrip(aCompletion.yield);
+    } else if ("throw" in aCompletion) {
+      protoValue.throw = this.createValueGrip(aCompletion.throw);
+    } else {
+      protoValue.terminated = true;
+    }
+    return protoValue;
+  },
+
+  /**
    * Create a grip for the given debuggee object.
    *
    * @param aValue Debugger.Object
    *        The debuggee object value.
    * @param aPool ActorPool
    *        The actor pool where the new object actor will be added.
    */
   objectGrip: function TA_objectGrip(aValue, aPool) {
@@ -741,19 +755,17 @@ ThreadActor.prototype = {
    *
    * @param aScript Debugger.Script
    *        The source script that has been loaded into a debuggee compartment.
    * @param aFunction Debugger.Object
    *        The function object that the ew code is part of.
    */
   onNewScript: function TA_onNewScript(aScript, aFunction) {
     // Use a sparse array for storing the scripts for each URL in order to
-    // optimize retrieval. XXX: in case this is not fast enough for very large
-    // files with too many scripts, we could sort the hash of script locations
-    // or use a trie.
+    // optimize retrieval.
     if (!this._scripts[aScript.url]) {
       this._scripts[aScript.url] = [];
     }
     this._scripts[aScript.url][aScript.startLine] = aScript;
     // Notify the client.
     this.conn.send({ from: this.actorID, type: "newScript",
                      url: aScript.url, startLine: aScript.startLine });
   }
@@ -814,17 +826,17 @@ ObjectActor.prototype = {
     message: "Object actors can only be accessed while the thread is paused."
   },
 
   /**
    * Returns a grip for this actor for returning in a protocol message.
    */
   grip: function OA_grip() {
     return { "type": "object",
-             "class": this.obj["class"],
+             "class": this.obj.class,
              "actor": this.actorID };
   },
 
   /**
    * Releases this actor from the pool.
    */
   release: function OA_release() {
     this.registeredPool.objectActors.delete(this.obj);
@@ -897,19 +909,18 @@ ObjectActor.prototype = {
    *
    * @param aRequest object
    *        The protocol request object.
    */
   onProperty: function OA_onProperty(aRequest) {
     if (this.threadActor.state !== "paused") {
       return this.WRONG_STATE_RESPONSE;
     }
-    // XXX: spec this.
     if (!aRequest.name) {
-      return { error: "noPropertyName",
+      return { error: "missingParameter",
                message: "no property name was specified" };
     }
 
     let desc = this.obj.getOwnPropertyDescriptor(aRequest.name);
     return { from: this.actorID,
              descriptor: this._propertyDescriptor(desc) };
   },
 
@@ -940,19 +951,18 @@ ObjectActor.prototype = {
    * @param aRequest object
    *        The protocol request object.
    */
   onDecompile: function OA_onDecompile(aRequest) {
     if (this.threadActor.state !== "paused") {
       return this.WRONG_STATE_RESPONSE;
     }
 
-    if (this.obj["class"] !== "Function") {
-      // XXXspec: Error type for this.
-      return { error: "unrecognizedPacketType",
+    if (this.obj.class !== "Function") {
+      return { error: "objectNotFunction",
                message: "decompile request is only valid for object grips " +
                         "with a 'Function' class." };
     }
 
     return { from: this.actorID,
              decompiledCode: this.obj.decompile(!!aRequest.pretty) };
   },
 
@@ -962,45 +972,48 @@ ObjectActor.prototype = {
    * @param aRequest object
    *        The protocol request object.
    */
   onScope: function OA_onScope(aRequest) {
     if (this.threadActor.state !== "paused") {
       return this.WRONG_STATE_RESPONSE;
     }
 
-    if (this.obj["class"] !== "Function") {
-      // XXXspec: Error type for this.
-      return { error: "unrecognizedPacketType",
+    if (this.obj.class !== "Function") {
+      return { error: "objectNotFunction",
                message: "scope request is only valid for object grips with a" +
                         " 'Function' class." };
     }
 
-    let packet = { name: this.obj.name || null };
-    let envActor = this.threadActor.createEnvironmentActor(this.obj, this.registeredPool);
-    packet.scope = envActor ? envActor.grip() : envActor;
+    let envActor = this.threadActor.createEnvironmentActor(this.obj,
+                                                           this.registeredPool);
+    if (!envActor) {
+      return { error: "notDebuggee",
+               message: "cannot access the environment of this function." };
+    }
 
-    return packet;
+    return { name: this.obj.name || null,
+             scope: envActor.form() };
   },
 
   /**
    * Handle a protocol request to provide the name and parameters of a function.
    *
    * @param aRequest object
    *        The protocol request object.
    */
   onNameAndParameters: function OA_onNameAndParameters(aRequest) {
     if (this.threadActor.state !== "paused") {
       return this.WRONG_STATE_RESPONSE;
     }
 
-    if (this.obj["class"] !== "Function") {
-      // XXXspec: Error type for this.
-      return { error: "unrecognizedPacketType",
-               message: "nameAndParameters request is only valid for object grips with a 'Function' class." };
+    if (this.obj.class !== "Function") {
+      return { error: "objectNotFunction",
+               message: "nameAndParameters request is only valid for object " +
+                        "grips with a 'Function' class." };
     }
 
     return { name: this.obj.name || null,
              parameters: this.obj.parameterNames };
   },
 
   /**
    * Handle a protocol request to promote a pause-lifetime grip to a
@@ -1023,19 +1036,18 @@ ObjectActor.prototype = {
    * @param aRequest object
    *        The protocol request object.
    */
   onRelease: function OA_onRelease(aRequest) {
     if (this.threadActor.state !== "paused") {
       return this.WRONG_STATE_RESPONSE;
     }
     if (this.registeredPool !== this.threadActor.threadLifetimePool) {
-      // XXXspec: error type?
-      return { error: "unrecognizedPacketType",
-               message: "release is only recognized on thread-lifetime actors." };
+      return { error: "notReleasable",
+               message: "only thread-lifetime actors can be released." };
     }
 
     this.release();
     return {};
   },
 };
 
 ObjectActor.prototype.requestTypes = {
@@ -1085,58 +1097,58 @@ FrameActor.prototype = {
    * the pool.
    */
   disconnect: function FA_disconnect() {
     this.conn.removeActorPool(this._frameLifetimePool);
     this._frameLifetimePool = null;
   },
 
   /**
-   * Returns a grip for this actor for returning in a protocol message.
+   * Returns a frame form for use in a protocol message.
    */
-  grip: function FA_grip() {
-    let grip = { actor: this.actorID,
+  form: function FA_form() {
+    let form = { actor: this.actorID,
                  type: this.frame.type };
     if (this.frame.type === "call") {
-      grip.callee = this.threadActor.createValueGrip(this.frame.callee);
+      form.callee = this.threadActor.createValueGrip(this.frame.callee);
       if (this.frame.callee.name) {
-        grip.calleeName = this.frame.callee.name;
+        form.calleeName = this.frame.callee.name;
       } else {
         let desc = this.frame.callee.getOwnPropertyDescriptor("displayName");
         if (desc && desc.value && typeof desc.value == "string") {
-          grip.calleeName = desc.value;
+          form.calleeName = desc.value;
         }
       }
     }
 
     let envActor = this.threadActor
                        .createEnvironmentActor(this.frame,
                                                this.frameLifetimePool);
-    grip.environment = envActor ? envActor.grip() : envActor;
-    grip["this"] = this.threadActor.createValueGrip(this.frame["this"]);
-    grip.arguments = this._args();
+    form.environment = envActor ? envActor.form() : envActor;
+    form.this = this.threadActor.createValueGrip(this.frame.this);
+    form.arguments = this._args();
     if (this.frame.script) {
-      grip.where = { url: this.frame.script.url,
+      form.where = { url: this.frame.script.url,
                      line: this.frame.script.getOffsetLine(this.frame.offset) };
     }
 
     if (!this.frame.older) {
-      grip.oldest = true;
+      form.oldest = true;
     }
 
-    return grip;
+    return form;
   },
 
   _args: function FA__args() {
-    if (!this.frame["arguments"]) {
+    if (!this.frame.arguments) {
       return [];
     }
 
     return [this.threadActor.createValueGrip(arg)
-            for each (arg in this.frame["arguments"])];
+            for each (arg in this.frame.arguments)];
   },
 
   /**
    * Handle a protocol request to pop this frame from the stack.
    *
    * @param aRequest object
    *        The protocol request object.
    */
@@ -1227,72 +1239,106 @@ function EnvironmentActor(aObject, aThre
   this.obj = aObject;
   this.threadActor = aThreadActor;
 }
 
 EnvironmentActor.prototype = {
   actorPrefix: "environment",
 
   /**
-   * Returns a grip for this actor for returning in a protocol message.
+   * Returns an environment form for use in a protocol message.
    */
-  grip: function EA_grip() {
+  form: function EA_form() {
     // Debugger.Frame might be dead by the time we get here, which will cause
     // accessing its properties to throw.
     if (!this.obj.live) {
       return undefined;
     }
 
     let parent;
     if (this.obj.environment.parent) {
       parent = this.threadActor
                    .createEnvironmentActor(this.obj.environment.parent,
                                            this.registeredPool);
     }
-    let grip = { actor: this.actorID,
-                 parent: parent ? parent.grip() : parent };
+    let form = { actor: this.actorID,
+                 parent: parent ? parent.form() : parent };
 
     if (this.obj.environment.type == "object") {
-      grip.type = "object"; // XXX: how can we tell if it's "with"?
-      grip.object = this.threadActor.createValueGrip(this.obj.environment.object);
+      if (this.obj.environment.parent) {
+        form.type = "with";
+      } else {
+        form.type = "object";
+      }
+      form.object = this.threadActor.createValueGrip(this.obj.environment.object);
     } else {
-      if (this.obj["class"] == "Function") {
-        grip.type = "function";
-        grip["function"] = this.threadActor.createValueGrip(this.obj);
-        grip.functionName = this.obj.name;
+      if (this.obj.class == "Function") {
+        form.type = "function";
+        form.function = this.threadActor.createValueGrip(this.obj);
+        form.functionName = this.obj.name;
       } else {
-        grip.type = "block";
+        form.type = "block";
       }
 
-      grip.bindings = this._bindings();
+      form.bindings = this._bindings();
     }
 
-    return grip;
+    return form;
   },
 
   /**
    * Return the identifier bindings object as required by the remote protocol
    * specification.
    */
   _bindings: function EA_bindings() {
-    let bindings = { mutable: {}, immutable: {} };
+    let bindings = { arguments: [], variables: {} };
 
     // TODO: this will be redundant after bug 692984 is fixed.
     if (typeof this.obj.environment.getVariableDescriptor != "function") {
       return bindings;
     }
 
-    for (let name in this.obj.environment.names()) {
+    for (let name in this.obj.parameterNames) {
+      let arg = {};
       let desc = this.obj.environment.getVariableDescriptor(name);
-      // XXX: the spec doesn't say what to do with accessor properties.
-      if (desc.writable) {
-        grip.bindings.mutable[name] = desc.value;
+      let descForm = {
+        enumerable: true,
+        configurable: desc.configurable
+      };
+      if ("value" in desc) {
+        descForm.value = this.threadActor.createValueGrip(desc.value);
+        descForm.writable = desc.writable;
       } else {
-        grip.bindings.immutable[name] = desc.value;
+        descForm.get = this.threadActor.createValueGrip(desc.get);
+        descForm.set = this.threadActor.createValueGrip(desc.set);
+      }
+      arg[name] = descForm;
+      bindings.arguments.push(arg);
+    }
+
+    for (let name in this.obj.environment.names()) {
+      if (bindings.arguments.some(function exists(element) {
+                                    return !!element[name];
+                                  })) {
+        continue;
       }
+
+      let desc = this.obj.environment.getVariableDescriptor(name);
+      let descForm = {
+        enumerable: true,
+        configurable: desc.configurable
+      };
+      if ("value" in desc) {
+        descForm.value = this.threadActor.createValueGrip(desc.value);
+        descForm.writable = desc.writable;
+      } else {
+        descForm.get = this.threadActor.createValueGrip(desc.get);
+        descForm.set = this.threadActor.createValueGrip(desc.set);
+      }
+      bindings.variables[name] = descForm;
     }
 
     return bindings;
   },
 
   /**
    * Handle a protocol request to change the value of a variable bound in this
    * lexical environment.
@@ -1308,19 +1354,19 @@ EnvironmentActor.prototype = {
                message: "Changing the value of an immutable binding is not " +
                         "allowed" };
     }
 
     try {
       this.obj.environment.setVariable(aRequest.name, aRequest.value);
     } catch (e) {
       if (e instanceof Debugger.DebuggeeWouldRun) {
-        // XXX: we need to spec this. Is this a real problem?
-        return { error: "debuggeeWouldRun",
-                 message: "Assigning this value would cause the debuggee to run." };
+        return { error: "threadWouldRun",
+                 cause: e.cause ? e.cause : "setter",
+                 message: "Assigning a value would cause the debuggee to run" };
       }
       // This should never happen, so let it complain loudly if it does.
       throw e;
     }
     return { from: this.actorID };
   },
 
   /**
--- a/toolkit/devtools/debugger/tests/unit/test_eval-01.js
+++ b/toolkit/devtools/debugger/tests/unit/test_eval-01.js
@@ -21,26 +21,26 @@ function run_test()
     });
   });
   do_test_pending();
 }
 
 function test_simple_eval()
 {
   gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
-    let arg1Actor = aPacket.frame["arguments"][0].actor;
+    let arg1Actor = aPacket.frame.arguments[0].actor;
     gThreadClient.eval(null, "({ obj: true })", function(aResponse) {
       do_check_eq(aResponse.type, "resumed");
       // Expect a pause notification immediately.
       gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
         // Check the return value...
         do_check_eq(aPacket.type, "paused");
         do_check_eq(aPacket.why.type, "clientEvaluated");
-        do_check_eq(aPacket.why.value.type, "object");
-        do_check_eq(aPacket.why.value["class"], "Object");
+        do_check_eq(aPacket.why.frameFinished.return.type, "object");
+        do_check_eq(aPacket.why.frameFinished.return.class, "Object");
 
         // Make sure the previous pause lifetime was correctly dropped.
         gClient.request({ to: arg1Actor, type: "bogusRequest" }, function(aResponse) {
           do_check_eq(aResponse.error, "noSuchActor");
           gThreadClient.resume(function() {
             finishClient(gClient);
           });
         });
--- a/toolkit/devtools/debugger/tests/unit/test_eval-02.js
+++ b/toolkit/devtools/debugger/tests/unit/test_eval-02.js
@@ -28,17 +28,17 @@ function test_throw_eval()
   gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
     gThreadClient.eval(null, "throw 'failure'", function(aResponse) {
       do_check_eq(aResponse.type, "resumed");
       // Expect a pause notification immediately.
       gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
         // Check the return value...
         do_check_eq(aPacket.type, "paused");
         do_check_eq(aPacket.why.type, "clientEvaluated");
-        do_check_eq(aPacket.why.exception, "failure");
+        do_check_eq(aPacket.why.frameFinished.throw, "failure");
         gThreadClient.resume(function() {
           finishClient(gClient);
         });
       });
     });
   });
 
   gDebuggee.eval("(" + function() {
--- a/toolkit/devtools/debugger/tests/unit/test_eval-03.js
+++ b/toolkit/devtools/debugger/tests/unit/test_eval-03.js
@@ -28,18 +28,18 @@ function test_syntax_error_eval()
   gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
     gThreadClient.eval(null, "%$@!@#", function(aResponse) {
       do_check_eq(aResponse.type, "resumed");
       // Expect a pause notification immediately.
       gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
         // Check the return value...
         do_check_eq(aPacket.type, "paused");
         do_check_eq(aPacket.why.type, "clientEvaluated");
-        do_check_eq(aPacket.why.exception.type, "object");
-        do_check_eq(aPacket.why.exception["class"], "Error");
+        do_check_eq(aPacket.why.frameFinished.throw.type, "object");
+        do_check_eq(aPacket.why.frameFinished.throw.class, "Error");
 
         gThreadClient.resume(function() {
           finishClient(gClient);
         });
       });
     });
   });
 
--- a/toolkit/devtools/debugger/tests/unit/test_eval-04.js
+++ b/toolkit/devtools/debugger/tests/unit/test_eval-04.js
@@ -33,24 +33,24 @@ function test_syntax_error_eval()
 
       // Eval against the top frame...
       gThreadClient.eval(frame0.actor, "arg", function(aResponse) {
         do_check_eq(aResponse.type, "resumed");
         gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
           // 'arg' should have been evaluated in frame0
           do_check_eq(aPacket.type, "paused");
           do_check_eq(aPacket.why.type, "clientEvaluated");
-          do_check_eq(aPacket.why.value, "arg0");
+          do_check_eq(aPacket.why.frameFinished.return, "arg0");
 
           // Now eval against the second frame.
           gThreadClient.eval(frame1.actor, "arg", function(aResponse) {
             gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
               // 'arg' should have been evaluated in frame1
               do_check_eq(aPacket.type, "paused");
-              do_check_eq(aPacket.why.value, "arg1");
+              do_check_eq(aPacket.why.frameFinished.return, "arg1");
 
               gThreadClient.resume(function() {
                 finishClient(gClient);
               });
             });
           });
         });
       });
--- a/toolkit/devtools/debugger/tests/unit/test_framearguments-01.js
+++ b/toolkit/devtools/debugger/tests/unit/test_framearguments-01.js
@@ -29,17 +29,17 @@ function test_pause_frame()
     let args = aPacket.frame["arguments"];
     do_check_eq(args.length, 6);
     do_check_eq(args[0], 42);
     do_check_eq(args[1], true);
     do_check_eq(args[2], "nasu");
     do_check_eq(args[3].type, "null");
     do_check_eq(args[4].type, "undefined");
     do_check_eq(args[5].type, "object");
-    do_check_eq(args[5]["class"], "Object");
+    do_check_eq(args[5].class, "Object");
     do_check_true(!!args[5].actor);
 
     gThreadClient.resume(function() {
       finishClient(gClient);
     });
   });
 
   gDebuggee.eval("(" + function() {
--- a/toolkit/devtools/debugger/tests/unit/test_functiongrips-01.js
+++ b/toolkit/devtools/debugger/tests/unit/test_functiongrips-01.js
@@ -21,19 +21,19 @@ function run_test()
     });
   });
   do_test_pending();
 }
 
 function test_named_function()
 {
   gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
-    let args = aPacket.frame["arguments"];
+    let args = aPacket.frame.arguments;
 
-    do_check_eq(args[0]["class"], "Function");
+    do_check_eq(args[0].class, "Function");
     // No name for an anonymous function.
 
     let objClient = gThreadClient.pauseGrip(args[0]);
     objClient.getSignature(function(aResponse) {
       do_check_eq(aResponse.name, "stopMe");
       do_check_eq(aResponse.parameters.length, 1);
       do_check_eq(aResponse.parameters[0], "arg1");
 
@@ -44,19 +44,19 @@ function test_named_function()
 
   });
 
   gDebuggee.eval("stopMe(stopMe)");
 }
 
 function test_anon_function() {
   gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
-    let args = aPacket.frame["arguments"];
+    let args = aPacket.frame.arguments;
 
-    do_check_eq(args[0]["class"], "Function");
+    do_check_eq(args[0].class, "Function");
     // No name for an anonymous function.
 
     let objClient = gThreadClient.pauseGrip(args[0]);
     objClient.getSignature(function(aResponse) {
       do_check_eq(aResponse.name, null);
       do_check_eq(aResponse.parameters.length, 3);
       do_check_eq(aResponse.parameters[0], "foo");
       do_check_eq(aResponse.parameters[1], "bar");
--- a/toolkit/devtools/debugger/tests/unit/test_nativewrappers.js
+++ b/toolkit/devtools/debugger/tests/unit/test_nativewrappers.js
@@ -1,17 +1,17 @@
 function run_test()
 {
   Components.utils.import("resource://gre/modules/jsdebugger.jsm");
   var g = testGlobal("test1");
 
   var dbg = new Debugger();
   dbg.addDebuggee(g);
   dbg.onDebuggerStatement = function(aFrame) {
-    let args = aFrame["arguments"];
+    let args = aFrame.arguments;
     try {
       args[0];
       do_check_true(true);
     } catch(ex) {
       do_check_true(false);
     }
   };
 
--- a/toolkit/devtools/debugger/tests/unit/test_objectgrips-01.js
+++ b/toolkit/devtools/debugger/tests/unit/test_objectgrips-01.js
@@ -21,19 +21,19 @@ function run_test()
     });
   });
   do_test_pending();
 }
 
 function test_object_grip()
 {
   gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
-    let args = aPacket.frame["arguments"];
+    let args = aPacket.frame.arguments;
 
-    do_check_eq(args[0]["class"], "Object");
+    do_check_eq(args[0].class, "Object");
 
     let objClient = gThreadClient.pauseGrip(args[0]);
     objClient.getOwnPropertyNames(function(aResponse) {
       do_check_eq(aResponse.ownPropertyNames.length, 3);
       do_check_eq(aResponse.ownPropertyNames[0], "a");
       do_check_eq(aResponse.ownPropertyNames[1], "b");
       do_check_eq(aResponse.ownPropertyNames[2], "c");
 
--- a/toolkit/devtools/debugger/tests/unit/test_objectgrips-02.js
+++ b/toolkit/devtools/debugger/tests/unit/test_objectgrips-02.js
@@ -21,19 +21,19 @@ function run_test()
     });
   });
   do_test_pending();
 }
 
 function test_object_grip()
 {
   gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
-    let args = aPacket.frame["arguments"];
+    let args = aPacket.frame.arguments;
 
-    do_check_eq(args[0]["class"], "Object");
+    do_check_eq(args[0].class, "Object");
 
     let objClient = gThreadClient.pauseGrip(args[0]);
     objClient.getPrototype(function(aResponse) {
       do_check_true(aResponse.prototype != undefined);
 
       let protoClient = gThreadClient.pauseGrip(aResponse.prototype);
       protoClient.getOwnPropertyNames(function(aResponse) {
         do_check_eq(aResponse.ownPropertyNames.length, 2);
--- a/toolkit/devtools/debugger/tests/unit/test_objectgrips-03.js
+++ b/toolkit/devtools/debugger/tests/unit/test_objectgrips-03.js
@@ -21,19 +21,19 @@ function run_test()
     });
   });
   do_test_pending();
 }
 
 function test_object_grip()
 {
   gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
-    let args = aPacket.frame["arguments"];
+    let args = aPacket.frame.arguments;
 
-    do_check_eq(args[0]["class"], "Object");
+    do_check_eq(args[0].class, "Object");
 
     let objClient = gThreadClient.pauseGrip(args[0]);
     objClient.getProperty("x", function(aResponse) {
       do_check_eq(aResponse.descriptor.configurable, true);
       do_check_eq(aResponse.descriptor.enumerable, true);
       do_check_eq(aResponse.descriptor.writable, true);
       do_check_eq(aResponse.descriptor.value, 10);
 
--- a/toolkit/devtools/debugger/tests/unit/test_objectgrips-04.js
+++ b/toolkit/devtools/debugger/tests/unit/test_objectgrips-04.js
@@ -21,19 +21,19 @@ function run_test()
     });
   });
   do_test_pending();
 }
 
 function test_object_grip()
 {
   gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
-    let args = aPacket.frame["arguments"];
+    let args = aPacket.frame.arguments;
 
-    do_check_eq(args[0]["class"], "Object");
+    do_check_eq(args[0].class, "Object");
 
     let objClient = gThreadClient.pauseGrip(args[0]);
     objClient.getPrototypeAndProperties(function(aResponse) {
       do_check_eq(aResponse.ownProperties.x.configurable, true);
       do_check_eq(aResponse.ownProperties.x.enumerable, true);
       do_check_eq(aResponse.ownProperties.x.writable, true);
       do_check_eq(aResponse.ownProperties.x.value, 10);
 
--- a/toolkit/devtools/debugger/tests/unit/test_pauselifetime-01.js
+++ b/toolkit/devtools/debugger/tests/unit/test_pauselifetime-01.js
@@ -21,17 +21,17 @@ function run_test()
     });
   });
   do_test_pending();
 }
 
 function test_pause_frame()
 {
   gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
-    let pauseActor = aPacket["actor"];
+    let pauseActor = aPacket.actor;
 
     // Make a bogus request to the pause-liftime actor.  Should get
     // unrecognized-packet-type (and not no-such-actor).
     gClient.request({ to: pauseActor, type: "bogusRequest" }, function(aResponse) {
       do_check_eq(aResponse.error, "unrecognizedPacketType");
 
       gThreadClient.resume(function() {
         // Now that we've resumed, should get no-such-actor for the
--- a/toolkit/devtools/debugger/tests/unit/test_pauselifetime-02.js
+++ b/toolkit/devtools/debugger/tests/unit/test_pauselifetime-02.js
@@ -21,19 +21,19 @@ function run_test()
     });
   });
   do_test_pending();
 }
 
 function test_pause_frame()
 {
   gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
-    let args = aPacket.frame["arguments"];
+    let args = aPacket.frame.arguments;
     let objActor = args[0].actor;
-    do_check_eq(args[0]["class"], "Object");
+    do_check_eq(args[0].class, "Object");
     do_check_true(!!objActor);
 
     // Make a bogus request to the grip actor.  Should get
     // unrecognized-packet-type (and not no-such-actor).
     gClient.request({ to: objActor, type: "bogusRequest" }, function(aResponse) {
       do_check_eq(aResponse.error, "unrecognizedPacketType");
 
       gThreadClient.resume(function() {
--- a/toolkit/devtools/debugger/tests/unit/test_pauselifetime-03.js
+++ b/toolkit/devtools/debugger/tests/unit/test_pauselifetime-03.js
@@ -21,19 +21,19 @@ function run_test()
     });
   });
   do_test_pending();
 }
 
 function test_pause_frame()
 {
   gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
-    let args = aPacket.frame["arguments"];
+    let args = aPacket.frame.arguments;
     let objActor = args[0].actor;
-    do_check_eq(args[0]["class"], "Object");
+    do_check_eq(args[0].class, "Object");
     do_check_true(!!objActor);
 
     let objClient = gThreadClient.pauseGrip(args[0]);
     do_check_true(objClient.valid);
 
     // Make a bogus request to the grip actor.  Should get
     // unrecognized-packet-type (and not no-such-actor).
     gClient.request({ to: objActor, type: "bogusRequest" }, function(aResponse) {
--- a/toolkit/devtools/debugger/tests/unit/test_pauselifetime-04.js
+++ b/toolkit/devtools/debugger/tests/unit/test_pauselifetime-04.js
@@ -22,17 +22,17 @@ function run_test()
     });
   });
   do_test_pending();
 }
 
 function test_pause_frame()
 {
   gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
-    let args = aPacket.frame["arguments"];
+    let args = aPacket.frame.arguments;
     let objActor1 = args[0].actor;
 
     gThreadClient.getFrames(0, 1, function(aResponse) {
       let frame = aResponse.frames[0];
       do_check_eq(objActor1, frame.arguments[0].actor);
       gThreadClient.resume(function () {
         finishClient(gClient);
       });
--- a/toolkit/devtools/debugger/tests/unit/test_threadlifetime-01.js
+++ b/toolkit/devtools/debugger/tests/unit/test_threadlifetime-01.js
@@ -21,17 +21,17 @@ function run_test()
     });
   });
   do_test_pending();
 }
 
 function test_thread_lifetime()
 {
   gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
-    let pauseGrip = aPacket.frame["arguments"][0];
+    let pauseGrip = aPacket.frame.arguments[0];
 
     gClient.request({ to: pauseGrip.actor, type: "threadGrip" }, function(aResponse) {
       let threadGrip = aResponse.threadGrip;
 
       do_check_neq(pauseGrip.actor, threadGrip.actor);
 
       // Create a thread-lifetime actor for this object.
 
--- a/toolkit/devtools/debugger/tests/unit/test_threadlifetime-02.js
+++ b/toolkit/devtools/debugger/tests/unit/test_threadlifetime-02.js
@@ -21,17 +21,17 @@ function run_test()
     });
   });
   do_test_pending();
 }
 
 function test_thread_lifetime()
 {
   gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
-    let pauseGrip = aPacket.frame["arguments"][0];
+    let pauseGrip = aPacket.frame.arguments[0];
 
     gClient.request({ to: pauseGrip.actor, type: "threadGrip" }, function(aResponse) {
       let threadGrip = aResponse.threadGrip;
       // Create a thread-lifetime actor for this object.
       gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
         // Now that we've resumed, release the thread-lifetime grip.
         gClient.request({ to: threadGrip.actor, type: "release" }, function(aResponse) {
           gClient.request({ to: threadGrip.actor, type: "bogusRequest" }, function(aResponse) {
--- a/toolkit/devtools/debugger/tests/unit/test_threadlifetime-03.js
+++ b/toolkit/devtools/debugger/tests/unit/test_threadlifetime-03.js
@@ -22,27 +22,27 @@ function run_test()
   });
   do_test_pending();
 }
 
 function test_thread_lifetime()
 {
   // Get three thread-lifetime grips.
   gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
-    aPacket.frame["arguments"][0];
+    aPacket.frame.arguments[0];
     let grips = [];
 
     let handler = function(aResponse) {
       grips.push(aResponse.threadGrip);
       if (grips.length == 3) {
         test_release_many(grips);
       }
     };
     for (let i = 0; i < 3; i++) {
-      gClient.request({ to: aPacket.frame["arguments"][i].actor, type: "threadGrip" },
+      gClient.request({ to: aPacket.frame.arguments[i].actor, type: "threadGrip" },
                       handler);
     }
   });
 
   gDebuggee.eval("(" + function() {
     function stopMe(arg1, arg2, arg3) {
       debugger;
     };