This commit is contained in:
Tim Taubert 2014-01-23 10:57:35 +01:00
Родитель 8d3a7df7a7 c74418115e
Коммит fc3315fbfe
29 изменённых файлов: 419 добавлений и 284 удалений

Просмотреть файл

@ -1103,6 +1103,8 @@ let RemoteDebugger = {
DebuggerServer.registerModule("devtools/server/actors/inspector"); DebuggerServer.registerModule("devtools/server/actors/inspector");
DebuggerServer.registerModule("devtools/server/actors/styleeditor"); DebuggerServer.registerModule("devtools/server/actors/styleeditor");
DebuggerServer.registerModule("devtools/server/actors/stylesheets"); DebuggerServer.registerModule("devtools/server/actors/stylesheets");
DebuggerServer.registerModule("devtools/server/actors/tracer");
DebuggerServer.registerModule("devtools/server/actors/webgl");
} }
DebuggerServer.addActors('chrome://browser/content/dbg-browser-actors.js'); DebuggerServer.addActors('chrome://browser/content/dbg-browser-actors.js');
DebuggerServer.addActors("resource://gre/modules/devtools/server/actors/webapps.js"); DebuggerServer.addActors("resource://gre/modules/devtools/server/actors/webapps.js");

Просмотреть файл

@ -235,7 +235,7 @@ let DebuggerController = {
if (target.chrome) { if (target.chrome) {
this._startChromeDebugging(chromeDebugger, startedDebugging.resolve); this._startChromeDebugging(chromeDebugger, startedDebugging.resolve);
} else { } else {
this._startDebuggingTab(threadActor, startedDebugging.resolve); this._startDebuggingTab(startedDebugging.resolve);
const startedTracing = promise.defer(); const startedTracing = promise.defer();
this._startTracingTab(traceActor, startedTracing.resolve); this._startTracingTab(traceActor, startedTracing.resolve);
@ -339,13 +339,13 @@ let DebuggerController = {
/** /**
* Sets up a debugging session. * Sets up a debugging session.
* *
* @param string aThreadActor
* The remote protocol grip of the tab.
* @param function aCallback * @param function aCallback
* A function to invoke once the client attaches to the active thread. * A function to invoke once the client attaches to the active thread.
*/ */
_startDebuggingTab: function(aThreadActor, aCallback) { _startDebuggingTab: function(aCallback) {
this.client.attachThread(aThreadActor, (aResponse, aThreadClient) => { this._target.activeTab.attachThread({
useSourceMaps: Prefs.sourceMapsEnabled
}, (aResponse, aThreadClient) => {
if (!aThreadClient) { if (!aThreadClient) {
Cu.reportError("Couldn't attach to thread: " + aResponse.error); Cu.reportError("Couldn't attach to thread: " + aResponse.error);
return; return;
@ -355,12 +355,14 @@ let DebuggerController = {
this.ThreadState.connect(); this.ThreadState.connect();
this.StackFrames.connect(); this.StackFrames.connect();
this.SourceScripts.connect(); this.SourceScripts.connect();
aThreadClient.resume(this._ensureResumptionOrder); if (aThreadClient.paused) {
aThreadClient.resume(this._ensureResumptionOrder);
}
if (aCallback) { if (aCallback) {
aCallback(); aCallback();
} }
}, { useSourceMaps: Prefs.sourceMapsEnabled }); });
}, },
/** /**
@ -382,7 +384,9 @@ let DebuggerController = {
this.ThreadState.connect(); this.ThreadState.connect();
this.StackFrames.connect(); this.StackFrames.connect();
this.SourceScripts.connect(); this.SourceScripts.connect();
aThreadClient.resume(this._ensureResumptionOrder); if (aThreadClient.paused) {
aThreadClient.resume(this._ensureResumptionOrder);
}
if (aCallback) { if (aCallback) {
aCallback(); aCallback();
@ -419,7 +423,7 @@ let DebuggerController = {
* away old sources and get them again. * away old sources and get them again.
*/ */
reconfigureThread: function(aUseSourceMaps) { reconfigureThread: function(aUseSourceMaps) {
this.client.reconfigureThread({ useSourceMaps: aUseSourceMaps }, aResponse => { this.activeThread.reconfigure({ useSourceMaps: aUseSourceMaps }, aResponse => {
if (aResponse.error) { if (aResponse.error) {
let msg = "Couldn't reconfigure thread: " + aResponse.message; let msg = "Couldn't reconfigure thread: " + aResponse.message;
Cu.reportError(msg); Cu.reportError(msg);
@ -432,8 +436,10 @@ let DebuggerController = {
this.SourceScripts.handleTabNavigation(); this.SourceScripts.handleTabNavigation();
// Update the stack frame list. // Update the stack frame list.
this.activeThread._clearFrames(); if (this.activeThread.paused) {
this.activeThread.fillFrames(CALL_STACK_PAGE_SIZE); this.activeThread._clearFrames();
this.activeThread.fillFrames(CALL_STACK_PAGE_SIZE);
}
}); });
}, },

Просмотреть файл

@ -32,7 +32,7 @@ function test() {
is(gEvents.itemCount, 0, "There should be no events before reloading."); is(gEvents.itemCount, 0, "There should be no events before reloading.");
let reloaded = waitForSourcesAfterReload(); let reloaded = waitForSourcesAfterReload();
gDebugger.gClient.activeTab.reload(); gDebugger.DebuggerController._target.activeTab.reload();
is(gEvents.itemCount, 0, "There should be no events while reloading."); is(gEvents.itemCount, 0, "There should be no events while reloading.");
yield reloaded; yield reloaded;

Просмотреть файл

@ -47,7 +47,7 @@ function test() {
let reloading = once(gDebugger.gTarget, "will-navigate"); let reloading = once(gDebugger.gTarget, "will-navigate");
let reloaded = waitForSourcesAfterReload(); let reloaded = waitForSourcesAfterReload();
gDebugger.gClient.activeTab.reload(); gDebugger.DebuggerController._target.activeTab.reload();
yield reloading; yield reloading;
@ -89,7 +89,7 @@ function test() {
let reloading = once(gDebugger.gTarget, "will-navigate"); let reloading = once(gDebugger.gTarget, "will-navigate");
let reloaded = waitForSourcesAfterReload(); let reloaded = waitForSourcesAfterReload();
gDebugger.gClient.activeTab.reload(); gDebugger.DebuggerController._target.activeTab.reload();
yield reloading; yield reloading;

Просмотреть файл

@ -68,7 +68,7 @@ function testBreakOnAll() {
// Test calling pauseOnDOMEvents from a paused state. // Test calling pauseOnDOMEvents from a paused state.
gThreadClient.pauseOnDOMEvents("*", (aPacket) => { gThreadClient.pauseOnDOMEvents("*", (aPacket) => {
is(aPacket, undefined, is(aPacket.error, undefined,
"The pause-on-any-event request completed successfully."); "The pause-on-any-event request completed successfully.");
gClient.addOneTimeListener("paused", (aEvent, aPacket) => { gClient.addOneTimeListener("paused", (aEvent, aPacket) => {

Просмотреть файл

@ -8,12 +8,11 @@
const TAB_URL = EXAMPLE_URL + "doc_binary_search.html"; const TAB_URL = EXAMPLE_URL + "doc_binary_search.html";
const JS_URL = EXAMPLE_URL + "code_binary_search.js"; const JS_URL = EXAMPLE_URL + "code_binary_search.js";
let gTab, gDebuggee, gPanel, gDebugger; let gDebuggee, gPanel, gDebugger, gEditor;
let gEditor, gSources, gFrames, gPrefs, gOptions; let gSources, gFrames, gPrefs, gOptions;
function test() { function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => { initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee; gDebuggee = aDebuggee;
gPanel = aPanel; gPanel = aPanel;
gDebugger = gPanel.panelWin; gDebugger = gPanel.panelWin;
@ -26,7 +25,6 @@ function test() {
waitForSourceShown(gPanel, ".coffee") waitForSourceShown(gPanel, ".coffee")
.then(testToggleGeneratedSource) .then(testToggleGeneratedSource)
.then(testSetBreakpoint) .then(testSetBreakpoint)
.then(testHitBreakpoint)
.then(testToggleOnPause) .then(testToggleOnPause)
.then(testResume) .then(testResume)
.then(() => closeDebuggerAndFinish(gPanel)) .then(() => closeDebuggerAndFinish(gPanel))
@ -68,34 +66,23 @@ function testSetBreakpoint() {
ok(!aResponse.error, ok(!aResponse.error,
"Should be able to set a breakpoint in a js file."); "Should be able to set a breakpoint in a js file.");
deferred.resolve(); gDebugger.gClient.addOneTimeListener("resumed", () => {
}); waitForCaretAndScopes(gPanel, 7).then(() => {
// Make sure that we have JavaScript stack frames.
is(gFrames.itemCount, 1,
"Should have only one frame.");
is(gFrames.getItemAtIndex(0).attachment.url.indexOf(".coffee"), -1,
"First frame should not be a coffee source frame.");
isnot(gFrames.getItemAtIndex(0).attachment.url.indexOf(".js"), -1,
"First frame should be a JS frame.");
return deferred.promise; deferred.resolve();
} });
function testHitBreakpoint() { // This will cause the breakpoint to be hit, and put us back in the
let deferred = promise.defer(); // paused state.
gDebuggee.binary_search([0, 2, 3, 5, 7, 10], 5);
gDebugger.gThreadClient.resume(aResponse => {
ok(!aResponse.error, "Shouldn't get an error resuming.");
is(aResponse.type, "resumed", "Type should be 'resumed'.");
waitForCaretAndScopes(gPanel, 7).then(() => {
// Make sure that we have JavaScript stack frames.
is(gFrames.itemCount, 1,
"Should have only one frame.");
is(gFrames.getItemAtIndex(0).attachment.url.indexOf(".coffee"), -1,
"First frame should not be a coffee source frame.");
isnot(gFrames.getItemAtIndex(0).attachment.url.indexOf(".js"), -1,
"First frame should be a JS frame.");
deferred.resolve();
}); });
// This will cause the breakpoint to be hit, and put us back in the
// paused state.
gDebuggee.binary_search([0, 2, 3, 5, 7, 10], 5);
}); });
return deferred.promise; return deferred.promise;
@ -148,7 +135,6 @@ function testResume() {
} }
registerCleanupFunction(function() { registerCleanupFunction(function() {
gTab = null;
gDebuggee = null; gDebuggee = null;
gPanel = null; gPanel = null;
gDebugger = null; gDebugger = null;

Просмотреть файл

@ -8,12 +8,11 @@
const TAB_URL = EXAMPLE_URL + "doc_minified.html"; const TAB_URL = EXAMPLE_URL + "doc_minified.html";
const JS_URL = EXAMPLE_URL + "code_math.js"; const JS_URL = EXAMPLE_URL + "code_math.js";
let gTab, gDebuggee, gPanel, gDebugger; let gDebuggee, gPanel, gDebugger;
let gEditor, gSources, gFrames; let gEditor, gSources, gFrames;
function test() { function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => { initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee; gDebuggee = aDebuggee;
gPanel = aPanel; gPanel = aPanel;
gDebugger = gPanel.panelWin; gDebugger = gPanel.panelWin;
@ -24,7 +23,6 @@ function test() {
waitForSourceShown(gPanel, JS_URL) waitForSourceShown(gPanel, JS_URL)
.then(checkInitialSource) .then(checkInitialSource)
.then(testSetBreakpoint) .then(testSetBreakpoint)
.then(testHitBreakpoint)
.then(() => resumeDebuggerThenCloseAndFinish(gPanel)) .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
.then(null, aError => { .then(null, aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack); ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
@ -45,50 +43,35 @@ function checkInitialSource() {
function testSetBreakpoint() { function testSetBreakpoint() {
let deferred = promise.defer(); let deferred = promise.defer();
gDebugger.gThreadClient.interrupt(aResponse => { gDebugger.gThreadClient.setBreakpoint({ url: JS_URL, line: 30, column: 21 }, aResponse => {
gDebugger.gThreadClient.setBreakpoint({ url: JS_URL, line: 30, column: 21 }, aResponse => { ok(!aResponse.error,
ok(!aResponse.error, "Should be able to set a breakpoint in a js file.");
"Should be able to set a breakpoint in a js file."); ok(!aResponse.actualLocation,
ok(!aResponse.actualLocation, "Should be able to set a breakpoint on line 30 and column 10.");
"Should be able to set a breakpoint on line 30 and column 10.");
deferred.resolve(); gDebugger.gClient.addOneTimeListener("resumed", () => {
waitForCaretAndScopes(gPanel, 30).then(() => {
// Make sure that we have the right stack frames.
is(gFrames.itemCount, 9,
"Should have nine frames.");
is(gFrames.getItemAtIndex(0).attachment.url.indexOf(".min.js"), -1,
"First frame should not be a minified JS frame.");
isnot(gFrames.getItemAtIndex(0).attachment.url.indexOf(".js"), -1,
"First frame should be a JS frame.");
deferred.resolve();
});
// This will cause the breakpoint to be hit, and put us back in the
// paused state.
gDebuggee.arithmetic();
}); });
}); });
return deferred.promise; return deferred.promise;
} }
function testHitBreakpoint() {
let deferred = promise.defer();
gDebugger.gThreadClient.resume(aResponse => {
ok(!aResponse.error, "Shouldn't get an error resuming.");
is(aResponse.type, "resumed", "Type should be 'resumed'.");
waitForCaretAndScopes(gPanel, 30).then(() => {
// Make sure that we have the right stack frames.
is(gFrames.itemCount, 9,
"Should have nine frames.");
is(gFrames.getItemAtIndex(0).attachment.url.indexOf(".min.js"), -1,
"First frame should not be a minified JS frame.");
isnot(gFrames.getItemAtIndex(0).attachment.url.indexOf(".js"), -1,
"First frame should be a JS frame.");
deferred.resolve();
});
// This will cause the breakpoint to be hit, and put us back in the
// paused state.
gDebuggee.arithmetic();
});
return deferred.promise;
}
registerCleanupFunction(function() { registerCleanupFunction(function() {
gTab = null;
gDebuggee = null; gDebuggee = null;
gPanel = null; gPanel = null;
gDebugger = null; gDebugger = null;

Просмотреть файл

@ -101,7 +101,7 @@ function testSetBreakpoint() {
function reloadPage() { function reloadPage() {
let loaded = waitForSourceAndCaret(gPanel, ".js", 3); let loaded = waitForSourceAndCaret(gPanel, ".js", 3);
gDebugger.gClient.activeTab.reload(); gDebugger.DebuggerController._target.activeTab.reload();
return loaded.then(() => ok(true, "Page was reloaded and execution resumed.")); return loaded.then(() => ok(true, "Page was reloaded and execution resumed."));
} }

Просмотреть файл

@ -410,7 +410,7 @@ function ensureThreadClientState(aPanel, aState) {
function navigateActiveTabTo(aPanel, aUrl, aWaitForEventName, aEventRepeat) { function navigateActiveTabTo(aPanel, aUrl, aWaitForEventName, aEventRepeat) {
let finished = waitForDebuggerEvents(aPanel, aWaitForEventName, aEventRepeat); let finished = waitForDebuggerEvents(aPanel, aWaitForEventName, aEventRepeat);
let activeTab = aPanel.panelWin.gClient.activeTab; let activeTab = aPanel.panelWin.DebuggerController._target.activeTab;
aUrl ? activeTab.navigateTo(aUrl) : activeTab.reload(); aUrl ? activeTab.navigateTo(aUrl) : activeTab.reload();
return finished; return finished;
} }

Просмотреть файл

@ -284,6 +284,7 @@ TabTarget.prototype = {
this._remote.reject("Unable to attach to the tab"); this._remote.reject("Unable to attach to the tab");
return; return;
} }
this.activeTab = aTabClient;
this.threadActor = aResponse.threadActor; this.threadActor = aResponse.threadActor;
this._remote.resolve(null); this._remote.resolve(null);
}); });
@ -444,11 +445,14 @@ TabTarget.prototype = {
this._teardownListeners(); this._teardownListeners();
} }
let cleanupAndResolve = () => {
this._cleanup();
this._destroyer.resolve(null);
};
// If this target was not remoted, the promise will be resolved before the // If this target was not remoted, the promise will be resolved before the
// function returns. // function returns.
if (this._tab && !this._client) { if (this._tab && !this._client) {
this._cleanup(); cleanupAndResolve();
this._destroyer.resolve(null);
} else if (this._client) { } else if (this._client) {
// If, on the other hand, this target was remoted, the promise will be // If, on the other hand, this target was remoted, the promise will be
// resolved after the remote connection is closed. // resolved after the remote connection is closed.
@ -457,15 +461,15 @@ TabTarget.prototype = {
if (this.isLocalTab) { if (this.isLocalTab) {
// We started with a local tab and created the client ourselves, so we // We started with a local tab and created the client ourselves, so we
// should close it. // should close it.
this._client.close(() => { this._client.close(cleanupAndResolve);
this._cleanup();
this._destroyer.resolve(null);
});
} else { } else {
// The client was handed to us, so we are not responsible for closing // The client was handed to us, so we are not responsible for closing
// it. // it. We just need to detach from the tab, if already attached.
this._cleanup(); if (this.activeTab) {
this._destroyer.resolve(null); this.activeTab.detach(cleanupAndResolve);
} else {
cleanupAndResolve();
}
} }
} }
@ -481,6 +485,7 @@ TabTarget.prototype = {
} else { } else {
promiseTargets.delete(this._form); promiseTargets.delete(this._form);
} }
this.activeTab = null;
this._client = null; this._client = null;
this._tab = null; this._tab = null;
this._form = null; this._form = null;

Просмотреть файл

@ -212,7 +212,7 @@ OptionsPanel.prototype = {
}.bind(menulist)); }.bind(menulist));
} }
this.target.client.attachTab(this.target.client.activeTab._actor, (response) => { this.target.client.attachTab(this.target.activeTab._actor, (response) => {
this._origJavascriptEnabled = response.javascriptEnabled; this._origJavascriptEnabled = response.javascriptEnabled;
this._origCacheEnabled = response.cacheEnabled; this._origCacheEnabled = response.cacheEnabled;
@ -248,7 +248,7 @@ OptionsPanel.prototype = {
"javascriptEnabled": !checked "javascriptEnabled": !checked
}; };
this.target.client.reconfigureTab(options); this.target.activeTab.reconfigure(options);
}, },
/** /**
@ -264,7 +264,7 @@ OptionsPanel.prototype = {
"cacheEnabled": !checked "cacheEnabled": !checked
}; };
this.target.client.reconfigureTab(options); this.target.activeTab.reconfigure(options);
}, },
destroy: function() { destroy: function() {
@ -291,7 +291,7 @@ OptionsPanel.prototype = {
"cacheEnabled": this._origCacheEnabled, "cacheEnabled": this._origCacheEnabled,
"javascriptEnabled": this._origJavascriptEnabled "javascriptEnabled": this._origJavascriptEnabled
}; };
this.target.client.reconfigureTab(options, () => { this.target.activeTab.reconfigure(options, () => {
this.toolbox = null; this.toolbox = null;
deferred.resolve(); deferred.resolve();
}, true); }, true);

Просмотреть файл

@ -1217,7 +1217,7 @@ Toolbox.prototype = {
outstanding.push(panel.destroy()); outstanding.push(panel.destroy());
} catch (e) { } catch (e) {
// We don't want to stop here if any panel fail to close. // We don't want to stop here if any panel fail to close.
console.error(e); console.error("Panel " + id + ":", e);
} }
} }

Просмотреть файл

@ -229,12 +229,12 @@ function navigateInHistory(aTarget, aDirection, aWaitForTargetEvent = "navigate"
} }
function navigate(aTarget, aUrl, aWaitForTargetEvent = "navigate") { function navigate(aTarget, aUrl, aWaitForTargetEvent = "navigate") {
executeSoon(() => aTarget.client.activeTab.navigateTo(aUrl)); executeSoon(() => aTarget.activeTab.navigateTo(aUrl));
return once(aTarget, aWaitForTargetEvent); return once(aTarget, aWaitForTargetEvent);
} }
function reload(aTarget, aWaitForTargetEvent = "navigate") { function reload(aTarget, aWaitForTargetEvent = "navigate") {
executeSoon(() => aTarget.client.activeTab.reload()); executeSoon(() => aTarget.activeTab.reload());
return once(aTarget, aWaitForTargetEvent); return once(aTarget, aWaitForTargetEvent);
} }

Просмотреть файл

@ -167,7 +167,9 @@ BreadcrumbsWidget.prototype = {
// Repeated calls to ensureElementIsVisible would interfere with each other // Repeated calls to ensureElementIsVisible would interfere with each other
// and may sometimes result in incorrect scroll positions. // and may sometimes result in incorrect scroll positions.
setNamedTimeout("breadcrumb-select", ENSURE_SELECTION_VISIBLE_DELAY, () => { setNamedTimeout("breadcrumb-select", ENSURE_SELECTION_VISIBLE_DELAY, () => {
this._list.ensureElementIsVisible(aElement); if (this._list.ensureElementIsVisible) {
this._list.ensureElementIsVisible(aElement);
}
}); });
}, },

Просмотреть файл

@ -4866,6 +4866,34 @@
"n_buckets": "1000", "n_buckets": "1000",
"description": "The time (in milliseconds) that it took to display a selected source to the user." "description": "The time (in milliseconds) that it took to display a selected source to the user."
}, },
"DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS": {
"expires_in_version": "never",
"kind": "exponential",
"high": "10000",
"n_buckets": "1000",
"description": "The time (in milliseconds) that it took a 'reconfigure tab' request to go round trip."
},
"DEVTOOLS_DEBUGGER_RDP_REMOTE_RECONFIGURETAB_MS": {
"expires_in_version": "never",
"kind": "exponential",
"high": "10000",
"n_buckets": "1000",
"description": "The time (in milliseconds) that it took a 'reconfigure tab' request to go round trip."
},
"DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETHREAD_MS": {
"expires_in_version": "never",
"kind": "exponential",
"high": "10000",
"n_buckets": "1000",
"description": "The time (in milliseconds) that it took a 'reconfigure thread' request to go round trip."
},
"DEVTOOLS_DEBUGGER_RDP_REMOTE_RECONFIGURETHREAD_MS": {
"expires_in_version": "never",
"kind": "exponential",
"high": "10000",
"n_buckets": "1000",
"description": "The time (in milliseconds) that it took a 'reconfigure thread' request to go round trip."
},
"WEBRTC_ICE_SUCCESS_RATE": { "WEBRTC_ICE_SUCCESS_RATE": {
"expires_in_version": "never", "expires_in_version": "never",
"kind": "boolean", "kind": "boolean",

Просмотреть файл

@ -234,9 +234,12 @@ this.DebuggerClient = function (aTransport)
{ {
this._transport = aTransport; this._transport = aTransport;
this._transport.hooks = this; this._transport.hooks = this;
this._threadClients = {};
this._tabClients = {}; // Map actor ID to client instance for each actor type.
this._consoleClients = {}; this._threadClients = new Map;
this._tabClients = new Map;
this._tracerClients = new Map;
this._consoleClients = new Map;
this._pendingRequests = []; this._pendingRequests = [];
this._activeRequests = new Map; this._activeRequests = new Map;
@ -281,7 +284,7 @@ this.DebuggerClient = function (aTransport)
*/ */
DebuggerClient.requester = function (aPacketSkeleton, DebuggerClient.requester = function (aPacketSkeleton,
{ telemetry, before, after }) { { telemetry, before, after }) {
return function (...args) { return DevToolsUtils.makeInfallible(function (...args) {
let histogram, startTime; let histogram, startTime;
if (telemetry) { if (telemetry) {
let transportType = this._transport.onOutputStreamReady === undefined let transportType = this._transport.onOutputStreamReady === undefined
@ -311,7 +314,7 @@ DebuggerClient.requester = function (aPacketSkeleton,
outgoingPacket = before.call(this, outgoingPacket); outgoingPacket = before.call(this, outgoingPacket);
} }
this.request(outgoingPacket, function (aResponse) { this.request(outgoingPacket, DevToolsUtils.makeInfallible(function (aResponse) {
if (after) { if (after) {
let { from } = aResponse; let { from } = aResponse;
aResponse = after.call(this, aResponse); aResponse = after.call(this, aResponse);
@ -323,19 +326,15 @@ DebuggerClient.requester = function (aPacketSkeleton,
// The callback is always the last parameter. // The callback is always the last parameter.
let thisCallback = args[maxPosition + 1]; let thisCallback = args[maxPosition + 1];
if (thisCallback) { if (thisCallback) {
try { thisCallback(aResponse);
thisCallback(aResponse);
} catch (e) {
DevToolsUtils.reportException("DebuggerClient.requester callback", e);
}
} }
if (histogram) { if (histogram) {
histogram.add(+new Date - startTime); histogram.add(+new Date - startTime);
} }
}.bind(this)); }.bind(this), "DebuggerClient.requester request callback"));
}; }, "DebuggerClient.requester");
}; };
function args(aPos) { function args(aPos) {
@ -390,43 +389,35 @@ DebuggerClient.prototype = {
}); });
} }
// In this function, we're using the hoisting behavior of nested const detachClients = (clientMap, next) => {
// function definitions to write the code in the order it will actually const clients = clientMap.values();
// execute. So converting to arrow functions to get rid of 'self' would const total = clientMap.size;
// be unhelpful here. let numFinished = 0;
let self = this;
let continuation = function () { if (total == 0) {
self._consoleClients = {}; next();
detachThread(); return;
}
for each (let client in this._consoleClients) {
continuation = client.close.bind(client, continuation);
}
continuation();
function detachThread() {
if (self.activeThread) {
self.activeThread.detach(detachTab);
} else {
detachTab();
} }
}
function detachTab() { for (let client of clients) {
if (self.activeTab) { let method = client instanceof WebConsoleClient ? "close" : "detach";
self.activeTab.detach(closeTransport); client[method](() => {
} else { if (++numFinished === total) {
closeTransport(); clientMap.clear();
next();
}
});
} }
} };
function closeTransport() { detachClients(this._consoleClients, () => {
self._transport.close(); detachClients(this._threadClients, () => {
self._transport = null; detachClients(this._tabClients, () => {
} this._transport.close();
this._transport = null;
});
});
});
}, },
/* /*
@ -451,6 +442,16 @@ DebuggerClient.prototype = {
* (which will be undefined on error). * (which will be undefined on error).
*/ */
attachTab: function (aTabActor, aOnResponse) { attachTab: function (aTabActor, aOnResponse) {
if (this._tabClients.has(aTabActor)) {
let cachedTab = this._tabClients.get(aTabActor);
let cachedResponse = {
cacheEnabled: cachedTab.cacheEnabled,
javascriptEnabled: cachedTab.javascriptEnabled
};
setTimeout(() => aOnResponse(cachedResponse, cachedTab), 0);
return;
}
let packet = { let packet = {
to: aTabActor, to: aTabActor,
type: "attach" type: "attach"
@ -458,9 +459,8 @@ DebuggerClient.prototype = {
this.request(packet, (aResponse) => { this.request(packet, (aResponse) => {
let tabClient; let tabClient;
if (!aResponse.error) { if (!aResponse.error) {
tabClient = new TabClient(this, aTabActor); tabClient = new TabClient(this, aResponse);
this._tabClients[aTabActor] = tabClient; this._tabClients.set(aTabActor, tabClient);
this.activeTab = tabClient;
} }
aOnResponse(aResponse, tabClient); aOnResponse(aResponse, tabClient);
}); });
@ -479,6 +479,11 @@ DebuggerClient.prototype = {
*/ */
attachConsole: attachConsole:
function (aConsoleActor, aListeners, aOnResponse) { function (aConsoleActor, aListeners, aOnResponse) {
if (this._consoleClients.has(aConsoleActor)) {
setTimeout(() => aOnResponse({}, this._consoleClients.get(aConsoleActor)), 0);
return;
}
let packet = { let packet = {
to: aConsoleActor, to: aConsoleActor,
type: "startListeners", type: "startListeners",
@ -489,14 +494,14 @@ DebuggerClient.prototype = {
let consoleClient; let consoleClient;
if (!aResponse.error) { if (!aResponse.error) {
consoleClient = new WebConsoleClient(this, aConsoleActor); consoleClient = new WebConsoleClient(this, aConsoleActor);
this._consoleClients[aConsoleActor] = consoleClient; this._consoleClients.set(aConsoleActor, consoleClient);
} }
aOnResponse(aResponse, consoleClient); aOnResponse(aResponse, consoleClient);
}); });
}, },
/** /**
* Attach to a thread actor. * Attach to a global-scoped thread actor for chrome debugging.
* *
* @param string aThreadActor * @param string aThreadActor
* The actor ID for the thread to attach. * The actor ID for the thread to attach.
@ -508,7 +513,12 @@ DebuggerClient.prototype = {
* - useSourceMaps: whether to use source maps or not. * - useSourceMaps: whether to use source maps or not.
*/ */
attachThread: function (aThreadActor, aOnResponse, aOptions={}) { attachThread: function (aThreadActor, aOnResponse, aOptions={}) {
let packet = { if (this._threadClients.has(aThreadActor)) {
setTimeout(() => aOnResponse({}, this._threadClients.get(aThreadActor)), 0);
return;
}
let packet = {
to: aThreadActor, to: aThreadActor,
type: "attach", type: "attach",
options: aOptions options: aOptions
@ -516,8 +526,7 @@ DebuggerClient.prototype = {
this.request(packet, (aResponse) => { this.request(packet, (aResponse) => {
if (!aResponse.error) { if (!aResponse.error) {
var threadClient = new ThreadClient(this, aThreadActor); var threadClient = new ThreadClient(this, aThreadActor);
this._threadClients[aThreadActor] = threadClient; this._threadClients.set(aThreadActor, threadClient);
this.activeThread = threadClient;
} }
aOnResponse(aResponse, threadClient); aOnResponse(aResponse, threadClient);
}); });
@ -533,52 +542,24 @@ DebuggerClient.prototype = {
* (which will be undefined on error). * (which will be undefined on error).
*/ */
attachTracer: function (aTraceActor, aOnResponse) { attachTracer: function (aTraceActor, aOnResponse) {
if (this._tracerClients.has(aTraceActor)) {
setTimeout(() => aOnResponse({}, this._tracerClients.get(aTraceActor)), 0);
return;
}
let packet = { let packet = {
to: aTraceActor, to: aTraceActor,
type: "attach" type: "attach"
}; };
this.request(packet, (aResponse) => { this.request(packet, (aResponse) => {
if (!aResponse.error) { if (!aResponse.error) {
let traceClient = new TraceClient(this, aTraceActor); var traceClient = new TraceClient(this, aTraceActor);
aOnResponse(aResponse, traceClient); this._tracerClients.set(aTraceActor, traceClient);
} }
aOnResponse(aResponse, traceClient);
}); });
}, },
/**
* Reconfigure a thread actor.
*
* @param object aOptions
* A dictionary object of the new options to use in the thread actor.
* @param function aOnResponse
* Called with the response packet.
*/
reconfigureThread: function (aOptions, aOnResponse) {
let packet = {
to: this.activeThread._actor,
type: "reconfigure",
options: aOptions
};
this.request(packet, aOnResponse);
},
/**
* Reconfigure a tab actor.
*
* @param object aOptions
* A dictionary object of the new options to use in the tab actor.
* @param function aOnResponse
* Called with the response packet.
*/
reconfigureTab: function (aOptions, aOnResponse) {
let packet = {
to: this.activeTab._actor,
type: "reconfigure",
options: aOptions
};
this.request(packet, aOnResponse);
},
/** /**
* Release an object actor. * Release an object actor.
* *
@ -697,17 +678,18 @@ DebuggerClient.prototype = {
// Packets that indicate thread state changes get special treatment. // Packets that indicate thread state changes get special treatment.
if (aPacket.type in ThreadStateTypes && if (aPacket.type in ThreadStateTypes &&
aPacket.from in this._threadClients) { this._threadClients.has(aPacket.from)) {
this._threadClients[aPacket.from]._onThreadState(aPacket); this._threadClients.get(aPacket.from)._onThreadState(aPacket);
} }
// On navigation the server resumes, so the client must resume as well. // On navigation the server resumes, so the client must resume as well.
// We achieve that by generating a fake resumption packet that triggers // We achieve that by generating a fake resumption packet that triggers
// the client's thread state change listeners. // the client's thread state change listeners.
if (this.activeThread && if (aPacket.type == UnsolicitedNotifications.tabNavigated &&
aPacket.type == UnsolicitedNotifications.tabNavigated && this._tabClients.has(aPacket.from) &&
aPacket.from in this._tabClients) { this._tabClients.get(aPacket.from).thread) {
let resumption = { from: this.activeThread._actor, type: "resumed" }; let thread = this._tabClients.get(aPacket.from).thread;
this.activeThread._onThreadState(resumption); let resumption = { from: thread._actor, type: "resumed" };
thread._onThreadState(resumption);
} }
// Only try to notify listeners on events, not responses to requests // Only try to notify listeners on events, not responses to requests
// that lack a packet type. // that lack a packet type.
@ -959,18 +941,52 @@ SSProto.translatePacket = function (aPacket, aReplacePacket, aExtraPacket,
* *
* @param aClient DebuggerClient * @param aClient DebuggerClient
* The debugger client parent. * The debugger client parent.
* @param aActor string * @param aForm object
* The actor ID for this tab. * The protocol form for this tab.
*/ */
function TabClient(aClient, aActor) { function TabClient(aClient, aForm) {
this._client = aClient; this.client = aClient;
this._actor = aActor; this._actor = aForm.from;
this.request = this._client.request; this._threadActor = aForm.threadActor;
this.javascriptEnabled = aForm.javascriptEnabled;
this.cacheEnabled = aForm.cacheEnabled;
this.thread = null;
this.request = this.client.request;
} }
TabClient.prototype = { TabClient.prototype = {
get actor() { return this._actor }, get actor() { return this._actor },
get _transport() { return this._client._transport; }, get _transport() { return this.client._transport; },
/**
* Attach to a thread actor.
*
* @param object aOptions
* Configuration options.
* - useSourceMaps: whether to use source maps or not.
* @param function aOnResponse
* Called with the response packet and a ThreadClient
* (which will be undefined on error).
*/
attachThread: function(aOptions={}, aOnResponse) {
if (this.thread) {
setTimeout(() => aOnResponse({}, this.thread), 0);
return;
}
let packet = {
to: this._threadActor,
type: "attach",
options: aOptions
};
this.request(packet, (aResponse) => {
if (!aResponse.error) {
this.thread = new ThreadClient(this, this._threadActor);
this.client._threadClients.set(this._threadActor, this.thread);
}
aOnResponse(aResponse, this.thread);
});
},
/** /**
* Detach the client from the tab actor. * Detach the client from the tab actor.
@ -981,11 +997,14 @@ TabClient.prototype = {
detach: DebuggerClient.requester({ detach: DebuggerClient.requester({
type: "detach" type: "detach"
}, { }, {
after: function (aResponse) { before: function (aPacket) {
if (this.activeTab === this._client._tabClients[this.actor]) { if (this.thread) {
this.activeTab = undefined; this.thread.detach();
} }
delete this._client._tabClients[this.actor]; return aPacket;
},
after: function (aResponse) {
this.client._tabClients.delete(this.actor);
return aResponse; return aResponse;
}, },
telemetry: "TABDETACH" telemetry: "TABDETACH"
@ -1012,6 +1031,21 @@ TabClient.prototype = {
}, { }, {
telemetry: "NAVIGATETO" telemetry: "NAVIGATETO"
}), }),
/**
* Reconfigure the tab actor.
*
* @param object aOptions
* A dictionary object of the new options to use in the tab actor.
* @param function aOnResponse
* Called with the response packet.
*/
reconfigure: DebuggerClient.requester({
type: "reconfigure",
options: args(0)
}, {
telemetry: "RECONFIGURETAB"
}),
}; };
eventSource(TabClient.prototype); eventSource(TabClient.prototype);
@ -1077,19 +1111,21 @@ RootClient.prototype = {
* is a front to the thread actor created in the server side, hiding the * is a front to the thread actor created in the server side, hiding the
* protocol details in a traditional JavaScript API. * protocol details in a traditional JavaScript API.
* *
* @param aClient DebuggerClient * @param aClient DebuggerClient|TabClient
* The debugger client parent. * The parent of the thread (tab for tab-scoped debuggers, DebuggerClient
* for chrome debuggers).
* @param aActor string * @param aActor string
* The actor ID for this thread. * The actor ID for this thread.
*/ */
function ThreadClient(aClient, aActor) { function ThreadClient(aClient, aActor) {
this._client = aClient; this._parent = aClient;
this.client = aClient instanceof DebuggerClient ? aClient : aClient.client;
this._actor = aActor; this._actor = aActor;
this._frameCache = []; this._frameCache = [];
this._scriptCache = {}; this._scriptCache = {};
this._pauseGrips = {}; this._pauseGrips = {};
this._threadGrips = {}; this._threadGrips = {};
this.request = this._client.request; this.request = this.client.request;
} }
ThreadClient.prototype = { ThreadClient.prototype = {
@ -1104,12 +1140,12 @@ ThreadClient.prototype = {
_actor: null, _actor: null,
get actor() { return this._actor; }, get actor() { return this._actor; },
get compat() { return this._client.compat; }, get compat() { return this.client.compat; },
get _transport() { return this._client._transport; }, get _transport() { return this.client._transport; },
_assertPaused: function (aCommand) { _assertPaused: function (aCommand) {
if (!this.paused) { if (!this.paused) {
throw Error(aCommand + " command sent while not paused."); throw Error(aCommand + " command sent while not paused. Currently " + this._state);
} }
}, },
@ -1156,6 +1192,21 @@ ThreadClient.prototype = {
telemetry: "RESUME" telemetry: "RESUME"
}), }),
/**
* Reconfigure the thread actor.
*
* @param object aOptions
* A dictionary object of the new options to use in the thread actor.
* @param function aOnResponse
* Called with the response packet.
*/
reconfigure: DebuggerClient.requester({
type: "reconfigure",
options: args(0)
}, {
telemetry: "RECONFIGURETHREAD"
}),
/** /**
* Resume a paused thread. * Resume a paused thread.
*/ */
@ -1222,7 +1273,7 @@ ThreadClient.prototype = {
// If the debuggee is paused, we have to send the flag via a reconfigure // If the debuggee is paused, we have to send the flag via a reconfigure
// request. // request.
if (this.paused) { if (this.paused) {
this._client.reconfigureThread({ this.reconfigure({
pauseOnExceptions: aPauseOnExceptions, pauseOnExceptions: aPauseOnExceptions,
ignoreCaughtExceptions: aIgnoreCaughtExceptions ignoreCaughtExceptions: aIgnoreCaughtExceptions
}, aOnResponse); }, aOnResponse);
@ -1256,12 +1307,16 @@ ThreadClient.prototype = {
// If the debuggee is paused, the value of the array will be communicated in // If the debuggee is paused, the value of the array will be communicated in
// the next resumption. Otherwise we have to force a pause in order to send // the next resumption. Otherwise we have to force a pause in order to send
// the array. // the array.
if (this.paused) if (this.paused) {
return void setTimeout(onResponse, 0); setTimeout(() => onResponse({}), 0);
return;
}
this.interrupt(response => { this.interrupt(response => {
// Can't continue if pausing failed. // Can't continue if pausing failed.
if (response.error) if (response.error) {
return void onResponse(response); onResponse(response);
return;
}
this.resume(onResponse); this.resume(onResponse);
}); });
}, },
@ -1310,10 +1365,8 @@ ThreadClient.prototype = {
type: "detach" type: "detach"
}, { }, {
after: function (aResponse) { after: function (aResponse) {
if (this.activeThread === this._client._threadClients[this.actor]) { this.client._threadClients.delete(this.actor);
this.activeThread = null; this._parent.thread = null;
}
delete this._client._threadClients[this.actor];
return aResponse; return aResponse;
}, },
telemetry: "THREADDETACH" telemetry: "THREADDETACH"
@ -1332,11 +1385,11 @@ ThreadClient.prototype = {
let doSetBreakpoint = function (aCallback) { let doSetBreakpoint = function (aCallback) {
let packet = { to: this._actor, type: "setBreakpoint", let packet = { to: this._actor, type: "setBreakpoint",
location: aLocation }; location: aLocation };
this._client.request(packet, function (aResponse) { this.client.request(packet, function (aResponse) {
// Ignoring errors, since the user may be setting a breakpoint in a // Ignoring errors, since the user may be setting a breakpoint in a
// dead script that will reappear on a page reload. // dead script that will reappear on a page reload.
if (aOnResponse) { if (aOnResponse) {
let bpClient = new BreakpointClient(this._client, aResponse.actor, let bpClient = new BreakpointClient(this.client, aResponse.actor,
aLocation); aLocation);
if (aCallback) { if (aCallback) {
aCallback(aOnResponse(aResponse, bpClient)); aCallback(aOnResponse(aResponse, bpClient));
@ -1570,7 +1623,7 @@ ThreadClient.prototype = {
return this._pauseGrips[aGrip.actor]; return this._pauseGrips[aGrip.actor];
} }
let client = new ObjectClient(this._client, aGrip); let client = new ObjectClient(this.client, aGrip);
this._pauseGrips[aGrip.actor] = client; this._pauseGrips[aGrip.actor] = client;
return client; return client;
}, },
@ -1590,7 +1643,7 @@ ThreadClient.prototype = {
return this[aGripCacheName][aGrip.actor]; return this[aGripCacheName][aGrip.actor];
} }
let client = new LongStringClient(this._client, aGrip); let client = new LongStringClient(this.client, aGrip);
this[aGripCacheName][aGrip.actor] = client; this[aGripCacheName][aGrip.actor] = client;
return client; return client;
}, },
@ -1655,14 +1708,14 @@ ThreadClient.prototype = {
this._clearFrames(); this._clearFrames();
this._clearPauseGrips(); this._clearPauseGrips();
aPacket.type === ThreadStateTypes.detached && this._clearThreadGrips(); aPacket.type === ThreadStateTypes.detached && this._clearThreadGrips();
this._client._eventsEnabled && this.notify(aPacket.type, aPacket); this.client._eventsEnabled && this.notify(aPacket.type, aPacket);
}, },
/** /**
* Return an EnvironmentClient instance for the given environment actor form. * Return an EnvironmentClient instance for the given environment actor form.
*/ */
environment: function (aForm) { environment: function (aForm) {
return new EnvironmentClient(this._client, aForm); return new EnvironmentClient(this.client, aForm);
}, },
/** /**
@ -1673,8 +1726,7 @@ ThreadClient.prototype = {
return this._threadGrips[aForm.actor]; return this._threadGrips[aForm.actor];
} }
return this._threadGrips[aForm.actor] = new SourceClient(this._client, return this._threadGrips[aForm.actor] = new SourceClient(this, aForm);
aForm);
}, },
/** /**
@ -1724,8 +1776,15 @@ TraceClient.prototype = {
/** /**
* Detach from the trace actor. * Detach from the trace actor.
*/ */
detach: DebuggerClient.requester({ type: "detach" }, detach: DebuggerClient.requester({
{ telemetry: "TRACERDETACH" }), type: "detach"
}, {
after: function (aResponse) {
this._client._tracerClients.delete(this.actor);
return aResponse;
},
telemetry: "TRACERDETACH"
}),
/** /**
* Start a new trace. * Start a new trace.
@ -1964,8 +2023,8 @@ LongStringClient.prototype = {
/** /**
* A SourceClient provides a way to access the source text of a script. * A SourceClient provides a way to access the source text of a script.
* *
* @param aClient DebuggerClient * @param aClient ThreadClient
* The debugger client parent. * The thread client parent.
* @param aForm Object * @param aForm Object
* The form sent across the remote debugging protocol. * The form sent across the remote debugging protocol.
*/ */
@ -1973,12 +2032,12 @@ function SourceClient(aClient, aForm) {
this._form = aForm; this._form = aForm;
this._isBlackBoxed = aForm.isBlackBoxed; this._isBlackBoxed = aForm.isBlackBoxed;
this._isPrettyPrinted = aForm.isPrettyPrinted; this._isPrettyPrinted = aForm.isPrettyPrinted;
this._client = aClient; this._activeThread = aClient;
this._client = aClient.client;
} }
SourceClient.prototype = { SourceClient.prototype = {
get _transport() this._client._transport, get _transport() this._client._transport,
get _activeThread() this._client.activeThread,
get isBlackBoxed() this._isBlackBoxed, get isBlackBoxed() this._isBlackBoxed,
get isPrettyPrinted() this._isPrettyPrinted, get isPrettyPrinted() this._isPrettyPrinted,
get actor() this._form.actor, get actor() this._form.actor,
@ -2089,8 +2148,7 @@ SourceClient.prototype = {
} }
let { contentType, source } = aResponse; let { contentType, source } = aResponse;
let longString = this._client.activeThread.threadLongString( let longString = this._activeThread.threadLongString(source);
source);
longString.substring(0, longString.length, function (aResponse) { longString.substring(0, longString.length, function (aResponse) {
if (aResponse.error) { if (aResponse.error) {
aCallback(aResponse); aCallback(aResponse);

Просмотреть файл

@ -655,8 +655,6 @@ ThreadActor.prototype = {
this.onResume(); this.onResume();
} }
this._state = "exited";
this.clearDebuggees(); this.clearDebuggees();
this.conn.removeActorPool(this._threadLifetimePool); this.conn.removeActorPool(this._threadLifetimePool);
this._threadLifetimePool = null; this._threadLifetimePool = null;
@ -682,6 +680,7 @@ ThreadActor.prototype = {
*/ */
exit: function () { exit: function () {
this.disconnect(); this.disconnect();
this._state = "exited";
}, },
// Request handlers // Request handlers
@ -691,7 +690,8 @@ ThreadActor.prototype = {
} }
if (this.state !== "detached") { if (this.state !== "detached") {
return { error: "wrongState" }; return { error: "wrongState",
message: "Current state is " + this.state };
} }
this._state = "attached"; this._state = "attached";
@ -741,6 +741,8 @@ ThreadActor.prototype = {
onDetach: function (aRequest) { onDetach: function (aRequest) {
this.disconnect(); this.disconnect();
this._state = "detached";
dumpn("ThreadActor.prototype.onDetach: returning 'detached' packet"); dumpn("ThreadActor.prototype.onDetach: returning 'detached' packet");
return { return {
type: "detached" type: "detached"

Просмотреть файл

@ -677,7 +677,7 @@ WebappsActor.prototype = {
} catch(e) { } catch(e) {
deferred.resolve({ deferred.resolve({
error: "noIcon", error: "noIcon",
message: "The icon file '" + iconURL + "' doesn't exists" message: "The icon file '" + iconURL + "' doesn't exist"
}); });
return; return;
} }

Просмотреть файл

@ -890,26 +890,24 @@ BrowserTabActor.prototype = {
*/ */
onWindowCreated: onWindowCreated:
makeInfallible(function BTA_onWindowCreated(evt) { makeInfallible(function BTA_onWindowCreated(evt) {
if (evt.target === this.browser.contentDocument) { // pageshow events for non-persisted pages have already been handled by a
// pageshow events for non-persisted pages have already been handled by a // prior DOMWindowCreated event.
// prior DOMWindowCreated event. if (!this._attached || (evt.type == "pageshow" && !evt.persisted)) {
if (evt.type == "pageshow" && !evt.persisted) { return;
return; }
} if (evt.target === this.browser.contentDocument ) {
if (this._attached) { this.threadActor.clearDebuggees();
this.threadActor.clearDebuggees(); if (this.threadActor.dbg) {
if (this.threadActor.dbg) { this.threadActor.dbg.enabled = true;
this.threadActor.dbg.enabled = true; this.threadActor.global = evt.target.defaultView.wrappedJSObject;
this.threadActor.maybePauseOnExceptions(); this.threadActor.maybePauseOnExceptions();
}
} }
} }
if (this._attached) { // Refresh the debuggee list when a new window object appears (top window or
this.threadActor.global = evt.target.defaultView.wrappedJSObject; // iframe).
if (this.threadActor.attached) { if (this.threadActor.attached) {
this.threadActor.findGlobals(); this.threadActor.findGlobals();
}
} }
}, "BrowserTabActor.prototype.onWindowCreated"), }, "BrowserTabActor.prototype.onWindowCreated"),

Просмотреть файл

@ -376,6 +376,7 @@ var DebuggerServer = {
this.registerModule("devtools/server/actors/webgl"); this.registerModule("devtools/server/actors/webgl");
this.registerModule("devtools/server/actors/stylesheets"); this.registerModule("devtools/server/actors/stylesheets");
this.registerModule("devtools/server/actors/styleeditor"); this.registerModule("devtools/server/actors/styleeditor");
this.registerModule("devtools/server/actors/tracer");
} }
if (!("ContentAppActor" in DebuggerServer)) { if (!("ContentAppActor" in DebuggerServer)) {
this.addActors("resource://gre/modules/devtools/server/actors/childtab.js"); this.addActors("resource://gre/modules/devtools/server/actors/childtab.js");

Просмотреть файл

@ -154,9 +154,10 @@ function attachTestTab(aClient, aTitle, aCallback) {
// thread. // thread.
function attachTestThread(aClient, aTitle, aCallback) { function attachTestThread(aClient, aTitle, aCallback) {
attachTestTab(aClient, aTitle, function (aResponse, aTabClient) { attachTestTab(aClient, aTitle, function (aResponse, aTabClient) {
aClient.attachThread(aResponse.threadActor, function (aResponse, aThreadClient) { function onAttach(aResponse, aThreadClient) {
aCallback(aResponse, aTabClient, aThreadClient); aCallback(aResponse, aTabClient, aThreadClient);
}, { useSourceMaps: true }); }
aTabClient.attachThread({ useSourceMaps: true }, onAttach);
}); });
} }

Просмотреть файл

@ -14,15 +14,15 @@ function run_test()
gClient = new DebuggerClient(transport); gClient = new DebuggerClient(transport);
gClient.connect(function(aType, aTraits) { gClient.connect(function(aType, aTraits) {
attachTestTab(gClient, "test-1", function(aReply, aTabClient) { attachTestTab(gClient, "test-1", function(aReply, aTabClient) {
test_attach(aReply.threadActor); test_attach(aTabClient);
}); });
}); });
do_test_pending(); do_test_pending();
} }
function test_attach(aThreadActorID) function test_attach(aTabClient)
{ {
gClient.attachThread(aThreadActorID, function(aResponse, aThreadClient) { aTabClient.attachThread({}, function(aResponse, aThreadClient) {
do_check_eq(aThreadClient.state, "paused"); do_check_eq(aThreadClient.state, "paused");
aThreadClient.resume(cleanup); aThreadClient.resume(cleanup);
}); });

Просмотреть файл

@ -43,12 +43,12 @@ function setUpCode() {
} }
function setBreakpoint() { function setBreakpoint() {
gClient.addOneTimeListener("resumed", runCode);
gThreadClient.setBreakpoint({ gThreadClient.setBreakpoint({
url: URL, url: URL,
line: 1 line: 1
}, ({ error }) => { }, ({ error }) => {
do_check_true(!error); do_check_true(!error);
gThreadClient.resume(runCode);
}); });
} }

Просмотреть файл

@ -5,6 +5,7 @@ Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
Cu.import("resource://gre/modules/devtools/dbg-client.jsm"); Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
var gClient; var gClient;
var gTabClient;
var gDebuggee; var gDebuggee;
function run_test() function run_test()
@ -17,6 +18,7 @@ function run_test()
gClient = new DebuggerClient(transport); gClient = new DebuggerClient(transport);
gClient.connect(function(aType, aTraits) { gClient.connect(function(aType, aTraits) {
attachTestTab(gClient, "test-1", function(aReply, aTabClient) { attachTestTab(gClient, "test-1", function(aReply, aTabClient) {
gTabClient = aTabClient;
test_threadAttach(aReply.threadActor); test_threadAttach(aReply.threadActor);
}); });
}); });
@ -26,7 +28,7 @@ function run_test()
function test_threadAttach(aThreadActorID) function test_threadAttach(aThreadActorID)
{ {
do_print("Trying to attach to thread " + aThreadActorID); do_print("Trying to attach to thread " + aThreadActorID);
gClient.attachThread(aThreadActorID, function(aResponse, aThreadClient) { gTabClient.attachThread({}, function(aResponse, aThreadClient) {
do_check_eq(aThreadClient.state, "paused"); do_check_eq(aThreadClient.state, "paused");
do_check_eq(aThreadClient.actor, aThreadActorID); do_check_eq(aThreadClient.actor, aThreadActorID);
aThreadClient.resume(function() { aThreadClient.resume(function() {

Просмотреть файл

@ -20,21 +20,21 @@ function run_test()
function test_attach(aResponse, aTabClient) function test_attach(aResponse, aTabClient)
{ {
gClient.attachThread(aResponse.threadActor, function(aResponse, aThreadClient) { aTabClient.attachThread({}, function(aResponse, aThreadClient) {
do_check_eq(aThreadClient.paused, true); do_check_eq(aThreadClient.paused, true);
aThreadClient.resume(function() { aThreadClient.resume(function() {
test_interrupt(); test_interrupt(aThreadClient);
}); });
}); });
} }
function test_interrupt() function test_interrupt(aThreadClient)
{ {
do_check_eq(gClient.activeThread.paused, false); do_check_eq(aThreadClient.paused, false);
gClient.activeThread.interrupt(function(aResponse) { aThreadClient.interrupt(function(aResponse) {
do_check_eq(gClient.activeThread.paused, true); do_check_eq(aThreadClient.paused, true);
gClient.activeThread.resume(function() { aThreadClient.resume(function() {
do_check_eq(gClient.activeThread.paused, false); do_check_eq(aThreadClient.paused, false);
cleanup(); cleanup();
}); });
}); });

Просмотреть файл

@ -5,7 +5,7 @@
// Test that we can detect nested event loops in tabs with the same URL. // Test that we can detect nested event loops in tabs with the same URL.
const { defer } = devtools.require("sdk/core/promise"); const { defer } = devtools.require("sdk/core/promise");
var gClient1, gClient2; var gClient1, gClient2, gThreadClient1, gThreadClient2;
function run_test() { function run_test() {
initTestDebuggerServer(); initTestDebuggerServer();
@ -15,6 +15,7 @@ function run_test() {
gClient1 = new DebuggerClient(DebuggerServer.connectPipe()); gClient1 = new DebuggerClient(DebuggerServer.connectPipe());
gClient1.connect(function () { gClient1.connect(function () {
attachTestThread(gClient1, "test-nesting1", function (aResponse, aTabClient, aThreadClient) { attachTestThread(gClient1, "test-nesting1", function (aResponse, aTabClient, aThreadClient) {
gThreadClient1 = aThreadClient;
start_second_connection(); start_second_connection();
}); });
}); });
@ -25,6 +26,7 @@ function start_second_connection() {
gClient2 = new DebuggerClient(DebuggerServer.connectPipe()); gClient2 = new DebuggerClient(DebuggerServer.connectPipe());
gClient2.connect(function () { gClient2.connect(function () {
attachTestThread(gClient2, "test-nesting1", function (aResponse, aTabClient, aThreadClient) { attachTestThread(gClient2, "test-nesting1", function (aResponse, aTabClient, aThreadClient) {
gThreadClient2 = aThreadClient;
test_nesting(); test_nesting();
}); });
}); });
@ -33,15 +35,15 @@ function start_second_connection() {
function test_nesting() { function test_nesting() {
const { resolve, reject, promise } = defer(); const { resolve, reject, promise } = defer();
gClient1.activeThread.resume(aResponse => { gThreadClient1.resume(aResponse => {
do_check_eq(aResponse.error, "wrongOrder"); do_check_eq(aResponse.error, "wrongOrder");
gClient2.activeThread.resume(aResponse => { gThreadClient2.resume(aResponse => {
do_check_true(!aResponse.error); do_check_true(!aResponse.error);
do_check_eq(aResponse.from, gClient2.activeThread.actor); do_check_eq(aResponse.from, gThreadClient2.actor);
gClient1.activeThread.resume(aResponse => { gThreadClient1.resume(aResponse => {
do_check_true(!aResponse.error); do_check_true(!aResponse.error);
do_check_eq(aResponse.from, gClient1.activeThread.actor); do_check_eq(aResponse.from, gThreadClient1.actor);
gClient1.close(() => finishClient(gClient2)); gClient1.close(() => finishClient(gClient2));
}); });

Просмотреть файл

@ -59,7 +59,7 @@ function test_definition_site(func, obj) {
function test_bad_definition_site(obj) { function test_bad_definition_site(obj) {
try { try {
obj.getDefinitionSite(() => do_check_true(false)); obj._client.request("definitionSite", () => do_check_true(false));
} catch (e) { } catch (e) {
gThreadClient.resume(() => finishClient(gClient)); gThreadClient.resume(() => finishClient(gClient));
} }

Просмотреть файл

@ -0,0 +1,58 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that reattaching to a previously detached thread works.
*/
var gClient, gDebuggee, gThreadClient, gTabClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = testGlobal("test-reattach");
DebuggerServer.addTestGlobal(gDebuggee);
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect(() => {
attachTestTab(gClient, "test-reattach", (aReply, aTabClient) => {
gTabClient = aTabClient;
test_attach();
});
});
do_test_pending();
}
function test_attach()
{
gTabClient.attachThread({}, (aResponse, aThreadClient) => {
do_check_eq(aThreadClient.state, "paused");
gThreadClient = aThreadClient;
aThreadClient.resume(test_detach);
});
}
function test_detach()
{
gThreadClient.detach(() => {
do_check_eq(gThreadClient.state, "detached");
do_check_eq(gTabClient.thread, null);
test_reattach();
});
}
function test_reattach()
{
gTabClient.attachThread({}, (aResponse, aThreadClient) => {
do_check_neq(gThreadClient, aThreadClient);
do_check_eq(aThreadClient.state, "paused");
do_check_eq(gTabClient.thread, aThreadClient);
aThreadClient.resume(cleanup);
});
}
function cleanup()
{
gClient.close(do_test_finished);
}

Просмотреть файл

@ -30,6 +30,7 @@ reason = bug 821285
[test_dbgglobal.js] [test_dbgglobal.js]
[test_dbgclient_debuggerstatement.js] [test_dbgclient_debuggerstatement.js]
[test_attach.js] [test_attach.js]
[test_reattach-thread.js]
[test_blackboxing-01.js] [test_blackboxing-01.js]
[test_blackboxing-02.js] [test_blackboxing-02.js]
[test_blackboxing-03.js] [test_blackboxing-03.js]