Bug 1230345 - kill breakpoint sliding for most scenarios, only do it when we know we have scripts r=fitzgen

This commit is contained in:
James Long 2016-01-07 11:53:56 -05:00
parent 6c69904a09
commit da676fb17f
23 changed files with 270 additions and 632 deletions

View File

@ -79,15 +79,13 @@ function testSetBreakpointBlankLine() {
let sourceForm = getSourceForm(gSources, COFFEE_URL);
let source = gDebugger.gThreadClient.source(sourceForm);
source.setBreakpoint({ line: 7 }, aResponse => {
source.setBreakpoint({ line: 8 }, aResponse => {
ok(!aResponse.error,
"Should be able to set a breakpoint in a coffee source file on a blank line.");
ok(aResponse.actualLocation,
"Because 7 is empty, we should have an actualLocation.");
is(aResponse.actualLocation.source.url, COFFEE_URL,
"actualLocation.actor should be source mapped to the coffee file.");
is(aResponse.actualLocation.line, 8,
"actualLocation.line should be source mapped back to 8.");
"Should be able to set a breakpoint in a coffee source file on a blank line.");
ok(!aResponse.isPending,
"Should not be a pending breakpoint.");
ok(!aResponse.actualLocation,
"Should not be a moved breakpoint.");
deferred.resolve();
});

View File

@ -2724,245 +2724,93 @@ SourceActor.prototype = {
* @returns A Promise that resolves to the given BreakpointActor.
*/
_setBreakpoint: function (actor) {
let { originalLocation } = actor;
let { originalSourceActor, originalLine, originalColumn } = originalLocation;
const { originalLocation } = actor;
const { originalLine, originalSourceActor } = originalLocation;
return this._setBreakpointAtOriginalLocation(actor, originalLocation)
.then((actualLocation) => {
if (actualLocation) {
return actualLocation;
}
// There were no scripts that matched the given location, so we need to
// perform breakpoint sliding. We try to slide the breakpoint by column
// first, and if that fails, by line instead.
if (!this.isSourceMapped) {
if (originalColumn !== undefined) {
// To perform breakpoint sliding for column breakpoints, we need to
// build a map from column numbers to a list of entry points for each
// column, implemented as a sparse array. An entry point is a (script,
// offsets) pair, and represents all offsets in that script that are
// entry points for the corresponding column.
let columnToEntryPointsMap = [];
// Iterate over all scripts that correspond to this source actor and
// line number.
let scripts = this.scripts.getScriptsBySourceActor(this, originalLine);
for (let script of scripts) {
let columnToOffsetMap = script.getAllColumnOffsets()
.filter(({ lineNumber }) => {
return lineNumber === originalLine;
})
// Iterate over each column, and add their list of offsets to the
// map from column numbers to entry points by forming a (script,
// offsets) pair, where script is the current script, and offsets is
// the list of offsets for the current column.
for (let { columnNumber: column, offset } of columnToOffsetMap) {
let entryPoints = columnToEntryPointsMap[column];
if (!entryPoints) {
// We dont have a list of entry points for the current column
// number yet, so create it and add it to the map.
entryPoints = [];
columnToEntryPointsMap[column] = entryPoints;
}
entryPoints.push({ script, offsets: [offset] });
}
}
// Now that we have a map from column numbers to a list of entry points
// for each column, we can use it to perform breakpoint sliding. Start
// at the original column of the breakpoint actor, and keep
// incrementing it by one, until either we find a line that has at
// least one entry point, or we go past the last column in the map.
//
// Note that by computing the entire map up front, and implementing it
// as a sparse array, we can easily tell when we went past the last
// column in the map.
let actualColumn = originalColumn + 1;
while (actualColumn < columnToEntryPointsMap.length) {
let entryPoints = columnToEntryPointsMap[actualColumn];
if (entryPoints) {
setBreakpointAtEntryPoints(actor, entryPoints);
return new OriginalLocation(
originalSourceActor,
originalLine,
actualColumn
);
}
++actualColumn;
}
return originalLocation;
} else {
// To perform breakpoint sliding for line breakpoints, we need to
// build a map from line numbers to a list of entry points for each
// line, implemented as a sparse array. An entry point is a (script,
// offsets) pair, and represents all offsets in that script that are
// entry points for the corresponding line.
let lineToEntryPointsMap = [];
// Iterate over all scripts that correspond to this source actor.
let scripts = this.scripts.getScriptsBySourceActor(this);
for (let script of scripts) {
// Get all offsets for each line in the current script. This returns
// a map from line numbers fo a list of offsets for each line,
// implemented as a sparse array.
let lineToOffsetsMap = script.getAllOffsets();
// Iterate over each line, and add their list of offsets to the map
// from line numbers to entry points by forming a (script, offsets)
// pair, where script is the current script, and offsets is the list
// of offsets for the current line.
for (let line = 0; line < lineToOffsetsMap.length; ++line) {
let offsets = lineToOffsetsMap[line];
if (offsets) {
let entryPoints = lineToEntryPointsMap[line];
if (!entryPoints) {
// We dont have a list of entry points for the current line
// number yet, so create it and add it to the map.
entryPoints = [];
lineToEntryPointsMap[line] = entryPoints;
}
entryPoints.push({ script, offsets });
}
}
}
// Now that we have a map from line numbers to a list of entry points
// for each line, we can use it to perform breakpoint sliding. Start
// at the original line of the breakpoint actor, and keep incrementing
// it by one, until either we find a line that has at least one entry
// point, or we go past the last line in the map.
//
// Note that by computing the entire map up front, and implementing it
// as a sparse array, we can easily tell when we went past the last
// line in the map.
let actualLine = originalLine + 1;
while (actualLine < lineToEntryPointsMap.length) {
let entryPoints = lineToEntryPointsMap[actualLine];
if (entryPoints) {
setBreakpointAtEntryPoints(actor, entryPoints);
break;
}
++actualLine;
}
if (actualLine >= lineToEntryPointsMap.length) {
// We went past the last line in the map, so breakpoint sliding
// failed. Keep the BreakpointActor in the BreakpointActorMap as a
// pending breakpoint, so we can try again whenever a new script is
// introduced.
return originalLocation;
}
return new OriginalLocation(
originalSourceActor,
actualLine
);
}
} else {
let slideByColumn = (actualColumn) => {
return this.sources.getAllGeneratedLocations(new OriginalLocation(
this,
originalLine,
actualColumn
)).then((generatedLocations) => {
// Because getAllGeneratedLocations will always return the list of
// generated locations for the closest column that is greater than
// the one we are searching for if no exact match can be found, if
// the list of generated locations is empty, we've reached the end
// of the original line, and sliding continues by line.
if (generatedLocations.length === 0) {
return slideByLine(originalLine + 1);
}
// If at least one script has an offset that matches one of the
// generated locations in the list, then breakpoint sliding
// succeeded.
if (this._setBreakpointAtAllGeneratedLocations(actor, generatedLocations)) {
return this.threadActor.sources.getOriginalLocation(generatedLocations[0]);
}
// Try the next column in the original source.
return slideByColumn(actualColumn + 1);
});
};
let slideByLine = (actualLine) => {
return this.sources.getAllGeneratedLocations(new OriginalLocation(
this,
actualLine
)).then((generatedLocations) => {
// Because getAllGeneratedLocations will always return the list of
// generated locations for the closest line that is greater than
// the one we are searching for if no exact match can be found, if
// the list of generated locations is empty, we've reached the end
// of the original source, and breakpoint sliding failed.
if (generatedLocations.length === 0) {
return originalLocation;
}
// If at least one script has an offset that matches one of the
// generated locations in the list, then breakpoint sliding
// succeeded.
if (this._setBreakpointAtAllGeneratedLocations(actor, generatedLocations)) {
return this.threadActor.sources.getOriginalLocation(generatedLocations[0]);
}
// Try the next line in the original source.
return slideByLine(actualLine + 1);
});
};
if (originalColumn !== undefined) {
return slideByColumn(originalColumn + 1);
} else {
return slideByLine(originalLine + 1);
}
}
}).then((actualLocation) => {
// If the actual location on which the BreakpointActor ended up being
// set differs from the original line that was requested, both the
// BreakpointActor and the BreakpointActorMap need to be updated
// accordingly.
if (!actualLocation.equals(originalLocation)) {
let existingActor = this.breakpointActorMap.getActor(actualLocation);
if (existingActor) {
actor.onDelete();
this.breakpointActorMap.deleteActor(originalLocation);
actor = existingActor;
} else {
this.breakpointActorMap.deleteActor(originalLocation);
actor.originalLocation = actualLocation;
this.breakpointActorMap.setActor(actualLocation, actor);
}
}
return actor;
});
},
_setBreakpointAtOriginalLocation: function (actor, originalLocation) {
if (!this.isSourceMapped) {
if (!this._setBreakpointAtGeneratedLocation(
actor,
GeneratedLocation.fromOriginalLocation(originalLocation)
)) {
return promise.resolve(null);
}
const scripts = this.scripts.getScriptsBySourceActorAndLine(
this,
originalLine
);
return promise.resolve(originalLocation);
} else {
return this.sources.getAllGeneratedLocations(originalLocation)
.then((generatedLocations) => {
if (!this._setBreakpointAtAllGeneratedLocations(
actor,
generatedLocations
)) {
return null;
// Never do breakpoint sliding for column breakpoints.
// Additionally, never do breakpoint sliding if no scripts
// exist on this line.
//
// Sliding can go horribly wrong if we always try to find the
// next line with valid entry points in the entire file.
// Scripts may be completely GCed and we never knew they
// existed, so we end up sliding through whole functions to
// the user's bewilderment.
//
// We can slide reliably if any scripts exist, however, due
// to how scripts are kept alive. A parent Debugger.Script
// keeps all of its children alive, so as long as we have a
// valid script, we can slide through it and know we won't
// slide through any of its child scripts. Additionally, if a
// script gets GCed, that means that all parents scripts are
// GCed as well, and no scripts will exist on those lines
// anymore. We will never slide through a GCed script.
if (originalLocation.originalColumn || scripts.length === 0) {
return promise.resolve(actor);
}
return this.threadActor.sources.getOriginalLocation(generatedLocations[0]);
// Find the script that spans the largest amount of code to
// determine the bounds for sliding.
const largestScript = scripts.reduce((largestScript, script) => {
if (script.lineCount > largestScript.lineCount) {
return script;
}
return largestScript;
});
const maxLine = largestScript.startLine + largestScript.lineCount - 1;
let actualLine = originalLine;
for (; actualLine <= maxLine; actualLine++) {
const loc = new GeneratedLocation(this, actualLine);
if (this._setBreakpointAtGeneratedLocation(actor, loc)) {
break;
}
}
// The above loop should never complete. We only did breakpoint sliding
// because we found scripts on the line we started from,
// which means there must be valid entry points somewhere
// within those scripts.
assert(
actualLine <= maxLine,
"Could not find any entry points to set a breakpoint on, " +
"even though I was told a script existed on the line I started " +
"the search with."
);
// Update the actor to use the new location (reusing a
// previous breakpoint if it already exists on that line).
const actualLocation = new OriginalLocation(originalSourceActor, actualLine);
const existingActor = this.breakpointActorMap.getActor(actualLocation);
this.breakpointActorMap.deleteActor(originalLocation);
if (existingActor) {
actor.onDelete();
actor = existingActor;
} else {
actor.originalLocation = actualLocation;
this.breakpointActorMap.setActor(actualLocation, actor);
}
}
return promise.resolve(actor);
} else {
return this.sources.getAllGeneratedLocations(originalLocation).then((generatedLocations) => {
this._setBreakpointAtAllGeneratedLocations(
actor,
generatedLocations
);
return actor;
});
}
},

View File

@ -632,8 +632,8 @@ TabSources.prototype = {
originalColumn
} = originalLocation;
let source = originalSourceActor.source ||
originalSourceActor.generatedSource;
let source = (originalSourceActor.source ||
originalSourceActor.generatedSource);
return this.fetchSourceMap(source).then((map) => {
if (map) {

View File

@ -65,9 +65,11 @@ function test_simple_breakpoint()
});
});
Components.utils.evalInSandbox("var line0 = Error().lineNumber;\n" +
"debugger;\n" + // line0 + 1
"var a = 1;\n" + // line0 + 2
"var b = 2;\n", // line0 + 3
gDebuggee);
Cu.evalInSandbox(
"var line0 = Error().lineNumber;\n" +
"debugger;\n" + // line0 + 1
"var a = 1;\n" + // line0 + 2
"var b = 2;\n", // line0 + 3
gDebuggee
);
}

View File

@ -57,8 +57,11 @@ function test_breakpoint_running()
});
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"debugger;\n" +
"var a = 1;\n" + // line0 + 2
"var b = 2;\n"); // line0 + 3
Cu.evalInSandbox(
"var line0 = Error().lineNumber;\n" +
"debugger;\n" +
"var a = 1;\n" + // line0 + 2
"var b = 2;\n", // line0 + 3
gDebuggee
);
}

