Bug 723563 - Use findScripts to retrieve the list of scripts known to the debugger; r=rcampbell

This commit is contained in:
Panos Astithas 2012-02-23 10:39:02 +02:00
parent 4743dd2932
commit 32e33cb96d
15 changed files with 54 additions and 105 deletions

View File

@ -311,6 +311,10 @@ var StackFrames = {
paramVar.setGrip(paramVal); paramVar.setGrip(paramVal);
this._addExpander(paramVar, paramVal); this._addExpander(paramVar, paramVal);
} }
// Signal that call parameters have been fetched.
let evt = document.createEvent("Event");
evt.initEvent("Debugger:FetchedParameters", true, false);
document.documentElement.dispatchEvent(evt);
}.bind(this)); }.bind(this));
} }
}, },
@ -469,11 +473,13 @@ var SourceScripts = {
DebuggerView.Scripts.addChangeListener(this.onChange); DebuggerView.Scripts.addChangeListener(this.onChange);
this.activeThread = aThreadClient; this.activeThread = aThreadClient;
aThreadClient.addListener("paused", this.onPaused);
aThreadClient.addListener("scriptsadded", this.onScripts); aThreadClient.addListener("scriptsadded", this.onScripts);
aThreadClient.addListener("scriptscleared", this.onScriptsCleared); aThreadClient.addListener("scriptscleared", this.onScriptsCleared);
this.clearLabelsCache(); this.clearLabelsCache();
this.onScriptsCleared(); this.onScriptsCleared();
// Retrieve the list of scripts known to the server from before the client
// was ready to handle new script notifications.
this.activeThread.fillScripts();
aCallback && aCallback(); aCallback && aCallback();
}, },
@ -481,21 +487,10 @@ var SourceScripts = {
* Disconnect from the client. * Disconnect from the client.
*/ */
disconnect: function TS_disconnect() { disconnect: function TS_disconnect() {
this.activeThread.removeListener("paused", this.onPaused);
this.activeThread.removeListener("scriptsadded", this.onScripts); this.activeThread.removeListener("scriptsadded", this.onScripts);
this.activeThread.removeListener("scriptscleared", this.onScriptsCleared); this.activeThread.removeListener("scriptscleared", this.onScriptsCleared);
}, },
/**
* Handler for the thread client's paused notification. This is triggered only
* once, to retrieve the list of scripts known to the server from before the
* client was ready to handle new script notifications.
*/
onPaused: function SS_onPaused() {
this.activeThread.removeListener("paused", this.onPaused);
this.activeThread.fillScripts();
},
/** /**
* Handler for the debugger client's unsolicited newScript notification. * Handler for the debugger client's unsolicited newScript notification.
*/ */
@ -657,7 +652,6 @@ var SourceScripts = {
} }
}; };
SourceScripts.onPaused = SourceScripts.onPaused.bind(SourceScripts);
SourceScripts.onScripts = SourceScripts.onScripts.bind(SourceScripts); SourceScripts.onScripts = SourceScripts.onScripts.bind(SourceScripts);
SourceScripts.onNewScript = SourceScripts.onNewScript.bind(SourceScripts); SourceScripts.onNewScript = SourceScripts.onNewScript.bind(SourceScripts);
SourceScripts.onScriptsCleared = SourceScripts.onScriptsCleared.bind(SourceScripts); SourceScripts.onScriptsCleared = SourceScripts.onScriptsCleared.bind(SourceScripts);

View File

@ -28,7 +28,7 @@ function test()
gPane = aPane; gPane = aPane;
gDebugger = gPane.debuggerWindow; gDebugger = gPane.debuggerWindow;
gPane.activeThread.addOneTimeListener("scriptsadded", function() { gPane.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: onScriptsAdded }, 0); Services.tm.currentThread.dispatch({ run: onScriptsAdded }, 0);
}); });
gDebuggee.firstCall(); gDebuggee.firstCall();

