mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 897567 - JS debugger: setting breakpoints can be confused by script GC. r=fitzgen
This commit is contained in:
parent
3882a241d1
commit
14e008b382
@ -1757,14 +1757,17 @@ ThreadClient.prototype = {
|
|||||||
this.client.request(packet, (aResponse) => {
|
this.client.request(packet, (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) {
|
let bpClient;
|
||||||
|
if (aResponse.actor) {
|
||||||
let root = this.client.mainRoot;
|
let root = this.client.mainRoot;
|
||||||
let bpClient = new BreakpointClient(
|
bpClient = new BreakpointClient(
|
||||||
this.client,
|
this.client,
|
||||||
aResponse.actor,
|
aResponse.actor,
|
||||||
location,
|
location,
|
||||||
root.traits.conditionalBreakpoints ? condition : undefined
|
root.traits.conditionalBreakpoints ? condition : undefined
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
if (aOnResponse) {
|
||||||
aOnResponse(aResponse, bpClient);
|
aOnResponse(aResponse, bpClient);
|
||||||
}
|
}
|
||||||
if (aCallback) {
|
if (aCallback) {
|
||||||
|
@ -98,7 +98,7 @@ BreakpointStore.prototype = {
|
|||||||
get size() { return this._size; },
|
get size() { return this._size; },
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a breakpoint to the breakpoint store.
|
* Add a breakpoint to the breakpoint store if it doesn't already exist.
|
||||||
*
|
*
|
||||||
* @param Object aBreakpoint
|
* @param Object aBreakpoint
|
||||||
* The breakpoint to be added (not copied). It is an object with the
|
* The breakpoint to be added (not copied). It is an object with the
|
||||||
@ -109,10 +109,11 @@ BreakpointStore.prototype = {
|
|||||||
* the whole line)
|
* the whole line)
|
||||||
* - condition (optional)
|
* - condition (optional)
|
||||||
* - actor (optional)
|
* - actor (optional)
|
||||||
|
* @returns Object aBreakpoint
|
||||||
|
* The new or existing breakpoint.
|
||||||
*/
|
*/
|
||||||
addBreakpoint: function (aBreakpoint) {
|
addBreakpoint: function (aBreakpoint) {
|
||||||
let { url, line, column } = aBreakpoint;
|
let { url, line, column } = aBreakpoint;
|
||||||
let updating = false;
|
|
||||||
|
|
||||||
if (column != null) {
|
if (column != null) {
|
||||||
if (!this._breakpoints[url]) {
|
if (!this._breakpoints[url]) {
|
||||||
@ -121,16 +122,22 @@ BreakpointStore.prototype = {
|
|||||||
if (!this._breakpoints[url][line]) {
|
if (!this._breakpoints[url][line]) {
|
||||||
this._breakpoints[url][line] = [];
|
this._breakpoints[url][line] = [];
|
||||||
}
|
}
|
||||||
this._breakpoints[url][line][column] = aBreakpoint;
|
if (!this._breakpoints[url][line][column]) {
|
||||||
|
this._breakpoints[url][line][column] = aBreakpoint;
|
||||||
|
this._size++;
|
||||||
|
}
|
||||||
|
return this._breakpoints[url][line][column];
|
||||||
} else {
|
} else {
|
||||||
// Add a breakpoint that breaks on the whole line.
|
// Add a breakpoint that breaks on the whole line.
|
||||||
if (!this._wholeLineBreakpoints[url]) {
|
if (!this._wholeLineBreakpoints[url]) {
|
||||||
this._wholeLineBreakpoints[url] = [];
|
this._wholeLineBreakpoints[url] = [];
|
||||||
}
|
}
|
||||||
this._wholeLineBreakpoints[url][line] = aBreakpoint;
|
if (!this._wholeLineBreakpoints[url][line]) {
|
||||||
|
this._wholeLineBreakpoints[url][line] = aBreakpoint;
|
||||||
|
this._size++;
|
||||||
|
}
|
||||||
|
return this._wholeLineBreakpoints[url][line];
|
||||||
}
|
}
|
||||||
|
|
||||||
this._size++;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1439,9 +1446,7 @@ ThreadActor.prototype = {
|
|||||||
|
|
||||||
let locationPromise = this.sources.getGeneratedLocation(aRequest.location);
|
let locationPromise = this.sources.getGeneratedLocation(aRequest.location);
|
||||||
return locationPromise.then(({url, line, column}) => {
|
return locationPromise.then(({url, line, column}) => {
|
||||||
if (line == null ||
|
if (line == null || line < 0) {
|
||||||
line < 0 ||
|
|
||||||
this.dbg.findScripts({ url: url }).length == 0) {
|
|
||||||
return {
|
return {
|
||||||
error: "noScript",
|
error: "noScript",
|
||||||
message: "Requested setting a breakpoint on "
|
message: "Requested setting a breakpoint on "
|
||||||
@ -1537,12 +1542,11 @@ ThreadActor.prototype = {
|
|||||||
// Find all scripts matching the given location
|
// Find all scripts matching the given location
|
||||||
let scripts = this.dbg.findScripts(aLocation);
|
let scripts = this.dbg.findScripts(aLocation);
|
||||||
if (scripts.length == 0) {
|
if (scripts.length == 0) {
|
||||||
|
// Since we did not find any scripts to set the breakpoint on now, return
|
||||||
|
// early. When a new script that matches this breakpoint location is
|
||||||
|
// introduced, the breakpoint actor will already be in the breakpoint store
|
||||||
|
// and will be set at that time.
|
||||||
return {
|
return {
|
||||||
error: "noScript",
|
|
||||||
message: "Requested setting a breakpoint on "
|
|
||||||
+ aLocation.url + ":" + aLocation.line
|
|
||||||
+ (aLocation.column != null ? ":" + aLocation.column : "")
|
|
||||||
+ " but there is no Debugger.Script at that location",
|
|
||||||
actor: actor.actorID
|
actor: actor.actorID
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -510,6 +510,17 @@ function resume(threadClient) {
|
|||||||
return rdpRequest(threadClient, threadClient.resume);
|
return rdpRequest(threadClient, threadClient.resume);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interrupt JS execution for the specified thread.
|
||||||
|
*
|
||||||
|
* @param ThreadClient threadClient
|
||||||
|
* @returns Promise
|
||||||
|
*/
|
||||||
|
function interrupt(threadClient) {
|
||||||
|
dumpn("Interrupting.");
|
||||||
|
return rdpRequest(threadClient, threadClient.interrupt);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resume JS execution for the specified thread and then wait for the next pause
|
* Resume JS execution for the specified thread and then wait for the next pause
|
||||||
* event.
|
* event.
|
||||||
|
@ -8,62 +8,65 @@
|
|||||||
var gDebuggee;
|
var gDebuggee;
|
||||||
var gClient;
|
var gClient;
|
||||||
var gThreadClient;
|
var gThreadClient;
|
||||||
var gCallback;
|
|
||||||
|
|
||||||
function run_test()
|
function run_test()
|
||||||
{
|
{
|
||||||
run_test_with_server(DebuggerServer, function () {
|
initTestDebuggerServer();
|
||||||
run_test_with_server(WorkerDebuggerServer, do_test_finished);
|
gDebuggee = addTestGlobal("test-stack");
|
||||||
});
|
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||||
do_test_pending();
|
|
||||||
};
|
|
||||||
|
|
||||||
function run_test_with_server(aServer, aCallback)
|
|
||||||
{
|
|
||||||
gCallback = aCallback;
|
|
||||||
initTestDebuggerServer(aServer);
|
|
||||||
gDebuggee = addTestGlobal("test-stack", aServer);
|
|
||||||
gClient = new DebuggerClient(aServer.connectPipe());
|
|
||||||
gClient.connect(function () {
|
gClient.connect(function () {
|
||||||
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
|
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
|
||||||
gThreadClient = aThreadClient;
|
gThreadClient = aThreadClient;
|
||||||
test_same_breakpoint();
|
testSameBreakpoint();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
do_test_pending();
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_same_breakpoint()
|
|
||||||
{
|
|
||||||
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
|
|
||||||
let path = getFilePath('test_breakpoint-01.js');
|
|
||||||
let location = {
|
|
||||||
url: path,
|
|
||||||
line: gDebuggee.line0 + 3
|
|
||||||
};
|
|
||||||
gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
|
|
||||||
gThreadClient.setBreakpoint(location, function (aResponse, secondBpClient) {
|
|
||||||
do_check_eq(bpClient.actor, secondBpClient.actor,
|
|
||||||
"Should get the same actor w/ whole line breakpoints");
|
|
||||||
let location = {
|
|
||||||
url: path,
|
|
||||||
line: gDebuggee.line0 + 2,
|
|
||||||
column: 6
|
|
||||||
};
|
|
||||||
gThreadClient.setBreakpoint(location, function (aResponse, bpClient) {
|
|
||||||
gThreadClient.setBreakpoint(location, function (aResponse, secondBpClient) {
|
|
||||||
do_check_eq(bpClient.actor, secondBpClient.actor,
|
|
||||||
"Should get the same actor column breakpoints");
|
|
||||||
gClient.close(gCallback);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
const SOURCE_URL = "http://example.com/source.js";
|
||||||
|
|
||||||
Components.utils.evalInSandbox("var line0 = Error().lineNumber;\n" +
|
const testSameBreakpoint = Task.async(function* () {
|
||||||
"debugger;\n" + // line0 + 1
|
yield executeOnNextTickAndWaitForPause(evalCode, gClient);
|
||||||
"var a = 1;\n" + // line0 + 2
|
|
||||||
"var b = 2;\n", // line0 + 3
|
// Whole line
|
||||||
gDebuggee);
|
|
||||||
}
|
let wholeLineLocation = {
|
||||||
|
url: SOURCE_URL,
|
||||||
|
line: 2
|
||||||
|
};
|
||||||
|
|
||||||
|
let [firstResponse, firstBpClient] = yield setBreakpoint(gThreadClient, wholeLineLocation);
|
||||||
|
let [secondResponse, secondBpClient] = yield setBreakpoint(gThreadClient, wholeLineLocation);
|
||||||
|
|
||||||
|
do_check_eq(firstBpClient.actor, secondBpClient.actor, "Should get the same actor w/ whole line breakpoints");
|
||||||
|
|
||||||
|
// Specific column
|
||||||
|
|
||||||
|
let columnLocation = {
|
||||||
|
url: SOURCE_URL,
|
||||||
|
line: 2,
|
||||||
|
column: 6
|
||||||
|
};
|
||||||
|
|
||||||
|
let [firstResponse, firstBpClient] = yield setBreakpoint(gThreadClient, columnLocation);
|
||||||
|
let [secondResponse, secondBpClient] = yield setBreakpoint(gThreadClient, columnLocation);
|
||||||
|
|
||||||
|
do_check_eq(secondBpClient.actor, secondBpClient.actor, "Should get the same actor column breakpoints");
|
||||||
|
|
||||||
|
finishClient(gClient);
|
||||||
|
});
|
||||||
|
|
||||||
|
function evalCode() {
|
||||||
|
Components.utils.evalInSandbox(
|
||||||
|
"" + function doStuff(k) { // line 1
|
||||||
|
let arg = 15; // line 2 - Step in here
|
||||||
|
k(arg); // line 3
|
||||||
|
} + "\n" // line 4
|
||||||
|
+ "debugger;", // line 5
|
||||||
|
gDebuggee,
|
||||||
|
"1.8",
|
||||||
|
SOURCE_URL,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
}
|
69
toolkit/devtools/server/tests/unit/test_breakpoint-19.js
Normal file
69
toolkit/devtools/server/tests/unit/test_breakpoint-19.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure that setting a breakpoint in a not-yet-existing script doesn't throw
|
||||||
|
* an error (see bug 897567). Also make sure that this breakpoint works.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var gDebuggee;
|
||||||
|
var gClient;
|
||||||
|
var gThreadClient;
|
||||||
|
var gCallback;
|
||||||
|
|
||||||
|
function run_test()
|
||||||
|
{
|
||||||
|
run_test_with_server(DebuggerServer, function () {
|
||||||
|
run_test_with_server(WorkerDebuggerServer, do_test_finished);
|
||||||
|
});
|
||||||
|
do_test_pending();
|
||||||
|
};
|
||||||
|
|
||||||
|
function run_test_with_server(aServer, aCallback)
|
||||||
|
{
|
||||||
|
gCallback = aCallback;
|
||||||
|
initTestDebuggerServer(aServer);
|
||||||
|
gDebuggee = addTestGlobal("test-breakpoints", aServer);
|
||||||
|
gDebuggee.console = { log: x => void x };
|
||||||
|
gClient = new DebuggerClient(aServer.connectPipe());
|
||||||
|
gClient.connect(function () {
|
||||||
|
attachTestTabAndResume(gClient,
|
||||||
|
"test-breakpoints",
|
||||||
|
function (aResponse, aTabClient, aThreadClient) {
|
||||||
|
gThreadClient = aThreadClient;
|
||||||
|
testBreakpoint();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const URL = "test.js";
|
||||||
|
|
||||||
|
function setUpCode() {
|
||||||
|
Cu.evalInSandbox(
|
||||||
|
"" + function test() { // 1
|
||||||
|
var a = 1; // 2
|
||||||
|
debugger; // 3
|
||||||
|
} + // 4
|
||||||
|
"\ndebugger;", // 5
|
||||||
|
gDebuggee,
|
||||||
|
"1.8",
|
||||||
|
URL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const testBreakpoint = Task.async(function* () {
|
||||||
|
const [response, bpClient] = yield setBreakpoint(gThreadClient, {url: URL, line: 2});
|
||||||
|
ok(!response.error);
|
||||||
|
|
||||||
|
const actor = response.actor;
|
||||||
|
ok(actor);
|
||||||
|
|
||||||
|
yield executeOnNextTickAndWaitForPause(setUpCode, gClient);
|
||||||
|
yield resume(gThreadClient);
|
||||||
|
|
||||||
|
const packet = yield executeOnNextTickAndWaitForPause(gDebuggee.test, gClient);
|
||||||
|
equal(packet.why.type, "breakpoint")
|
||||||
|
notEqual(packet.why.actors.indexOf(actor), -1);
|
||||||
|
|
||||||
|
finishClient(gClient);
|
||||||
|
});
|
@ -16,6 +16,7 @@ function run_test()
|
|||||||
test_add_breakpoint();
|
test_add_breakpoint();
|
||||||
test_remove_breakpoint();
|
test_remove_breakpoint();
|
||||||
test_find_breakpoints();
|
test_find_breakpoints();
|
||||||
|
test_duplicate_breakpoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_has_breakpoint() {
|
function test_has_breakpoint() {
|
||||||
@ -165,3 +166,28 @@ function test_find_breakpoints() {
|
|||||||
do_check_eq(bpSet.size, 0,
|
do_check_eq(bpSet.size, 0,
|
||||||
"Should be able to filter the iteration by url and line");
|
"Should be able to filter the iteration by url and line");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test_duplicate_breakpoints() {
|
||||||
|
let bpStore = new BreakpointStore();
|
||||||
|
|
||||||
|
// Breakpoint with column
|
||||||
|
let location = {
|
||||||
|
url: "http://example.com/foo.js",
|
||||||
|
line: 10,
|
||||||
|
column: 9
|
||||||
|
};
|
||||||
|
bpStore.addBreakpoint(location);
|
||||||
|
bpStore.addBreakpoint(location);
|
||||||
|
do_check_eq(bpStore.size, 1, "We should have only 1 column breakpoint");
|
||||||
|
bpStore.removeBreakpoint(location);
|
||||||
|
|
||||||
|
// Breakpoint without column (whole line breakpoint)
|
||||||
|
location = {
|
||||||
|
url: "http://example.com/foo.js",
|
||||||
|
line: 15
|
||||||
|
};
|
||||||
|
bpStore.addBreakpoint(location);
|
||||||
|
bpStore.addBreakpoint(location);
|
||||||
|
do_check_eq(bpStore.size, 1, "We should have only 1 whole line breakpoint");
|
||||||
|
bpStore.removeBreakpoint(location);
|
||||||
|
}
|
||||||
|
@ -110,6 +110,7 @@ reason = bug 820380
|
|||||||
[test_breakpoint-16.js]
|
[test_breakpoint-16.js]
|
||||||
[test_breakpoint-17.js]
|
[test_breakpoint-17.js]
|
||||||
[test_breakpoint-18.js]
|
[test_breakpoint-18.js]
|
||||||
|
[test_breakpoint-19.js]
|
||||||
[test_conditional_breakpoint-01.js]
|
[test_conditional_breakpoint-01.js]
|
||||||
[test_conditional_breakpoint-02.js]
|
[test_conditional_breakpoint-02.js]
|
||||||
[test_conditional_breakpoint-03.js]
|
[test_conditional_breakpoint-03.js]
|
||||||
|
Loading…
Reference in New Issue
Block a user