View File

@ -2,7 +2,9 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that setting a breakpoint in a line without code will skip forward.
* Check that setting a breakpoint on a line without code will skip
* forward when we know the script isn't GCed (the debugger is connected,
* so it's kept alive).
*/
var gDebuggee;
@ -65,14 +67,18 @@ function test_skip_breakpoint()
});
});
// Continue until the breakpoint is hit.
gThreadClient.resume();
});
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"debugger;\n" + // line0 + 1
"var a = 1;\n" + // line0 + 2
"// A comment.\n" + // line0 + 3
"var b = 2;"); // line0 + 4
// Use `evalInSandbox` to make the debugger treat it as normal
// globally-scoped code, where breakpoint sliding rules apply.
Cu.evalInSandbox(
"var line0 = Error().lineNumber;\n" +
"debugger;\n" + // line0 + 1
"var a = 1;\n" + // line0 + 2
"// A comment.\n" + // line0 + 3
"var b = 2;", // line0 + 4
gDebuggee
);
}

View File

@ -67,11 +67,14 @@ function test_child_breakpoint()
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2
" this.b = 2;\n" + // line0 + 3
"}\n" + // line0 + 4
"debugger;\n" + // line0 + 5
"foo();\n"); // line0 + 6
Cu.evalInSandbox(
"var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2
" this.b = 2;\n" + // line0 + 3
"}\n" + // line0 + 4
"debugger;\n" + // line0 + 5
"foo();\n", // line0 + 6
gDebuggee
);
}