View File

@ -26,7 +26,7 @@ function test()
gPane = aPane; gPane = aPane;
gDebugger = gPane.debuggerWindow; gDebugger = gPane.debuggerWindow;
gPane.activeThread.addOneTimeListener("scriptsadded", function() { gPane.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: onScriptsAdded }, 0); Services.tm.currentThread.dispatch({ run: onScriptsAdded }, 0);
}); });
gDebuggee.firstCall(); gDebuggee.firstCall();

View File

@ -32,8 +32,7 @@ function test_early_debugger_statement(aActor)
gClient.addListener("paused", paused); gClient.addListener("paused", paused);
// This should continue without nesting an event loop and calling // This should continue without nesting an event loop and calling
// the onPaused hook, because we haven't attached yet. // the onPaused hook, because we haven't attached yet.
// TODO: uncomment this when bug 723563 is fixed. gTab.linkedBrowser.contentWindow.wrappedJSObject.runDebuggerStatement();
//gTab.linkedBrowser.contentWindow.wrappedJSObject.runDebuggerStatement();
gClient.removeListener("paused", paused); gClient.removeListener("paused", paused);

View File

@ -87,7 +87,7 @@ function test_attach_removed_tab()
}); });
gClient.request({ to: gTab2Actor, type: "attach" }, function(aResponse) { gClient.request({ to: gTab2Actor, type: "attach" }, function(aResponse) {
is(aResponse.error, "noSuchActor", "Tab should be gone."); is(aResponse.type, "exited", "Tab should consider itself exited.");
finish_test(); finish_test();
}); });
} }

View File

