зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset 0d73f35c5025 (bug 1172572) for failures on browser_dbg_rr_breakpoints-03.js
This commit is contained in:
Родитель
e53a880b1c
Коммит
b0c02638f6
|
@ -208,7 +208,7 @@ BreakpointActor.prototype = {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
if (!this.threadActor.hasMoved(frame, "breakpoint")) {
|
||||
if (!this.threadActor.hasMoved(location, "breakpoint")) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
|
|
@ -807,10 +807,12 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
}
|
||||
|
||||
// Continue forward until we get to a valid step target.
|
||||
const { onStep, onPop } = this._makeSteppingHooks({
|
||||
steppingType: "next",
|
||||
rewinding: false,
|
||||
});
|
||||
const { onStep, onPop } = this._makeSteppingHooks(
|
||||
null,
|
||||
"next",
|
||||
false,
|
||||
null
|
||||
);
|
||||
|
||||
if (this.dbg.replaying) {
|
||||
const offsets = this._findReplayingStepOffsets(
|
||||
|
@ -828,7 +830,7 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
};
|
||||
},
|
||||
|
||||
_makeOnPop: function({ pauseAndRespond, steppingType }) {
|
||||
_makeOnPop: function({ pauseAndRespond, startLocation, steppingType }) {
|
||||
const thread = this;
|
||||
const result = function(completion) {
|
||||
// onPop is called with 'this' set to the current frame.
|
||||
|
@ -855,12 +857,15 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
if (steppingType == "finish") {
|
||||
const parentFrame = thread._getNextStepFrame(this);
|
||||
if (parentFrame && parentFrame.script) {
|
||||
const { onStep, onPop } = thread._makeSteppingHooks({
|
||||
steppingType: "next",
|
||||
rewinding: false,
|
||||
completion,
|
||||
});
|
||||
|
||||
// We can't use the completion value in stepping hooks if we're
|
||||
// replaying, as we can't use its contents after resuming.
|
||||
const ncompletion = thread.dbg.replaying ? null : completion;
|
||||
const { onStep, onPop } = thread._makeSteppingHooks(
|
||||
location,
|
||||
"next",
|
||||
false,
|
||||
ncompletion
|
||||
);
|
||||
if (thread.dbg.replaying) {
|
||||
const parentLocation = thread.sources.getFrameLocation(parentFrame);
|
||||
const offsets = thread._findReplayingStepOffsets(
|
||||
|
@ -880,17 +885,31 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
}
|
||||
}
|
||||
|
||||
return pauseAndRespond(this, packet =>
|
||||
thread.createCompletionGrip(packet, completion)
|
||||
);
|
||||
return pauseAndRespond(this, packet => {
|
||||
if (completion) {
|
||||
thread.createCompletionGrip(packet, completion);
|
||||
} else {
|
||||
packet.why.frameFinished = {
|
||||
terminated: true,
|
||||
};
|
||||
}
|
||||
return packet;
|
||||
});
|
||||
};
|
||||
|
||||
// When stepping out, we don't want to stop at a breakpoint that
|
||||
// happened to be set exactly at the spot where we stepped out.
|
||||
// See bug 970469. We record the location here and check
|
||||
// it when a breakpoint is hit. Furthermore we store this on the
|
||||
// function because, while we could store it directly on the
|
||||
// frame, if we did we'd also have to find the appropriate spot to
|
||||
// clear it.
|
||||
result.location = startLocation;
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
hasMoved: function(frame, newType) {
|
||||
const newLocation = this.sources.getFrameLocation(frame);
|
||||
|
||||
hasMoved: function(newLocation, newType) {
|
||||
if (!this._priorPause) {
|
||||
return true;
|
||||
}
|
||||
|
@ -909,9 +928,44 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
return line !== newLocation.line || column !== newLocation.column;
|
||||
},
|
||||
|
||||
// Return whether reaching a script offset should be considered a distinct
|
||||
// "step" from another location.
|
||||
_intraFrameLocationIsStepTarget: function(startLocation, script, offset) {
|
||||
// Only allow stepping stops at entry points for the line.
|
||||
if (!script.getOffsetMetadata(offset).isBreakpoint) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const location = this.sources.getScriptOffsetLocation(script, offset);
|
||||
|
||||
if (!startLocation || startLocation.url !== location.url) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO(logan): When we remove points points, this can be removed too as
|
||||
// we assert that we're at a different frame offset from the last time
|
||||
// we paused.
|
||||
if (!this.hasMoved(location)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// When pause points are specified for the source,
|
||||
// we should pause when we are at a stepOver pause point
|
||||
const pausePoints = location.sourceActor.pausePoints;
|
||||
const pausePoint =
|
||||
pausePoints && findPausePointForLocation(pausePoints, location);
|
||||
|
||||
if (pausePoint) {
|
||||
return pausePoint.step;
|
||||
}
|
||||
|
||||
return script.getOffsetMetadata(offset).isStepStart;
|
||||
},
|
||||
|
||||
_makeOnStep: function({
|
||||
pauseAndRespond,
|
||||
startFrame,
|
||||
startLocation,
|
||||
steppingType,
|
||||
completion,
|
||||
rewinding,
|
||||
|
@ -927,45 +981,37 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
this.onPop = undefined;
|
||||
return undefined;
|
||||
}
|
||||
const location = thread.sources.getFrameLocation(this);
|
||||
|
||||
if (thread._validFrameStepOffset(this, startFrame)) {
|
||||
// Continue if the source is black boxed.
|
||||
if (thread.sources.isBlackBoxed(location.url)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// A step has occurred if we are rewinding and have changed frames.
|
||||
if (rewinding && this !== startFrame) {
|
||||
return pauseAndRespond(this);
|
||||
}
|
||||
|
||||
// A step has occurred if we reached a step target.
|
||||
if (
|
||||
thread._intraFrameLocationIsStepTarget(
|
||||
startLocation,
|
||||
this.script,
|
||||
this.offset
|
||||
)
|
||||
) {
|
||||
return pauseAndRespond(this, packet =>
|
||||
thread.createCompletionGrip(packet, completion)
|
||||
);
|
||||
}
|
||||
|
||||
// Otherwise, let execution continue (we haven't executed enough code to
|
||||
// consider this a "step" yet).
|
||||
return undefined;
|
||||
};
|
||||
},
|
||||
|
||||
_validFrameStepOffset: function(frame, startFrame) {
|
||||
const location = this.sources.getFrameLocation(frame);
|
||||
const offsetMetadata = frame.script.getOffsetMetadata(frame.offset);
|
||||
|
||||
// Continue if the source is blackboxed or
|
||||
// the current location is not a possible breakpoint position.
|
||||
if (
|
||||
!offsetMetadata.isBreakpoint ||
|
||||
this.sources.isBlackBoxed(location.url)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pause if the frame has changed.
|
||||
if (frame !== startFrame) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Continue if the location has not changed, which can
|
||||
// occur via loops and recursion.
|
||||
if (!this.hasMoved(frame)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pause if the current location is a step position.
|
||||
return offsetMetadata.isStepStart;
|
||||
},
|
||||
|
||||
createCompletionGrip: function(packet, completion) {
|
||||
if (!completion) {
|
||||
return packet;
|
||||
|
@ -992,7 +1038,7 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
* backwards (rewinding == true), return an array of all the step targets
|
||||
* that could be reached next from startLocation.
|
||||
*/
|
||||
_findReplayingStepOffsets: function(frame, rewinding) {
|
||||
_findReplayingStepOffsets: function(startLocation, frame, rewinding) {
|
||||
const worklist = [frame.offset],
|
||||
seen = [],
|
||||
result = [];
|
||||
|
@ -1002,7 +1048,13 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
continue;
|
||||
}
|
||||
seen.push(offset);
|
||||
if (this._validFrameStepOffset(frame)) {
|
||||
if (
|
||||
this._intraFrameLocationIsStepTarget(
|
||||
startLocation,
|
||||
frame.script,
|
||||
offset
|
||||
)
|
||||
) {
|
||||
if (!result.includes(offset)) {
|
||||
result.push(offset);
|
||||
}
|
||||
|
@ -1021,13 +1073,12 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
/**
|
||||
* Define the JS hook functions for stepping.
|
||||
*/
|
||||
_makeSteppingHooks: function({ steppingType, rewinding, completion }) {
|
||||
// We can't use the completion value in stepping hooks if we're
|
||||
// replaying, as we can't use its contents after resuming.
|
||||
if (this.dbg.replaying) {
|
||||
completion = null;
|
||||
}
|
||||
|
||||
_makeSteppingHooks: function(
|
||||
startLocation,
|
||||
steppingType,
|
||||
rewinding,
|
||||
completion
|
||||
) {
|
||||
// Bind these methods and state because some of the hooks are called
|
||||
// with 'this' set to the current frame. Rather than repeating the
|
||||
// binding in each _makeOnX method, just do it once here and pass it
|
||||
|
@ -1036,8 +1087,9 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
pauseAndRespond: (frame, onPacket = k => k) =>
|
||||
this._pauseAndRespond(frame, { type: "resumeLimit" }, onPacket),
|
||||
startFrame: this.youngestFrame,
|
||||
steppingType,
|
||||
rewinding,
|
||||
startLocation: startLocation,
|
||||
steppingType: steppingType,
|
||||
rewinding: rewinding,
|
||||
completion,
|
||||
};
|
||||
|
||||
|
@ -1078,10 +1130,12 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
steppingType = "next";
|
||||
}
|
||||
|
||||
const { onEnterFrame, onPop, onStep } = this._makeSteppingHooks({
|
||||
const location = this.sources.getFrameLocation(this.youngestFrame);
|
||||
const { onEnterFrame, onPop, onStep } = this._makeSteppingHooks(
|
||||
location,
|
||||
steppingType,
|
||||
rewinding,
|
||||
});
|
||||
rewinding
|
||||
);
|
||||
|
||||
// Make sure there is still a frame on the stack if we are to continue
|
||||
// stepping.
|
||||
|
@ -1100,6 +1154,7 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
if (stepFrame.script) {
|
||||
if (this.dbg.replaying) {
|
||||
const offsets = this._findReplayingStepOffsets(
|
||||
location,
|
||||
stepFrame,
|
||||
rewinding
|
||||
);
|
||||
|
@ -1121,7 +1176,11 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
// Set an onStep handler in the older frame to stop at the call site.
|
||||
// Make sure the offsets we use are valid breakpoint locations, as we
|
||||
// cannot stop at other offsets when replaying.
|
||||
const offsets = this._findReplayingStepOffsets(olderFrame, true);
|
||||
const offsets = this._findReplayingStepOffsets(
|
||||
{},
|
||||
olderFrame,
|
||||
true
|
||||
);
|
||||
olderFrame.setReplayingOnStep(onStep, offsets);
|
||||
}
|
||||
} else {
|
||||
|
@ -1604,7 +1663,7 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
createProtocolCompletionValue: function(completion) {
|
||||
const protoValue = {};
|
||||
if (completion == null) {
|
||||
return protoValue;
|
||||
protoValue.terminated = true;
|
||||
} else if ("return" in completion) {
|
||||
protoValue.return = createValueGrip(
|
||||
completion.return,
|
||||
|
@ -1824,7 +1883,7 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
// 2. breakpoints are disabled
|
||||
// 3. the source is blackboxed
|
||||
if (
|
||||
!this.hasMoved(frame, "debuggerStatement") ||
|
||||
!this.hasMoved(location, "debuggerStatement") ||
|
||||
this.skipBreakpoints ||
|
||||
this.sources.isBlackBoxed(url)
|
||||
) {
|
||||
|
@ -2135,6 +2194,11 @@ this.reportError = function(error, prefix = "") {
|
|||
dumpn(msg);
|
||||
};
|
||||
|
||||
function findPausePointForLocation(pausePoints, location) {
|
||||
const { line: line, column: column } = location;
|
||||
return pausePoints[line] && pausePoints[line][column];
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwrap a global that is wrapped in a |Debugger.Object|, or if the global has
|
||||
* become a dead object, return |undefined|.
|
||||
|
|
|
@ -32,6 +32,7 @@ function getPauseLocation(packet) {
|
|||
}
|
||||
|
||||
function getPauseReturn(packet) {
|
||||
dump(`>> getPauseReturn yo ${JSON.stringify(packet.why)}\n`);
|
||||
return packet.why.frameFinished.return;
|
||||
}
|
||||
|
||||
|
@ -49,7 +50,9 @@ async function stepOutOfA(dbg, func, expectedLocation) {
|
|||
const { threadFront } = dbg;
|
||||
await steps(threadFront, [stepOver, stepIn]);
|
||||
|
||||
dump(`>>> oof\n`);
|
||||
const packet = await stepOut(threadFront);
|
||||
dump(`>>> foo\n`);
|
||||
|
||||
deepEqual(
|
||||
getPauseLocation(packet),
|
||||
|
@ -66,6 +69,7 @@ async function stepOverInA(dbg, func, expectedLocation) {
|
|||
await steps(threadFront, [stepOver, stepIn]);
|
||||
|
||||
let packet = await stepOver(threadFront);
|
||||
dump(`>> stepOverInA hi\n`);
|
||||
equal(getPauseReturn(packet).ownPropertyLength, 1, "a() is returning obj");
|
||||
|
||||
packet = await stepOver(threadFront);
|
||||
|
@ -77,18 +81,18 @@ async function stepOverInA(dbg, func, expectedLocation) {
|
|||
await dbg.threadFront.resume();
|
||||
}
|
||||
|
||||
async function testStep(dbg, func, expectedValue) {
|
||||
await stepOverInA(dbg, func, expectedValue);
|
||||
await stepOutOfA(dbg, func, expectedValue);
|
||||
async function testStep(dbg, func, expectedLocation) {
|
||||
await stepOverInA(dbg, func, expectedLocation);
|
||||
await stepOutOfA(dbg, func, expectedLocation);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
return (async function() {
|
||||
const dbg = await setupTestFromUrl("stepping.js");
|
||||
|
||||
await testStep(dbg, "arithmetic", { line: 16, column: 8 });
|
||||
await testStep(dbg, "composition", { line: 21, column: 3 });
|
||||
await testStep(dbg, "chaining", { line: 26, column: 6 });
|
||||
await testStep(dbg, "arithmetic", { line: 17, column: 0 });
|
||||
await testStep(dbg, "composition", { line: 22, column: 0 });
|
||||
await testStep(dbg, "chaining", { line: 27, column: 0 });
|
||||
|
||||
await testFinish(dbg);
|
||||
})();
|
||||
|
|
|
@ -25,7 +25,6 @@ add_task(
|
|||
const step2 = await stepOut(threadFront);
|
||||
// The bug was that we'd step right past the end of the function and never pause.
|
||||
equal(step2.frame.where.line, 2);
|
||||
equal(step2.frame.where.column, 31);
|
||||
deepEqual(step2.why.frameFinished.return, { type: "undefined" });
|
||||
})
|
||||
);
|
||||
|
|
|
@ -22,7 +22,8 @@ add_task(
|
|||
);
|
||||
|
||||
await waitForEvent(threadFront, "paused");
|
||||
const packet = await stepOver(threadFront);
|
||||
await threadFront.stepOver();
|
||||
const packet = await waitForEvent(threadFront, "paused");
|
||||
Assert.equal(packet.frame.where.line, 3, "step to line 3");
|
||||
await threadFront.resume();
|
||||
})
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* Check that is possible to step into both the inner and outer function
|
||||
* calls.
|
||||
*/
|
||||
|
||||
add_task(
|
||||
threadFrontTest(async ({ threadFront, targetFront, debuggee }) => {
|
||||
dumpn("Evaluating test code and waiting for first debugger statement");
|
||||
|
||||
const consoleFront = await targetFront.getFront("console");
|
||||
consoleFront.evaluateJSAsync(
|
||||
`(function () {
|
||||
const a = () => { return 2 };
|
||||
debugger;
|
||||
a(a())
|
||||
})()`
|
||||
);
|
||||
|
||||
await waitForEvent(threadFront, "paused");
|
||||
const step1 = await stepOver(threadFront);
|
||||
Assert.equal(step1.frame.where.line, 4, "step to line 4");
|
||||
|
||||
const step2 = await stepIn(threadFront);
|
||||
Assert.equal(step2.frame.where.line, 2, "step in to line 2");
|
||||
|
||||
const step3 = await stepOut(threadFront);
|
||||
Assert.equal(step3.frame.where.line, 4, "step back to line 4");
|
||||
Assert.equal(step3.frame.where.column, 9, "step out to column 9");
|
||||
|
||||
const step4 = await stepIn(threadFront);
|
||||
Assert.equal(step4.frame.where.line, 2, "step in to line 2");
|
||||
|
||||
await threadFront.resume();
|
||||
})
|
||||
);
|
|
@ -193,7 +193,6 @@ skip-if = true # breakpoint sliding is not supported bug 1525685
|
|||
[test_stepping-10.js]
|
||||
[test_stepping-11.js]
|
||||
[test_stepping-12.js]
|
||||
[test_stepping-13.js]
|
||||
[test_stepping-with-skip-breakpoints.js]
|
||||
[test_framebindings-01.js]
|
||||
[test_framebindings-02.js]
|
||||
|
|
Загрузка…
Ссылка в новой задаче