View File

@ -2,7 +2,7 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that setting a breakpoint in a line without code in a child scrip
* Check that setting a breakpoint in a line without code in a child script
* will skip forward.
*/
@ -68,12 +68,15 @@ function test_child_skip_breakpoint()
});
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2
" // A comment.\n" + // line0 + 3
" this.b = 2;\n" + // line0 + 4
"}\n" + // line0 + 5
"debugger;\n" + // line0 + 6
"foo();\n"); // line0 + 7
Cu.evalInSandbox(
"var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2
" // A comment.\n" + // line0 + 3
" this.b = 2;\n" + // line0 + 4
"}\n" + // line0 + 5
"debugger;\n" + // line0 + 6
"foo();\n", // line0 + 7
gDebuggee
);
}

View File

@ -69,18 +69,21 @@ function test_nested_breakpoint()
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" function bar() {\n" + // line0 + 2
" function baz() {\n" + // line0 + 3
" this.a = 1;\n" + // line0 + 4
" // A comment.\n" + // line0 + 5
" this.b = 2;\n" + // line0 + 6
" }\n" + // line0 + 7
" baz();\n" + // line0 + 8
" }\n" + // line0 + 9
" bar();\n" + // line0 + 10
"}\n" + // line0 + 11
"debugger;\n" + // line0 + 12
"foo();\n"); // line0 + 13
Cu.evalInSandbox(
"var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" function bar() {\n" + // line0 + 2
" function baz() {\n" + // line0 + 3
" this.a = 1;\n" + // line0 + 4
" // A comment.\n" + // line0 + 5
" this.b = 2;\n" + // line0 + 6
" }\n" + // line0 + 7
" baz();\n" + // line0 + 8
" }\n" + // line0 + 9
" bar();\n" + // line0 + 10
"}\n" + // line0 + 11
"debugger;\n" + // line0 + 12
"foo();\n", // line0 + 13
gDebuggee
)
}

