зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1013219 - set line number of return instruction; r=efaust,fitzgen,ejpbruel
This commit is contained in:
Родитель
01a6e5dccb
Коммит
c432b14b9b
|
@ -36,13 +36,13 @@ function test() {
|
|||
let stepTests = [
|
||||
{key: 'VK_F11', keyRepeat: 1, caretLine: 16},
|
||||
{key: 'VK_F11', keyRepeat: 2, caretLine: 18},
|
||||
{key: 'VK_F11', keyRepeat: 2, caretLine: 26},
|
||||
{key: 'VK_F10', keyRepeat: 1, caretLine: 18},
|
||||
{key: 'VK_F11', keyRepeat: 1, caretLine: 19},
|
||||
{key: 'VK_F11', keyRepeat: 5, caretLine: 29},
|
||||
{key: 'VK_F11', modifier:'Shift', keyRepeat: 1, caretLine: 32},
|
||||
{key: 'VK_F11', modifier:'Shift', keyRepeat: 2, caretLine: 32},
|
||||
{key: 'VK_F11', modifier:'Shift', keyRepeat: 2, caretLine: 20}
|
||||
{key: 'VK_F11', keyRepeat: 2, caretLine: 27},
|
||||
{key: 'VK_F10', keyRepeat: 1, caretLine: 27},
|
||||
{key: 'VK_F11', keyRepeat: 1, caretLine: 18},
|
||||
{key: 'VK_F11', keyRepeat: 5, caretLine: 32},
|
||||
{key: 'VK_F11', modifier:'Shift', keyRepeat: 1, caretLine: 29},
|
||||
{key: 'VK_F11', modifier:'Shift', keyRepeat: 2, caretLine: 34},
|
||||
{key: 'VK_F11', modifier:'Shift', keyRepeat: 2, caretLine: 34}
|
||||
];
|
||||
// Trigger script that stops at debugger statement
|
||||
executeSoon(() => generateMouseClickInTab(gTab,
|
||||
|
|
|
@ -23,7 +23,7 @@ function test() {
|
|||
|
||||
function testNormalReturn() {
|
||||
waitForSourceAndCaretAndScopes(gPanel, ".html", 17).then(() => {
|
||||
waitForCaretAndScopes(gPanel, 19).then(() => {
|
||||
waitForCaretAndScopes(gPanel, 20).then(() => {
|
||||
let innerScope = gVars.getScopeAtIndex(0);
|
||||
let returnVar = innerScope.get("<return>");
|
||||
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
function f() {
|
||||
function g() { var a = 1; var b = 2; return; } g();
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
function f() {
|
||||
function g() {
|
||||
var a = 1;
|
||||
var b = 2;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
g();
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
var SOURCE_URL = getFileUrl("setBreakpoint-on-line-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: 8 };
|
||||
let [packet, breakpointClient] = yield setBreakpoint(sourceClient, location);
|
||||
do_check_false(packet.isPending); // NOTE: Change this when bug 1148356 lands
|
||||
do_check_true("actualLocation" in packet);
|
||||
let actualLocation = packet.actualLocation;
|
||||
do_check_eq(actualLocation.line, 11);
|
||||
|
||||
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);
|
||||
|
||||
yield resume(threadClient);
|
||||
yield close(client);
|
||||
|
||||
do_test_finished();
|
||||
});
|
||||
}
|
|
@ -43,7 +43,7 @@ function test_simple_stepping()
|
|||
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
|
||||
// Check that the return value is 10.
|
||||
do_check_eq(aPacket.type, "paused");
|
||||
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 4);
|
||||
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 5);
|
||||
do_check_eq(aPacket.why.type, "resumeLimit");
|
||||
do_check_eq(aPacket.why.frameFinished.return, 10);
|
||||
|
||||
|
|
|
@ -54,8 +54,11 @@ const testSteppingAndReturns = Task.async(function*() {
|
|||
const step3 = yield stepOver(gClient, threadClient);
|
||||
equal(step3.frame.where.line, 13, "Should step to line 13");
|
||||
const step4 = yield stepOver(gClient, threadClient);
|
||||
equal(step4.frame.where.line, 13, "Should step out of the function from line 13");
|
||||
ok(step4.why.frameFinished, "This should be the explicit function return");
|
||||
equal(step4.frame.where.line, 15, "Should step out of the function from line 15");
|
||||
// This step is a bit funny, see bug 1013219 for details.
|
||||
const step5 = yield stepOver(gClient, threadClient);
|
||||
equal(step5.frame.where.line, 15, "Should step out of the function from line 15");
|
||||
ok(step5.why.frameFinished, "This should be the explicit function return");
|
||||
|
||||
finishClient(gClient, gCallback);
|
||||
});
|
||||
|
|
|
@ -23,14 +23,12 @@ support-files =
|
|||
setBreakpoint-on-column-in-gcd-script.js
|
||||
setBreakpoint-on-column-with-no-offsets.js
|
||||
setBreakpoint-on-column-with-no-offsets-at-end-of-line.js
|
||||
setBreakpoint-on-column-with-no-offsets-at-end-of-script.js
|
||||
setBreakpoint-on-column-with-no-offsets-in-gcd-script.js
|
||||
setBreakpoint-on-line.js
|
||||
setBreakpoint-on-line-in-gcd-script.js
|
||||
setBreakpoint-on-line-with-multiple-offsets.js
|
||||
setBreakpoint-on-line-with-multiple-statements.js
|
||||
setBreakpoint-on-line-with-no-offsets.js
|
||||
setBreakpoint-on-line-with-no-offsets-at-end-of-script.js
|
||||
setBreakpoint-on-line-with-no-offsets-in-gcd-script.js
|
||||
|
||||
[test_ScriptStore.js]
|
||||
|
@ -263,7 +261,6 @@ reason = bug 1014071
|
|||
[test_setBreakpoint-on-line-with-multiple-offsets.js]
|
||||
[test_setBreakpoint-on-line-with-multiple-statements.js]
|
||||
[test_setBreakpoint-on-line-with-no-offsets.js]
|
||||
[test_setBreakpoint-on-line-with-no-offsets-at-end-of-script.js]
|
||||
[test_setBreakpoint-on-line-with-no-offsets-in-gcd-script.js]
|
||||
[test_safe-getter.js]
|
||||
[test_client_close.js]
|
||||
|
|
|
@ -346,12 +346,16 @@ BytecodeCompiler::prepareAndEmitTree(ParseNode** ppn)
|
|||
{
|
||||
if (!FoldConstants(cx, ppn, parser.ptr()) ||
|
||||
!NameFunctions(cx, *ppn) ||
|
||||
!emitter->updateLocalsToFrameSlots() ||
|
||||
!emitter->emitTree(*ppn))
|
||||
!emitter->updateLocalsToFrameSlots())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
emitter->setFunctionBodyEndPos((*ppn)->pn_pos);
|
||||
|
||||
if (!emitter->emitTree(*ppn))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -828,7 +832,7 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
|
|||
MOZ_ASSERT(!options.forEval);
|
||||
BytecodeEmitter bce(/* parent = */ nullptr, &parser, pn->pn_funbox, script, lazy,
|
||||
/* insideEval = */ false, /* evalCaller = */ nullptr,
|
||||
/* insideNonGlobalEval = */ false, options.lineno,
|
||||
/* insideNonGlobalEval = */ false, pn->pn_pos,
|
||||
BytecodeEmitter::LazyFunction);
|
||||
if (!bce.init())
|
||||
return false;
|
||||
|
|
|
@ -143,12 +143,27 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
|
|||
insideEval(insideEval),
|
||||
insideNonGlobalEval(insideNonGlobalEval),
|
||||
insideModule(false),
|
||||
emitterMode(emitterMode)
|
||||
emitterMode(emitterMode),
|
||||
functionBodyEndPosSet(false)
|
||||
{
|
||||
MOZ_ASSERT_IF(evalCaller, insideEval);
|
||||
MOZ_ASSERT_IF(emitterMode == LazyFunction, lazyScript);
|
||||
}
|
||||
|
||||
BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
|
||||
Parser<FullParseHandler>* parser, SharedContext* sc,
|
||||
HandleScript script, Handle<LazyScript*> lazyScript,
|
||||
bool insideEval, HandleScript evalCaller,
|
||||
bool insideNonGlobalEval, TokenPos bodyPosition,
|
||||
EmitterMode emitterMode)
|
||||
: BytecodeEmitter(parent, parser, sc, script, lazyScript, insideEval,
|
||||
evalCaller, insideNonGlobalEval,
|
||||
parser->tokenStream.srcCoords.lineNum(bodyPosition.begin),
|
||||
emitterMode)
|
||||
{
|
||||
setFunctionBodyEndPos(bodyPosition);
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::init()
|
||||
{
|
||||
|
@ -3589,6 +3604,7 @@ BytecodeEmitter::emitFunctionScript(ParseNode* body)
|
|||
switchToMain();
|
||||
}
|
||||
|
||||
setFunctionBodyEndPos(body->pn_pos);
|
||||
if (!emitTree(body))
|
||||
return false;
|
||||
|
||||
|
@ -3694,6 +3710,7 @@ BytecodeEmitter::emitModuleScript(ParseNode* body)
|
|||
// may walk the scope chain of currently compiling scripts.
|
||||
JSScript::linkToModuleFromEmitter(cx, script, modulebox);
|
||||
|
||||
setFunctionBodyEndPos(body->pn_pos);
|
||||
if (!emitTree(body))
|
||||
return false;
|
||||
|
||||
|
@ -6413,10 +6430,9 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
|
|||
|
||||
script->bindings = funbox->bindings;
|
||||
|
||||
uint32_t lineNum = parser->tokenStream.srcCoords.lineNum(pn->pn_pos.begin);
|
||||
BytecodeEmitter bce2(this, parser, funbox, script, /* lazyScript = */ nullptr,
|
||||
insideEval, evalCaller,
|
||||
insideNonGlobalEval, lineNum, emitterMode);
|
||||
insideNonGlobalEval, pn->pn_pos, emitterMode);
|
||||
if (!bce2.init())
|
||||
return false;
|
||||
|
||||
|
@ -6787,6 +6803,13 @@ BytecodeEmitter::emitReturn(ParseNode* pn)
|
|||
return false;
|
||||
}
|
||||
|
||||
// We know functionBodyEndPos is set because "return" is only
|
||||
// valid in a function, and so we've passed through
|
||||
// emitFunctionScript.
|
||||
MOZ_ASSERT(functionBodyEndPosSet);
|
||||
if (!updateSourceCoordNotes(functionBodyEndPos))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* EmitNonLocalJumpFixup may add fixup bytecode to close open try
|
||||
* blocks having finally clauses and to exit intermingled let blocks.
|
||||
|
|
|
@ -234,6 +234,11 @@ struct BytecodeEmitter
|
|||
|
||||
const EmitterMode emitterMode;
|
||||
|
||||
// The end location of a function body that is being emitted.
|
||||
uint32_t functionBodyEndPos;
|
||||
// Whether functionBodyEndPos was set.
|
||||
bool functionBodyEndPosSet;
|
||||
|
||||
/*
|
||||
* Note that BytecodeEmitters are magic: they own the arena "top-of-stack"
|
||||
* space above their tempMark points. This means that you cannot alloc from
|
||||
|
@ -244,6 +249,14 @@ struct BytecodeEmitter
|
|||
HandleScript script, Handle<LazyScript*> lazyScript,
|
||||
bool insideEval, HandleScript evalCaller,
|
||||
bool insideNonGlobalEval, uint32_t lineNum, EmitterMode emitterMode = Normal);
|
||||
|
||||
// An alternate constructor that uses a TokenPos for the starting
|
||||
// line and that sets functionBodyEndPos as well.
|
||||
BytecodeEmitter(BytecodeEmitter* parent, Parser<FullParseHandler>* parser, SharedContext* sc,
|
||||
HandleScript script, Handle<LazyScript*> lazyScript,
|
||||
bool insideEval, HandleScript evalCaller,
|
||||
bool insideNonGlobalEval, TokenPos bodyPosition, EmitterMode emitterMode = Normal);
|
||||
|
||||
bool init();
|
||||
bool updateLocalsToFrameSlots();
|
||||
|
||||
|
@ -304,6 +317,11 @@ struct BytecodeEmitter
|
|||
unsigned currentLine() const { return current->currentLine; }
|
||||
unsigned lastColumn() const { return current->lastColumn; }
|
||||
|
||||
void setFunctionBodyEndPos(TokenPos pos) {
|
||||
functionBodyEndPos = pos.end;
|
||||
functionBodyEndPosSet = true;
|
||||
}
|
||||
|
||||
bool reportError(ParseNode* pn, unsigned errorNumber, ...);
|
||||
bool reportStrictWarning(ParseNode* pn, unsigned errorNumber, ...);
|
||||
bool reportStrictModeError(ParseNode* pn, unsigned errorNumber, ...);
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
// Stepping through a function with a return statement should pause on
|
||||
// the closing brace of the function.
|
||||
|
||||
var g = newGlobal();
|
||||
var dbg = Debugger(g);
|
||||
var log;
|
||||
|
||||
function test(fnStr) {
|
||||
log = '';
|
||||
g.eval(fnStr);
|
||||
|
||||
dbg.onDebuggerStatement = function(frame) {
|
||||
frame.onStep = function() {
|
||||
let {lineNumber, isEntryPoint} = frame.script.getOffsetLocation(frame.offset);
|
||||
if (isEntryPoint) {
|
||||
log += lineNumber + ' ';
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
g.eval("f(23);");
|
||||
}
|
||||
|
||||
test("function f(x) {\n" + // 1
|
||||
" debugger;\n" + // 2
|
||||
" return 23 + x;\n" + // 3
|
||||
"}\n"); // 4
|
||||
assertEq(log, '3 4 ');
|
||||
|
||||
test("function f(x) {\n" + // 1
|
||||
" debugger;\n" + // 2
|
||||
" return;\n" + // 3
|
||||
"}\n"); // 4
|
||||
assertEq(log, '3 4 ');
|
|
@ -48,7 +48,7 @@ assertEq(Object.keys(offsets).length, 2);
|
|||
// have no effect on this one.
|
||||
doSingleStep = false;
|
||||
g.eval('t(0, 0, 0)');
|
||||
assertEq(Object.keys(offsets).length, 6);
|
||||
assertEq(Object.keys(offsets).length, 7);
|
||||
doSingleStep = true;
|
||||
|
||||
// Single-step in an eval frame. This should reach every line but the
|
||||
|
|
Загрузка…
Ссылка в новой задаче