Bug 704369: Move while emit. (r=Waldo)

This commit is contained in:
Chris Leary 2011-11-21 17:59:27 -08:00
parent efabf9287d
commit 5787980ae7

View File

@ -5953,6 +5953,62 @@ EmitDo(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
return PopStatementBCE(cx, bce);
}
static bool
EmitWhile(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
{
/*
* Minimize bytecodes issued for one or more iterations by jumping to
* the condition below the body and closing the loop if the condition
* is true with a backward branch. For iteration count i:
*
* i test at the top test at the bottom
* = =============== ==================
* 0 ifeq-pass goto; ifne-fail
* 1 ifeq-fail; goto; ifne-pass goto; ifne-pass; ifne-fail
* 2 2*(ifeq-fail; goto); ifeq-pass goto; 2*ifne-pass; ifne-fail
* . . .
* N N*(ifeq-fail; goto); ifeq-pass goto; N*ifne-pass; ifne-fail
*
* SpiderMonkey, pre-mozilla.org, emitted while parsing and so used
* test at the top. When ParseNode trees were added during the ES3
* work (1998-9), the code generation scheme was not optimized, and
* the decompiler continued to take advantage of the branch and jump
* that bracketed the body. But given the SRC_WHILE note, it is easy
* to support the more efficient scheme.
*/
StmtInfo stmtInfo;
PushStatement(bce, &stmtInfo, STMT_WHILE_LOOP, top);
ptrdiff_t noteIndex = NewSrcNote(cx, bce, SRC_WHILE);
if (noteIndex < 0)
return JS_FALSE;
ptrdiff_t jmp = EmitJump(cx, bce, JSOP_GOTO, 0);
if (jmp < 0)
return JS_FALSE;
ptrdiff_t noteIndex2 = NewSrcNote(cx, bce, SRC_LOOPHEAD);
if (noteIndex2 < 0)
return JS_FALSE;
top = EmitTraceOp(cx, bce, pn->pn_right);
if (top < 0)
return JS_FALSE;
if (!EmitTree(cx, bce, pn->pn_right))
return JS_FALSE;
CHECK_AND_SET_JUMP_OFFSET_AT(cx, bce, jmp);
if (!EmitTree(cx, bce, pn->pn_left))
return JS_FALSE;
ptrdiff_t beq = EmitJump(cx, bce, JSOP_IFNE, top - bce->offset());
if (beq < 0)
return JS_FALSE;
/*
* Be careful: We must set noteIndex2 before noteIndex in case the noteIndex
* note gets bigger.
*/
if (!SetSrcNoteOffset(cx, bce, noteIndex2, 0, beq - top))
return JS_FALSE;
if (!SetSrcNoteOffset(cx, bce, noteIndex, 0, beq - jmp))
return JS_FALSE;
return PopStatementBCE(cx, bce);
}
JSBool
frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
{
@ -5963,7 +6019,7 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
ParseNode *pn2, *pn3;
JSAtom *atom;
jsatomid atomIndex;
ptrdiff_t noteIndex, noteIndex2;
ptrdiff_t noteIndex;
SrcNoteType noteType;
jsbytecode *pc;
JSOp op;
@ -6018,56 +6074,7 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
break;
case PNK_WHILE:
/*
* Minimize bytecodes issued for one or more iterations by jumping to
* the condition below the body and closing the loop if the condition
* is true with a backward branch. For iteration count i:
*
* i test at the top test at the bottom
* = =============== ==================
* 0 ifeq-pass goto; ifne-fail
* 1 ifeq-fail; goto; ifne-pass goto; ifne-pass; ifne-fail
* 2 2*(ifeq-fail; goto); ifeq-pass goto; 2*ifne-pass; ifne-fail
* . . .
* N N*(ifeq-fail; goto); ifeq-pass goto; N*ifne-pass; ifne-fail
*
* SpiderMonkey, pre-mozilla.org, emitted while parsing and so used
* test at the top. When ParseNode trees were added during the ES3
* work (1998-9), the code generation scheme was not optimized, and
* the decompiler continued to take advantage of the branch and jump
* that bracketed the body. But given the SRC_WHILE note, it is easy
* to support the more efficient scheme.
*/
PushStatement(bce, &stmtInfo, STMT_WHILE_LOOP, top);
noteIndex = NewSrcNote(cx, bce, SRC_WHILE);
if (noteIndex < 0)
return JS_FALSE;
jmp = EmitJump(cx, bce, JSOP_GOTO, 0);
if (jmp < 0)
return JS_FALSE;
noteIndex2 = NewSrcNote(cx, bce, SRC_LOOPHEAD);
if (noteIndex2 < 0)
return JS_FALSE;
top = EmitTraceOp(cx, bce, pn->pn_right);
if (top < 0)
return JS_FALSE;
if (!EmitTree(cx, bce, pn->pn_right))
return JS_FALSE;
CHECK_AND_SET_JUMP_OFFSET_AT(cx, bce, jmp);
if (!EmitTree(cx, bce, pn->pn_left))
return JS_FALSE;
beq = EmitJump(cx, bce, JSOP_IFNE, top - bce->offset());
if (beq < 0)
return JS_FALSE;
/*
* Be careful: We must set noteIndex2 before noteIndex in case the noteIndex
* note gets bigger.
*/
if (!SetSrcNoteOffset(cx, bce, noteIndex2, 0, beq - top))
return JS_FALSE;
if (!SetSrcNoteOffset(cx, bce, noteIndex, 0, beq - jmp))
return JS_FALSE;
ok = PopStatementBCE(cx, bce);
ok = EmitWhile(cx, bce, pn, top);
break;
case PNK_DOWHILE: