diff --git a/toolkit/devtools/debugger/dbg-client.jsm b/toolkit/devtools/debugger/dbg-client.jsm index 271fb224554b..2ace75bf0fcc 100644 --- a/toolkit/devtools/debugger/dbg-client.jsm +++ b/toolkit/devtools/debugger/dbg-client.jsm @@ -807,6 +807,21 @@ ThreadClient.prototype = { this._client.request(packet, aOnResponse); }, + /** + * Promote multiple pause-lifetime object actors to thread-lifetime ones. + * + * @param array aActors + * An array with actor IDs to promote. + */ + threadGrips: function TC_threadGrips(aActors, aOnResponse) { + let packet = { + to: this._actor, + type: "threadGrips", + actors: aActors + }; + this._client.request(packet, aOnResponse); + }, + /** * Request the loaded scripts for the current thread. * diff --git a/toolkit/devtools/debugger/dbg-transport.js b/toolkit/devtools/debugger/dbg-transport.js index 713379a8b373..611917d5eab8 100644 --- a/toolkit/devtools/debugger/dbg-transport.js +++ b/toolkit/devtools/debugger/dbg-transport.js @@ -202,9 +202,9 @@ LocalDebuggerTransport.prototype = { */ send: function LDT_send(aPacket) { try { - // Avoid the cost of uneval() when logging is disabled. + // Avoid the cost of JSON.stringify() when logging is disabled. if (wantLogging) { - dumpn("Got: " + uneval(aPacket)); + dumpn("Got: " + JSON.stringify(aPacket, null, 2)); } this._deepFreeze(aPacket); let self = this; diff --git a/toolkit/devtools/debugger/server/dbg-script-actors.js b/toolkit/devtools/debugger/server/dbg-script-actors.js index 7bb31c50ae71..c471db3f78fc 100644 --- a/toolkit/devtools/debugger/server/dbg-script-actors.js +++ b/toolkit/devtools/debugger/server/dbg-script-actors.js @@ -57,6 +57,7 @@ ThreadActor.prototype = { if (!this._threadLifetimePool) { this._threadLifetimePool = new ActorPool(this.conn); this.conn.addActorPool(this._threadLifetimePool); + this._threadLifetimePool.objectActors = new WeakMap(); } return this._threadLifetimePool; }, @@ -909,6 +910,8 @@ ThreadActor.prototype = { if (aPool.objectActors.has(aValue)) { return aPool.objectActors.get(aValue).grip(); + } else if (this.threadLifetimePool.objectActors.has(aValue)) { + return this.threadLifetimePool.objectActors.get(aValue).grip(); } let actor = new ObjectActor(aValue, this); @@ -938,9 +941,6 @@ ThreadActor.prototype = { * The object actor. */ threadObjectGrip: function TA_threadObjectGrip(aActor) { - if (!this.threadLifetimePool.objectActors) { - this.threadLifetimePool.objectActors = new WeakMap(); - } // We want to reuse the existing actor ID, so we just remove it from the // current pool's weak map and then let pool.addActor do the rest. aActor.registeredPool.objectActors.delete(aActor.obj); @@ -948,6 +948,32 @@ ThreadActor.prototype = { this.threadLifetimePool.objectActors.set(aActor.obj, aActor); }, + /** + * Handle a protocol request to promote multiple pause-lifetime grips to + * thread-lifetime grips. + * + * @param aRequest object + * The protocol request object. + */ + onThreadGrips: function OA_onThreadGrips(aRequest) { + if (this.state != "paused") { + return { error: "wrongState" }; + } + + if (!aRequest.actors) { + return { error: "missingParameter", + message: "no actors were specified" }; + } + + for (let actorID of aRequest.actors) { + let actor = this._pausePool.get(actorID); + if (actor) { + this.threadObjectGrip(actor); + } + } + return {}; + }, + /** * Create a grip for the given string. * @@ -1165,7 +1191,8 @@ ThreadActor.prototype.requestTypes = { "interrupt": ThreadActor.prototype.onInterrupt, "releaseMany": ThreadActor.prototype.onReleaseMany, "setBreakpoint": ThreadActor.prototype.onSetBreakpoint, - "scripts": ThreadActor.prototype.onScripts + "scripts": ThreadActor.prototype.onScripts, + "threadGrips": ThreadActor.prototype.onThreadGrips }; diff --git a/toolkit/devtools/debugger/tests/unit/test_threadlifetime-01.js b/toolkit/devtools/debugger/tests/unit/test_threadlifetime-01.js index 7c9fe58fde17..a910cc3d0a98 100644 --- a/toolkit/devtools/debugger/tests/unit/test_threadlifetime-01.js +++ b/toolkit/devtools/debugger/tests/unit/test_threadlifetime-01.js @@ -33,6 +33,8 @@ function test_thread_lifetime() // Successful promotion won't return an error. do_check_eq(aResponse.error, undefined); gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) { + // Verify that the promoted actor is returned again. + do_check_eq(pauseGrip.actor, aPacket.frame.arguments[0].actor); // Now that we've resumed, should get unrecognizePacketType for the // promoted grip. gClient.request({ to: pauseGrip.actor, type: "bogusRequest"}, function(aResponse) { diff --git a/toolkit/devtools/debugger/tests/unit/test_threadlifetime-02.js b/toolkit/devtools/debugger/tests/unit/test_threadlifetime-02.js index ad122688e60e..04e9d2732281 100644 --- a/toolkit/devtools/debugger/tests/unit/test_threadlifetime-02.js +++ b/toolkit/devtools/debugger/tests/unit/test_threadlifetime-02.js @@ -33,6 +33,8 @@ function test_thread_lifetime() // Successful promotion won't return an error. do_check_eq(aResponse.error, undefined); gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) { + // Verify that the promoted actor is returned again. + do_check_eq(pauseGrip.actor, aPacket.frame.arguments[0].actor); // Now that we've resumed, release the thread-lifetime grip. gClient.release(pauseGrip.actor, function(aResponse) { gClient.request({ to: pauseGrip.actor, type: "bogusRequest" }, function(aResponse) { diff --git a/toolkit/devtools/debugger/tests/unit/test_threadlifetime-03.js b/toolkit/devtools/debugger/tests/unit/test_threadlifetime-03.js index 2e9a116700a0..635deb86bf82 100644 --- a/toolkit/devtools/debugger/tests/unit/test_threadlifetime-03.js +++ b/toolkit/devtools/debugger/tests/unit/test_threadlifetime-03.js @@ -27,7 +27,6 @@ function test_thread_lifetime() { // Get three thread-lifetime grips. gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) { - aPacket.frame.arguments[0]; let grips = []; let handler = function(aResponse) { diff --git a/toolkit/devtools/debugger/tests/unit/test_threadlifetime-06.js b/toolkit/devtools/debugger/tests/unit/test_threadlifetime-06.js new file mode 100644 index 000000000000..3ff8b98f5e91 --- /dev/null +++ b/toolkit/devtools/debugger/tests/unit/test_threadlifetime-06.js @@ -0,0 +1,72 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Check that promoting multiple pause-lifetime actors to thread-lifetime actors + * works as expected. + */ + +var gDebuggee; +var gClient; +var gThreadClient; + +function run_test() +{ + initTestDebuggerServer(); + gDebuggee = addTestGlobal("test-grips"); + gClient = new DebuggerClient(DebuggerServer.connectPipe()); + gClient.connect(function() { + attachTestGlobalClientAndResume(gClient, "test-grips", function(aResponse, aThreadClient) { + gThreadClient = aThreadClient; + test_thread_lifetime(); + }); + }); + do_test_pending(); +} + +function test_thread_lifetime() +{ + gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) { + let actors = []; + let last; + for (let aGrip of aPacket.frame.arguments) { + actors.push(aGrip.actor); + last = aGrip.actor; + } + + // Create thread-lifetime actors for these objects. + gThreadClient.threadGrips(actors, function(aResponse) { + // Successful promotion won't return an error. + do_check_eq(aResponse.error, undefined); + + gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) { + // Verify that the promoted actors are returned again. + actors.forEach(function(actor, i) { + do_check_eq(actor, aPacket.frame.arguments[i].actor); + }); + // Now that we've resumed, release the thread-lifetime grips. + gThreadClient.releaseMany(actors, function(aResponse) { + // Successful release won't return an error. + do_check_eq(aResponse.error, undefined); + + gClient.request({ to: last, type: "bogusRequest" }, function(aResponse) { + do_check_eq(aResponse.error, "noSuchActor"); + gThreadClient.resume(function(aResponse) { + finishClient(gClient); + }); + }); + }); + }); + gThreadClient.resume(); + }); + }); + + gDebuggee.eval("(" + function() { + function stopMe(arg1, arg2, arg3) { + debugger; + debugger; + }; + stopMe({obj: 1}, {obj: 2}, {obj: 3}); + ")" + } + ")()"); +} diff --git a/toolkit/devtools/debugger/tests/unit/xpcshell.ini b/toolkit/devtools/debugger/tests/unit/xpcshell.ini index 875b1d096adf..5875fa77b04f 100644 --- a/toolkit/devtools/debugger/tests/unit/xpcshell.ini +++ b/toolkit/devtools/debugger/tests/unit/xpcshell.ini @@ -24,6 +24,7 @@ tail = [test_threadlifetime-03.js] [test_threadlifetime-04.js] [test_threadlifetime-05.js] +[test_threadlifetime-06.js] [test_functiongrips-01.js] [test_frameclient-01.js] [test_frameclient-02.js]