View File

@ -68,15 +68,18 @@ function test_second_child_skip_breakpoint()
});
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" bar();\n" + // line0 + 2
"}\n" + // line0 + 3
"function bar() {\n" + // line0 + 4
" this.a = 1;\n" + // line0 + 5
" // A comment.\n" + // line0 + 6
" this.b = 2;\n" + // line0 + 7
"}\n" + // line0 + 8
"debugger;\n" + // line0 + 9
"foo();\n"); // line0 + 10
Cu.evalInSandbox(
"var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" bar();\n" + // line0 + 2
"}\n" + // line0 + 3
"function bar() {\n" + // line0 + 4
" this.a = 1;\n" + // line0 + 5
" // A comment.\n" + // line0 + 6
" this.b = 2;\n" + // line0 + 7
"}\n" + // line0 + 8
"debugger;\n" + // line0 + 9
"foo();\n", // line0 + 10
gDebuggee
)
}

View File

@ -48,8 +48,7 @@ function test_child_skip_breakpoint()
let location = { line: gDebuggee.line0 + 3 };
source.setBreakpoint(location, function (aResponse, bpClient) {
// Check that the breakpoint has properly skipped forward one
// line.
// Check that the breakpoint has properly skipped forward one line.
do_check_eq(aResponse.actualLocation.source.actor, source.actor);
do_check_eq(aResponse.actualLocation.line, location.line + 1);
@ -78,13 +77,20 @@ function test_child_skip_breakpoint()
}
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2
" // A comment.\n" + // line0 + 3
" this.b = 2;\n" + // line0 + 3
"}\n"); // line0 + 4
gDebuggee.eval("var line1 = Error().lineNumber;\n" +
"debugger;\n" + // line1 + 1
"foo();\n"); // line1 + 2
Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2
" // A comment.\n" + // line0 + 3
" this.b = 2;\n" + // line0 + 4
"}\n", // line0 + 5
gDebuggee,
"1.7",
"script1.js");
Cu.evalInSandbox("var line1 = Error().lineNumber;\n" +
"debugger;\n" + // line1 + 1
"foo();\n", // line1 + 2
gDebuggee,
"1.7",
"script2.js");
}