@ -85,6 +85,7 @@ function resumeAndFinish() {
gDebugger.StackFrames.activeThread.resume(function() { gDebugger.StackFrames.activeThread.resume(function() {
let vs = gDebugger.DebuggerView.Scripts; let vs = gDebugger.DebuggerView.Scripts;
let ss = gDebugger.SourceScripts; let ss = gDebugger.SourceScripts;
ss.onScriptsCleared();
is(ss._trimUrlQuery("a/b/c.d?test=1&random=4"), "a/b/c.d", is(ss._trimUrlQuery("a/b/c.d?test=1&random=4"), "a/b/c.d",
"Trimming the url query isn't done properly."); "Trimming the url query isn't done properly.");

View File

@ -25,9 +25,8 @@ function test()
function testFrameParameters() function testFrameParameters()
{ {
// scriptsadded is fired last when switching to a paused state, so the gDebugger.addEventListener("Debugger:FetchedParameters", function test() {
// property view will have had a chance to fetch the call parameters. gDebugger.removeEventListener("Debugger:FetchedParameters", test, false);
gPane.activeThread.addOneTimeListener("scriptsadded", function() {
Services.tm.currentThread.dispatch({ run: function() { Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.Stackframes._frames, var frames = gDebugger.DebuggerView.Stackframes._frames,
@ -70,7 +69,7 @@ function testFrameParameters()
resumeAndFinish(); resumeAndFinish();
}}, 0); }}, 0);
}); }, false);
EventUtils.sendMouseEvent({ type: "click" }, EventUtils.sendMouseEvent({ type: "click" },
content.document.querySelector("button"), content.document.querySelector("button"),

View File

@ -25,9 +25,8 @@ function test()
function testFrameParameters() function testFrameParameters()
{ {
// scriptsadded is fired last when switching to a paused state, so the gDebugger.addEventListener("Debugger:FetchedParameters", function test() {
// property view will have had a chance to fetch the call parameters. gDebugger.removeEventListener("Debugger:FetchedParameters", test, false);
gPane.activeThread.addOneTimeListener("scriptsadded", function() {
Services.tm.currentThread.dispatch({ run: function() { Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.Stackframes._frames, var frames = gDebugger.DebuggerView.Stackframes._frames,
@ -86,7 +85,7 @@ function testFrameParameters()
resumeAndFinish(); resumeAndFinish();
}, 100); }, 100);
}}, 0); }}, 0);
}); }, false);
EventUtils.synthesizeMouseAtCenter(content.document.querySelector("button"), EventUtils.synthesizeMouseAtCenter(content.document.querySelector("button"),
{}, {},

View File

@ -31,7 +31,7 @@ function test()
} }
function testScriptsDisplay() { function testScriptsDisplay() {
gPane.activeThread.addOneTimeListener("scriptsadded", function() { gPane.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() { Services.tm.currentThread.dispatch({ run: function() {
gScripts = gDebugger.DebuggerView.Scripts._scripts; gScripts = gDebugger.DebuggerView.Scripts._scripts;

View File

@ -26,7 +26,7 @@ function test() {
} }
function testRecurse() { function testRecurse() {
gPane.activeThread.addOneTimeListener("scriptsadded", function() { gPane.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() { Services.tm.currentThread.dispatch({ run: function() {
let frames = gDebugger.DebuggerView.Stackframes._frames; let frames = gDebugger.DebuggerView.Stackframes._frames;
let childNodes = frames.childNodes; let childNodes = frames.childNodes;

View File

@ -31,7 +31,7 @@ function test()
} }
function testScriptsDisplay() { function testScriptsDisplay() {
gPane.activeThread.addOneTimeListener("scriptsadded", function() { gPane.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() { Services.tm.currentThread.dispatch({ run: function() {
gScripts = gDebugger.DebuggerView.Scripts._scripts; gScripts = gDebugger.DebuggerView.Scripts._scripts;

View File

@ -73,7 +73,7 @@ function testCreateCommands() {
// Wait for the initial resume. // Wait for the initial resume.
aPane.debuggerWindow.gClient.addOneTimeListener("resumed", function() { aPane.debuggerWindow.gClient.addOneTimeListener("resumed", function() {
delete aPane.onConnected; delete aPane.onConnected;
aPane.debuggerWindow.gClient.activeThread.addOneTimeListener("scriptsadded", function() { aPane.debuggerWindow.gClient.activeThread.addOneTimeListener("framesadded", function() {
type("break add line " + TEST_URI + " " + content.wrappedJSObject.line0); type("break add line " + TEST_URI + " " + content.wrappedJSObject.line0);
is(requisition.getStatus().toString(), "VALID", "break add line is VALID"); is(requisition.getStatus().toString(), "VALID", "break add line is VALID");
requisition.exec(); requisition.exec();

View File

@ -30,7 +30,7 @@ localScope=Local
# pane as a header on the globel scope container. # pane as a header on the globel scope container.
globalScope=Global globalScope=Global
# LOCALIZATION NOTE (localScope): The label that is displayed in the variables # LOCALIZATION NOTE (withScope): The label that is displayed in the variables
# pane as a header on the container for identifiers in a with block. # pane as a header on the container for identifiers in a with block.
withScope=With block withScope=With block

View File

@ -67,7 +67,6 @@ function BrowserRootActor(aConnection)
this._actorFactories = null; this._actorFactories = null;
this.onTabClosed = this.onTabClosed.bind(this); this.onTabClosed = this.onTabClosed.bind(this);
this._onWindowCreated = this.onWindowCreated.bind(this);
windowMediator.addListener(this); windowMediator.addListener(this);
} }
@ -76,10 +75,6 @@ BrowserRootActor.prototype = {
* Return a 'hello' packet as specified by the Remote Debugging Protocol. * Return a 'hello' packet as specified by the Remote Debugging Protocol.
*/ */
sayHello: function BRA_sayHello() { sayHello: function BRA_sayHello() {
// Create the tab actor for the selected tab right away so that it gets a
// chance to listen to onNewScript notifications.
this._preInitTabActor();
return { from: "root", return { from: "root",
applicationType: "browser", applicationType: "browser",
traits: [] }; traits: [] };
@ -123,6 +118,10 @@ BrowserRootActor.prototype = {
while (e.hasMoreElements()) { while (e.hasMoreElements()) {
let win = e.getNext(); let win = e.getNext();
// Watch the window for tab closes so we can invalidate
// actors as needed.
this.watchWindow(win);
// List the tabs in this browser. // List the tabs in this browser.
let selectedBrowser = win.getBrowser().selectedBrowser; let selectedBrowser = win.getBrowser().selectedBrowser;
let browsers = win.getBrowser().browsers; let browsers = win.getBrowser().browsers;
@ -183,61 +182,16 @@ BrowserRootActor.prototype = {
this.exitTabActor(aEvent.target.linkedBrowser); this.exitTabActor(aEvent.target.linkedBrowser);
}, },
/**
* Handle location changes, by preinitializing a tab actor.
*/
onWindowCreated: function BRA_onWindowCreated(evt) {
if (evt.target === this.browser.contentDocument) {
this._preInitTabActor();
}
},
/** /**
* Exit the tab actor of the specified tab. * Exit the tab actor of the specified tab.
*/ */
exitTabActor: function BRA_exitTabActor(aWindow) { exitTabActor: function BRA_exitTabActor(aWindow) {
this.browser.removeEventListener("DOMWindowCreated", this._onWindowCreated, true);
let actor = this._tabActors.get(aWindow); let actor = this._tabActors.get(aWindow);
if (actor) { if (actor) {
actor.exit(); actor.exit();
} }
}, },
/**
* Create the tab actor in the selected tab right away so that it gets a
* chance to listen to onNewScript notifications.
*/
_preInitTabActor: function BRA__preInitTabActor() {
let actorPool = new ActorPool(this.conn);
// Walk over open browser windows.
let e = windowMediator.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
let win = e.getNext();
// Watch the window for tab closes so we can invalidate
// actors as needed.
this.watchWindow(win);
this.browser = win.getBrowser().selectedBrowser;
let actor = this._tabActors.get(this.browser);
if (actor) {
actor._detach();
}
actor = new BrowserTabActor(this.conn, this.browser);
actor.parentID = this.actorID;
this._tabActors.set(this.browser, actor);
actorPool.addActor(actor);
}
this._tabActorPool = actorPool;
this.conn.addActorPool(this._tabActorPool);
// Watch for globals being created in this tab.
this.browser.addEventListener("DOMWindowCreated", this._onWindowCreated, true);
},
// nsIWindowMediatorListener // nsIWindowMediatorListener
onWindowTitleChange: function BRA_onWindowTitleChange(aWindow, aTitle) { }, onWindowTitleChange: function BRA_onWindowTitleChange(aWindow, aTitle) { },
onOpenWindow: function BRA_onOpenWindow(aWindow) { }, onOpenWindow: function BRA_onOpenWindow(aWindow) { },
@ -270,7 +224,6 @@ function BrowserTabActor(aConnection, aBrowser)
this._browser = aBrowser; this._browser = aBrowser;
this._onWindowCreated = this.onWindowCreated.bind(this); this._onWindowCreated = this.onWindowCreated.bind(this);
this._attach();
} }
// XXX (bug 710213): BrowserTabActor attach/detach/exit/disconnect is a // XXX (bug 710213): BrowserTabActor attach/detach/exit/disconnect is a
@ -341,7 +294,7 @@ BrowserTabActor.prototype = {
this._pushContext(); this._pushContext();
// Watch for globals being created in this tab. // Watch for globals being created in this tab.
this.browser.addEventListener("DOMWindowCreated", this._onWindowCreated, false); this.browser.addEventListener("DOMWindowCreated", this._onWindowCreated, true);
this._attached = true; this._attached = true;
}, },
@ -382,7 +335,7 @@ BrowserTabActor.prototype = {
return; return;
} }
this.browser.removeEventListener("DOMWindowCreated", this._onWindowCreated, false); this.browser.removeEventListener("DOMWindowCreated", this._onWindowCreated, true);
this._popContext(); this._popContext();

View File

@ -99,19 +99,12 @@ ThreadActor.prototype = {
this._dbg = new Debugger(); this._dbg = new Debugger();
} }
// TODO: Remove this horrible hack when bug 723563 is fixed.
// Make sure that a chrome window is not added as a debuggee when opening
// the debugger in an empty tab or during tests.
if (aGlobal.location &&
(aGlobal.location.protocol == "about:" ||
aGlobal.location.protocol == "chrome:")) {
return;
}
this.dbg.addDebuggee(aGlobal); this.dbg.addDebuggee(aGlobal);
this.dbg.uncaughtExceptionHook = this.uncaughtExceptionHook.bind(this); this.dbg.uncaughtExceptionHook = this.uncaughtExceptionHook.bind(this);
this.dbg.onDebuggerStatement = this.onDebuggerStatement.bind(this); this.dbg.onDebuggerStatement = this.onDebuggerStatement.bind(this);
this.dbg.onNewScript = this.onNewScript.bind(this); this.dbg.onNewScript = this.onNewScript.bind(this);
// Keep the debugger disabled until a client attaches.
this.dbg.enabled = false;
}, },
/** /**
@ -503,6 +496,11 @@ ThreadActor.prototype = {
* Handle a protocol request to return the list of loaded scripts. * Handle a protocol request to return the list of loaded scripts.
*/ */
onScripts: function TA_onScripts(aRequest) { onScripts: function TA_onScripts(aRequest) {
// Get the script list from the debugger.
for (let s of this.dbg.findScripts()) {
this._addScript(s);
}
// Build the cache.
let scripts = []; let scripts = [];
for (let url in this._scripts) { for (let url in this._scripts) {
for (let i = 0; i < this._scripts[url].length; i++) { for (let i = 0; i < this._scripts[url].length; i++) {
@ -859,28 +857,34 @@ ThreadActor.prototype = {
}, },
/** /**
* A function that the engine calls when a new script has been loaded into a * A function that the engine calls when a new script has been loaded into the
* debuggee compartment. If the new code is part of a function, aFunction is * scope of the specified debuggee global.
* a Debugger.Object reference to the function object. (Not all code is part
* of a function; for example, the code appearing in a <script> tag that is
* outside of any functions defined in that tag would be passed to
* onNewScript without an accompanying function argument.)
* *
* @param aScript Debugger.Script * @param aScript Debugger.Script
* The source script that has been loaded into a debuggee compartment. * The source script that has been loaded into a debuggee compartment.
* @param aFunction Debugger.Object * @param aGlobal Debugger.Object
* The function object that the ew code is part of. * A Debugger.Object instance whose referent is the global object.
*/ */
onNewScript: function TA_onNewScript(aScript, aFunction) { onNewScript: function TA_onNewScript(aScript, aGlobal) {
this._addScript(aScript);
// Notify the client.
this.conn.send({ from: this.actorID, type: "newScript",
url: aScript.url, startLine: aScript.startLine });
},
/**
* Add the provided script to the server cache.
*
* @param aScript Debugger.Script
* The source script that will be stored.
*/
_addScript: function TA__addScript(aScript) {
// Use a sparse array for storing the scripts for each URL in order to // Use a sparse array for storing the scripts for each URL in order to
// optimize retrieval. // optimize retrieval.
if (!this._scripts[aScript.url]) { if (!this._scripts[aScript.url]) {
this._scripts[aScript.url] = []; this._scripts[aScript.url] = [];
} }
this._scripts[aScript.url][aScript.startLine] = aScript; this._scripts[aScript.url][aScript.startLine] = aScript;
// Notify the client.
this.conn.send({ from: this.actorID, type: "newScript",
url: aScript.url, startLine: aScript.startLine });
} }
}; };