зеркало из https://github.com/mozilla/pjs.git
Bug 704369: Move while emit. (r=Waldo)
This commit is contained in:
Родитель
e206adcf82
Коммит
94a4dfa97a
|
@ -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:
|
||||
|
|
Загрузка…
Ссылка в новой задаче