View File

@ -71,15 +71,16 @@ function test_remove_breakpoint()
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"function foo(stop) {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2
" if (stop) return;\n" + // line0 + 3
" delete this.a;\n" + // line0 + 4
" foo(true);\n" + // line0 + 5
"}\n" + // line0 + 6
"debugger;\n" + // line1 + 7
"foo();\n"); // line1 + 8
Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
"function foo(stop) {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2
" if (stop) return;\n" + // line0 + 3
" delete this.a;\n" + // line0 + 4
" foo(true);\n" + // line0 + 5
"}\n" + // line0 + 6
"debugger;\n" + // line1 + 7
"foo();\n", // line1 + 8
gDebuggee);
if (!done) {
do_check_true(false);
}

View File

@ -79,10 +79,11 @@ function test_child_breakpoint()
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"debugger;\n" + // line0 + 1
"var a, i = 0;\n" + // line0 + 2
"for (i = 1; i <= 2; i++) {\n" + // line0 + 3
" a = i;\n" + // line0 + 4
"}\n"); // line0 + 5
Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
"debugger;\n" + // line0 + 1
"var a, i = 0;\n" + // line0 + 2
"for (i = 1; i <= 2; i++) {\n" + // line0 + 3
" a = i;\n" + // line0 + 4
"}\n", // line0 + 5
gDebuggee);
}

View File

@ -80,8 +80,9 @@ function test_child_breakpoint()
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"debugger;\n" + // line0 + 1
"var a = { b: 1, f: function() { return 2; } };\n" + // line0+2
"var res = a.f();\n"); // line0 + 3
Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
"debugger;\n" + // line0 + 1
"var a = { b: 1, f: function() { return 2; } };\n" + // line0+2
"var res = a.f();\n", // line0 + 3
gDebuggee);
}

View File

@ -55,14 +55,15 @@ function test_child_skip_breakpoint()
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2
" // A comment.\n" + // line0 + 3
" this.b = 2;\n" + // line0 + 4
"}\n" + // line0 + 5
"debugger;\n" + // line0 + 6
"foo();\n"); // line0 + 7
Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2
" // A comment.\n" + // line0 + 3
" this.b = 2;\n" + // line0 + 4
"}\n" + // line0 + 5
"debugger;\n" + // line0 + 6
"foo();\n", // line0 + 7
gDebuggee);
}
// Set many breakpoints at the same location.

View File

