mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-06 00:31:27 +00:00
First stage of loop optimization (371802, r=igor).
This commit is contained in:
parent
7bf5f8b7a1
commit
187827fa7f
@ -4155,32 +4155,52 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
break;
|
||||
|
||||
case TOK_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 JSParseNode 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.
|
||||
*/
|
||||
js_PushStatement(&cg->treeContext, &stmtInfo, STMT_WHILE_LOOP, top);
|
||||
if (!js_EmitTree(cx, cg, pn->pn_left))
|
||||
return JS_FALSE;
|
||||
noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE);
|
||||
if (noteIndex < 0)
|
||||
return JS_FALSE;
|
||||
beq = EmitJump(cx, cg, JSOP_IFEQ, 0);
|
||||
if (beq < 0)
|
||||
return JS_FALSE;
|
||||
if (!js_EmitTree(cx, cg, pn->pn_right))
|
||||
return JS_FALSE;
|
||||
jmp = EmitJump(cx, cg, JSOP_GOTO, top - CG_OFFSET(cg));
|
||||
jmp = EmitJump(cx, cg, JSOP_GOTO, 0);
|
||||
if (jmp < 0)
|
||||
return JS_FALSE;
|
||||
CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);
|
||||
if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq))
|
||||
top = CG_OFFSET(cg);
|
||||
if (!js_EmitTree(cx, cg, pn->pn_right))
|
||||
return JS_FALSE;
|
||||
CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
|
||||
if (!js_EmitTree(cx, cg, pn->pn_left))
|
||||
return JS_FALSE;
|
||||
beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg));
|
||||
if (beq < 0)
|
||||
return JS_FALSE;
|
||||
if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, beq - jmp))
|
||||
return JS_FALSE;
|
||||
ok = js_PopStatementCG(cx, cg);
|
||||
break;
|
||||
|
||||
case TOK_DO:
|
||||
/* Emit an annotated nop so we know to decompile a 'do' keyword. */
|
||||
if (js_NewSrcNote(cx, cg, SRC_WHILE) < 0 ||
|
||||
js_Emit1(cx, cg, JSOP_NOP) < 0) {
|
||||
noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE);
|
||||
if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_NOP) < 0)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Compile the loop body. */
|
||||
top = CG_OFFSET(cg);
|
||||
@ -4199,12 +4219,14 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
return JS_FALSE;
|
||||
|
||||
/*
|
||||
* No source note needed, because JSOP_IFNE is used only for do-while.
|
||||
* If we ever use JSOP_IFNE for other purposes, we can still avoid yet
|
||||
* another note here, by storing (jmp - top) in the SRC_WHILE note's
|
||||
* offset, and fetching that delta in order to decompile recursively.
|
||||
* Since we use JSOP_IFNE for other purposes as well as for do-while
|
||||
* loops, we must store 1 + (beq - top) in the SRC_WHILE note offset,
|
||||
* and the decompiler must get that delta and decompile recursively.
|
||||
*/
|
||||
if (EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg)) < 0)
|
||||
beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg));
|
||||
if (beq < 0)
|
||||
return JS_FALSE;
|
||||
if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, 1 + (beq - top)))
|
||||
return JS_FALSE;
|
||||
ok = js_PopStatementCG(cx, cg);
|
||||
break;
|
||||
|
@ -1791,8 +1791,18 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
||||
todo = -2;
|
||||
switch (sn ? SN_TYPE(sn) : SRC_NULL) {
|
||||
case SRC_WHILE:
|
||||
++pc;
|
||||
tail = js_GetSrcNoteOffset(sn, 0) - 1;
|
||||
LOCAL_ASSERT(pc[tail] == JSOP_IFNE ||
|
||||
pc[tail] == JSOP_IFNEX);
|
||||
js_printf(SET_MAYBE_BRACE(jp), "\tdo {\n");
|
||||
jp->indent += 4;
|
||||
DECOMPILE_CODE(pc, tail);
|
||||
jp->indent -= 4;
|
||||
js_printf(jp, "\t} while (%s);\n", POP_STR());
|
||||
pc += tail;
|
||||
len = js_CodeSpec[*pc].length;
|
||||
todo = -2;
|
||||
break;
|
||||
|
||||
case SRC_FOR:
|
||||
@ -2571,6 +2581,22 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
||||
case JSOP_GOTOX:
|
||||
sn = js_GetSrcNote(jp->script, pc);
|
||||
switch (sn ? SN_TYPE(sn) : SRC_NULL) {
|
||||
case SRC_WHILE:
|
||||
cond = GetJumpOffset(pc, pc);
|
||||
tail = js_GetSrcNoteOffset(sn, 0);
|
||||
DECOMPILE_CODE(pc + cond, tail - cond);
|
||||
rval = POP_STR();
|
||||
js_printf(SET_MAYBE_BRACE(jp), "\twhile (%s) {\n", rval);
|
||||
jp->indent += 4;
|
||||
DECOMPILE_CODE(pc + oplen, cond - oplen);
|
||||
jp->indent -= 4;
|
||||
js_printf(jp, "\t}\n");
|
||||
pc += tail;
|
||||
LOCAL_ASSERT(*pc == JSOP_IFNE || *pc == JSOP_IFNEX);
|
||||
len = js_CodeSpec[*pc].length;
|
||||
todo = -2;
|
||||
break;
|
||||
|
||||
case SRC_CONT2LABEL:
|
||||
atom = js_GetAtom(cx, &jp->script->atomMap,
|
||||
(jsatomid) js_GetSrcNoteOffset(sn, 0));
|
||||
@ -2580,9 +2606,11 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
||||
RETRACT(&ss->sprinter, rval);
|
||||
js_printf(jp, "\tcontinue %s;\n", rval);
|
||||
break;
|
||||
|
||||
case SRC_CONTINUE:
|
||||
js_printf(jp, "\tcontinue;\n");
|
||||
break;
|
||||
|
||||
case SRC_BREAK2LABEL:
|
||||
atom = js_GetAtom(cx, &jp->script->atomMap,
|
||||
(jsatomid) js_GetSrcNoteOffset(sn, 0));
|
||||
@ -2592,8 +2620,10 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
||||
RETRACT(&ss->sprinter, rval);
|
||||
js_printf(jp, "\tbreak %s;\n", rval);
|
||||
break;
|
||||
|
||||
case SRC_HIDDEN:
|
||||
break;
|
||||
|
||||
default:
|
||||
js_printf(jp, "\tbreak;\n");
|
||||
break;
|
||||
@ -2667,17 +2697,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
||||
todo = -2;
|
||||
break;
|
||||
|
||||
case SRC_WHILE:
|
||||
rval = POP_STR();
|
||||
js_printf(SET_MAYBE_BRACE(jp), "\twhile (%s) {\n", rval);
|
||||
jp->indent += 4;
|
||||
tail = js_GetSrcNoteOffset(sn, 0);
|
||||
DECOMPILE_CODE(pc + oplen, tail - oplen);
|
||||
jp->indent -= 4;
|
||||
js_printf(jp, "\t}\n");
|
||||
todo = -2;
|
||||
break;
|
||||
|
||||
case SRC_COND:
|
||||
xval = JS_strdup(cx, POP_STR());
|
||||
if (!xval)
|
||||
@ -2709,10 +2728,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
||||
|
||||
case JSOP_IFNE:
|
||||
case JSOP_IFNEX:
|
||||
/* Currently, this must be a do-while loop's upward branch. */
|
||||
jp->indent -= 4;
|
||||
js_printf(jp, "\t} while (%s);\n", POP_STR());
|
||||
todo = -2;
|
||||
LOCAL_ASSERT(0);
|
||||
break;
|
||||
|
||||
case JSOP_OR:
|
||||
|
@ -200,7 +200,7 @@ JS_XDRFindClassById(JSXDRState *xdr, uint32 id);
|
||||
* before deserialization of bytecode. If the saved version does not match
|
||||
* the current version, abort deserialization and invalidate the file.
|
||||
*/
|
||||
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 5)
|
||||
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 6)
|
||||
|
||||
/*
|
||||
* Library-private functions.
|
||||
|
Loading…
x
Reference in New Issue
Block a user