Bug 1129813 - special-case "while" and "for" line notes; r=jimb

This commit is contained in:
Tom Tromey 2015-11-09 08:09:00 +01:00
parent d56c319644
commit 87fd9b0316
2 changed files with 51 additions and 7 deletions

View File

@ -5770,14 +5770,17 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, ptrdiff_t top)
bool bool
BytecodeEmitter::emitFor(ParseNode* pn, ptrdiff_t top) BytecodeEmitter::emitFor(ParseNode* pn, ptrdiff_t top)
{ {
if (pn->pn_left->isKind(PNK_FORHEAD))
return emitCStyleFor(pn, top);
if (!updateLineNumberNotes(pn->pn_pos.begin))
return false;
if (pn->pn_left->isKind(PNK_FORIN)) if (pn->pn_left->isKind(PNK_FORIN))
return emitForIn(pn, top); return emitForIn(pn, top);
if (pn->pn_left->isKind(PNK_FOROF)) MOZ_ASSERT(pn->pn_left->isKind(PNK_FOROF));
return emitForOf(StmtType::FOR_OF_LOOP, pn, top); return emitForOf(StmtType::FOR_OF_LOOP, pn, top);
MOZ_ASSERT(pn->pn_left->isKind(PNK_FORHEAD));
return emitCStyleFor(pn, top);
} }
MOZ_NEVER_INLINE bool MOZ_NEVER_INLINE bool
@ -6021,6 +6024,20 @@ BytecodeEmitter::emitWhile(ParseNode* pn, ptrdiff_t top)
* . . . * . . .
* N N*(ifeq-fail; goto); ifeq-pass goto; N*ifne-pass; ifne-fail * N N*(ifeq-fail; goto); ifeq-pass goto; N*ifne-pass; ifne-fail
*/ */
// If we have a single-line while, like "while (x) ;", we want to
// emit the line note before the initial goto, so that the
// debugger sees a single entry point. This way, if there is a
// breakpoint on the line, it will only fire once; and "next"ing
// will skip the whole loop. However, for the multi-line case we
// want to emit the line note after the initial goto, so that
// "cont" stops on each iteration -- but without a stop before the
// first iteration.
if (parser->tokenStream.srcCoords.lineNum(pn->pn_pos.begin) ==
parser->tokenStream.srcCoords.lineNum(pn->pn_pos.end) &&
!updateSourceCoordNotes(pn->pn_pos.begin))
return false;
LoopStmtInfo stmtInfo(cx); LoopStmtInfo stmtInfo(cx);
pushLoopStatement(&stmtInfo, StmtType::WHILE_LOOP, top); pushLoopStatement(&stmtInfo, StmtType::WHILE_LOOP, top);
@ -7547,8 +7564,11 @@ BytecodeEmitter::emitTree(ParseNode* pn)
ptrdiff_t top = offset(); ptrdiff_t top = offset();
pn->pn_offset = top; pn->pn_offset = top;
/* Emit notes to tell the current bytecode's source line number. */ /* Emit notes to tell the current bytecode's source line number.
if (!updateLineNumberNotes(pn->pn_pos.begin)) However, a couple trees require special treatment; see the
relevant emitter functions for details. */
if (pn->getKind() != PNK_WHILE && pn->getKind() != PNK_FOR &&
!updateLineNumberNotes(pn->pn_pos.begin))
return false; return false;
switch (pn->getKind()) { switch (pn->getKind()) {

View File

@ -0,0 +1,24 @@
// A "while" or a "for" loop should have a single entry point.
var g = newGlobal();
var dbg = new Debugger(g);
dbg.onDebuggerStatement = function(frame) {
var s = frame.eval('f').return.script;
// There should be just a single entry point for the first line of
// the function. See below to understand the "+2".
assertEq(s.getLineOffsets(g.line0 + 2).length, 1);
};
function test(code) {
g.eval('var line0 = Error().lineNumber;\n' +
'function f() {\n' + // line0 + 1
code + '\n' + // line0 + 2 -- see above
'}\n' +
'debugger;');
}
test('while (false)\n;');
test('for (;false;)\n;');