@ -104,12 +104,13 @@ function test_simple_breakpoint()
});
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2 <-- Breakpoint is set here.
"}\n" + // line0 + 3
"debugger;\n" + // line0 + 4
"foo();\n" + // line0 + 5
"debugger;\n" + // line0 + 6
"var b = 2;\n"); // line0 + 7
Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2 <-- Breakpoint is set here.
"}\n" + // line0 + 3
"debugger;\n" + // line0 + 4
"foo();\n" + // line0 + 5
"debugger;\n" + // line0 + 6
"var b = 2;\n", // line0 + 7
gDebuggee);
}

View File

@ -102,12 +102,13 @@ function test_simple_breakpoint()
});
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2 <-- Breakpoint is set here.
"}\n" + // line0 + 3
"debugger;\n" + // line0 + 4
"foo();\n" + // line0 + 5
"debugger;\n" + // line0 + 6
"var b = 2;\n"); // line0 + 7
Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
"function foo() {\n" + // line0 + 1
" this.a = 1;\n" + // line0 + 2 <-- Breakpoint is set here.
"}\n" + // line0 + 3
"debugger;\n" + // line0 + 4
"foo();\n" + // line0 + 5
"debugger;\n" + // line0 + 6
"var b = 2;\n", // line0 + 7
gDebuggee);
}

View File

@ -1,57 +0,0 @@
"use strict";
var SOURCE_URL = getFileUrl("setBreakpoint-on-column-with-no-offsets-in-gcd-script.js");
function run_test() {
return Task.spawn(function* () {
do_test_pending();
let global = testGlobal("test");
loadSubScript(SOURCE_URL, global);
Cu.forceGC();
DebuggerServer.registerModule("xpcshell-test/testactors");
DebuggerServer.init(() => true);
DebuggerServer.addTestGlobal(global);
let client = new DebuggerClient(DebuggerServer.connectPipe());
yield connect(client);
let tab = yield findTab(client, "test");
let [, tabClient] = yield attachTab(client, tab);
let [, threadClient] = yield attachThread(tabClient);
yield resume(threadClient);
let source = yield findSource(threadClient, SOURCE_URL);
let sourceClient = threadClient.source(source);
let location = { line: 6, column: 17 };
let [packet, breakpointClient] = yield setBreakpoint(sourceClient, location);
do_check_true(packet.isPending);
do_check_false("actualLocation" in packet);
executeSoon(function () {
reload(tabClient).then(function () {
loadSubScript(SOURCE_URL, global);
});
});
packet = yield waitForPaused(threadClient);
do_check_eq(packet.type, "paused");
let why = packet.why;
do_check_eq(why.type, "breakpoint");
do_check_eq(why.actors.length, 1);
do_check_eq(why.actors[0], breakpointClient.actor);
let frame = packet.frame;
let where = frame.where;
do_check_eq(where.source.actor, source.actor);
do_check_eq(where.line, location.line);
do_check_eq(where.column, location.column + 7);
let variables = frame.environment.bindings.variables;
do_check_eq(variables.a.value, 1);
do_check_eq(variables.b.value.type, "undefined");
do_check_eq(variables.c.value.type, "undefined");
yield resume(threadClient);
yield close(client);
do_test_finished();
});
}

View File

@ -1,55 +0,0 @@
"use strict";
var SOURCE_URL = getFileUrl("setBreakpoint-on-column-with-no-offsets-at-end-of-script.js");
function run_test() {
return Task.spawn(function* () {
do_test_pending();
DebuggerServer.registerModule("xpcshell-test/testactors");
DebuggerServer.init(() => true);
let global = createTestGlobal("test");
DebuggerServer.addTestGlobal(global);
let client = new DebuggerClient(DebuggerServer.connectPipe());
yield connect(client);
let { tabs } = yield listTabs(client);
let tab = findTab(tabs, "test");
let [, tabClient] = yield attachTab(client, tab);
let [, threadClient] = yield attachThread(tabClient);
yield resume(threadClient);
let promise = waitForNewSource(threadClient, SOURCE_URL);
loadSubScript(SOURCE_URL, global);
let { source } = yield promise;
let sourceClient = threadClient.source(source);
let location = { line: 4, column: 38 };
let [packet, breakpointClient] = yield setBreakpoint(sourceClient, location);
do_check_false(packet.isPending);
do_check_true("actualLocation" in packet);
let actualLocation = packet.actualLocation;
do_check_eq(actualLocation.line, 4);
do_check_eq(actualLocation.column, 41);
packet = yield executeOnNextTickAndWaitForPause(function () {
Cu.evalInSandbox("f()", global);
}, client);
do_check_eq(packet.type, "paused");
let why = packet.why;
do_check_eq(why.type, "breakpoint");
do_check_eq(why.actors.length, 1);
do_check_eq(why.actors[0], breakpointClient.actor);
let where = packet.frame.where;
do_check_eq(where.source.actor, source.actor);
do_check_eq(where.line, actualLocation.line);
do_check_eq(where.column, actualLocation.column);
yield resume(threadClient);
yield close(client);
do_test_finished();
});
}

View File

@ -1,57 +0,0 @@
"use strict";
var SOURCE_URL = getFileUrl("setBreakpoint-on-column-with-no-offsets-in-gcd-script.js");
function run_test() {
return Task.spawn(function* () {
do_test_pending();
let global = testGlobal("test");
loadSubScript(SOURCE_URL, global);
Cu.forceGC(); Cu.forceGC(); Cu.forceGC();
DebuggerServer.registerModule("xpcshell-test/testactors");
DebuggerServer.init(() => true);
DebuggerServer.addTestGlobal(global);
let client = new DebuggerClient(DebuggerServer.connectPipe());
yield connect(client);
let { tabs } = yield listTabs(client);
let tab = findTab(tabs, "test");
let [, tabClient] = yield attachTab(client, tab);
let [, threadClient] = yield attachThread(tabClient);
yield resume(threadClient);
let { sources } = yield getSources(threadClient);
let source = findSource(sources, SOURCE_URL);
let sourceClient = threadClient.source(source);
let location = { line: 6, column: 17 };
let [packet, breakpointClient] = yield setBreakpoint(sourceClient, location);
do_check_true(packet.isPending);
do_check_false("actualLocation" in packet);
packet = yield executeOnNextTickAndWaitForPause(function () {
reload(tabClient).then(function () {
loadSubScript(SOURCE_URL, global);
});
}, client);
do_check_eq(packet.type, "paused");
let why = packet.why;
do_check_eq(why.type, "breakpoint");
do_check_eq(why.actors.length, 1);
do_check_eq(why.actors[0], breakpointClient.actor);
let frame = packet.frame;
let where = frame.where;
do_check_eq(where.source.actor, source.actor);
do_check_eq(where.line, location.line);
do_check_eq(where.column, 28);
let variables = frame.environment.bindings.variables;
do_check_eq(variables.a.value, 1);
do_check_eq(variables.c.value.type, "undefined");
yield resume(threadClient);
yield close(client);
do_test_finished();
});
}

View File

@ -1,59 +0,0 @@
"use strict";
var SOURCE_URL = getFileUrl("setBreakpoint-on-column-with-no-offsets.js");
function run_test() {
return Task.spawn(function* () {
do_test_pending();
DebuggerServer.registerModule("xpcshell-test/testactors");
DebuggerServer.init(() => true);
let global = createTestGlobal("test");
DebuggerServer.addTestGlobal(global);
let client = new DebuggerClient(DebuggerServer.connectPipe());
yield connect(client);
let { tabs } = yield listTabs(client);
let tab = findTab(tabs, "test");
let [, tabClient] = yield attachTab(client, tab);
let [, threadClient] = yield attachThread(tabClient);
yield resume(threadClient);
let promise = waitForNewSource(threadClient, SOURCE_URL);
loadSubScript(SOURCE_URL, global);
let { source } = yield promise;
let sourceClient = threadClient.source(source);
let location = { line: 4, column: 17 };
let [packet, breakpointClient] = yield setBreakpoint(sourceClient, location);
do_check_false(packet.isPending);
do_check_true("actualLocation" in packet);
let actualLocation = packet.actualLocation;
do_check_eq(actualLocation.line, 4);
do_check_eq(actualLocation.column, 28);
packet = yield executeOnNextTickAndWaitForPause(function () {
Cu.evalInSandbox("f()", global);
}, client);
do_check_eq(packet.type, "paused");
let why = packet.why;
do_check_eq(why.type, "breakpoint");
do_check_eq(why.actors.length, 1);
do_check_eq(why.actors[0], breakpointClient.actor);
let frame = packet.frame;
let where = frame.where;
do_check_eq(where.source.actor, source.actor);
do_check_eq(where.line, actualLocation.line);
do_check_eq(where.column, actualLocation.column);
let variables = frame.environment.bindings.variables;
do_check_eq(variables.a.value, 1);
do_check_eq(variables.c.value.type, "undefined");
yield resume(threadClient);
yield close(client);
do_test_finished();
});
}

View File

@ -27,58 +27,46 @@ function run_test()
function testBreakpointMapping(aName, aCallback)
{
// Pause so we can set a breakpoint.
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
do_check_true(!aPacket.error);
do_check_eq(aPacket.why.type, "debuggerStatement");
Task.spawn(function*() {
let response = yield waitForPause(gThreadClient);
do_check_eq(response.why.type, "debuggerStatement");
getSource(gThreadClient, "http://example.com/www/js/" + aName + ".js").then(source => {
source.setBreakpoint({
// Setting the breakpoint on an empty line so that it is pushed down one
// line and we can check the source mapped actualLocation later.
line: 3
}, function (aResponse) {
do_check_true(!aResponse.error);
// Actual location should come back source mapped still so that
// breakpoints are displayed in the UI correctly, etc.
do_check_eq(aResponse.actualLocation.line, 4);
do_check_eq(aResponse.actualLocation.source.url,
"http://example.com/www/js/" + aName + ".js");
// The eval will cause us to resume, then we get an unsolicited pause
// because of our breakpoint, we resume again to finish the eval, and
// finally receive our last pause which has the result of the client
// evaluation.
gThreadClient.eval(null, aName + "()", function (aResponse) {
do_check_true(!aResponse.error, "Shouldn't be an error resuming to eval");
do_check_eq(aResponse.type, "resumed");
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
do_check_eq(aPacket.why.type, "breakpoint");
// Assert that we paused because of the breakpoint at the correct
// location in the code by testing that the value of `ret` is still
// undefined.
do_check_eq(aPacket.frame.environment.bindings.variables.ret.value.type,
"undefined");
gThreadClient.resume(function (aResponse) {
do_check_true(!aResponse.error);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
do_check_eq(aPacket.why.type, "clientEvaluated");
do_check_eq(aPacket.why.frameFinished.return, aName);
gThreadClient.resume(function (aResponse) {
do_check_true(!aResponse.error);
aCallback();
});
});
});
});
});
});
const source = yield getSource(gThreadClient, "http://example.com/www/js/" + aName + ".js");
response = yield setBreakpoint(source, {
// Setting the breakpoint on an empty line so that it is pushed down one
// line and we can check the source mapped actualLocation later.
line: 3
});
// Should not slide breakpoints for sourcemapped sources
do_check_true(!response.actualLocation);
yield setBreakpoint(source, { line: 4 });
// The eval will cause us to resume, then we get an unsolicited pause
// because of our breakpoint, we resume again to finish the eval, and
// finally receive our last pause which has the result of the client
// evaluation.
response = yield rdpRequest(gThreadClient, gThreadClient.eval, null, aName + "()");
do_check_eq(response.type, "resumed");
response = yield waitForPause(gThreadClient);
do_check_eq(response.why.type, "breakpoint");
// Assert that we paused because of the breakpoint at the correct
// location in the code by testing that the value of `ret` is still
// undefined.
do_check_eq(response.frame.environment.bindings.variables.ret.value.type,
"undefined");
response = yield resume(gThreadClient);
response = yield waitForPause(gThreadClient);
do_check_eq(response.why.type, "clientEvaluated");
do_check_eq(response.why.frameFinished.return, aName);
response = yield resume(gThreadClient);
aCallback();
});
gDebuggee.eval("(" + function () {

View File

@ -256,10 +256,7 @@ skip-if = os != 'linux' || debug || asan
reason = bug 1014071
[test_setBreakpoint-on-column.js]
[test_setBreakpoint-on-column-in-gcd-script.js]
[test_setBreakpoint-on-column-with-no-offsets.js]
[test_setBreakpoint-on-column-with-no-offsets-at-end-of-line.js]
[test_setBreakpoint-on-column-with-no-offsets-at-end-of-script.js]
[test_setBreakpoint-on-column-with-no-offsets-in-gcd-script.js]
[test_setBreakpoint-on-line.js]
[test_setBreakpoint-on-line-in-gcd-script.js]
[test_setBreakpoint-on-line-with-multiple-offsets.js]