Bug 458851 - TM: for-in loops skip every other value in certain cases (r=gal/mrbkap).

This commit is contained in:
Brendan Eich
2008-10-27 22:30:52 -07:00
parent 0e7339ad0e
commit 7e901e72c3
9 changed files with 267 additions and 303 deletions

View File

@@ -1740,6 +1740,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
static const char exception_cookie[] = "/*EXCEPTION*/";
static const char retsub_pc_cookie[] = "/*RETSUB_PC*/";
static const char iter_cookie[] = "/*ITER*/";
static const char forelem_cookie[] = "/*FORELEM*/";
static const char with_cookie[] = "/*WITH*/";
static const char dot_format[] = "%s.%s";
@@ -1760,6 +1761,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
#define LOCAL_ASSERT(expr) LOCAL_ASSERT_RV(expr, NULL)
#define DECOMPILE_CODE(pc,nb) if (!Decompile(ss, pc, nb, JSOP_NOP)) return NULL
#define NEXT_OP(pc) (((pc) + (len) == endpc) ? nextop : pc[len])
#define TOP_STR() GetStr(ss, ss->top - 1)
#define POP_STR() PopStr(ss, op)
#define POP_STR_PREC(prec) PopStrPrec(ss, prec)
@@ -2502,14 +2504,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
sn = NULL;
break;
case JSOP_ENDITER:
sn = js_GetSrcNote(jp->script, pc);
todo = -2;
if (sn && SN_TYPE(sn) == SRC_HIDDEN)
break;
(void) PopOff(ss, op);
break;
case JSOP_ENTERWITH:
LOCAL_ASSERT(!js_GetSrcNote(jp->script, pc));
rval = POP_STR();
@@ -2883,7 +2877,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
pos = ss->top;
while (pos != 0) {
op = (JSOp) ss->opcodes[--pos];
if (op != JSOP_FORLOCAL)
if (op == JSOP_ENTERBLOCK)
break;
}
JS_ASSERT(op == JSOP_ENTERBLOCK);
@@ -2893,7 +2887,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
* in the single string of accumulated |for| heads and optional
* final |if (condition)|.
*/
forpos = pos + 1;
forpos = pos + 2;
LOCAL_ASSERT(forpos < ss->top);
/*
@@ -2965,6 +2959,25 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
js_printf(jp, "\t%s %s;\n", js_throw_str, rval);
break;
case JSOP_ITER:
foreach = (pc[1] & (JSITER_FOREACH | JSITER_KEYVALUE)) ==
JSITER_FOREACH;
todo = SprintCString(&ss->sprinter, iter_cookie);
break;
case JSOP_NEXTITER:
JS_NOT_REACHED("JSOP_NEXTITER");
break;
case JSOP_ENDITER:
sn = js_GetSrcNote(jp->script, pc);
todo = -2;
if (sn && SN_TYPE(sn) == SRC_HIDDEN)
break;
(void) PopOff(ss, op);
(void) PopOff(ss, op);
break;
case JSOP_GOTO:
case JSOP_GOTOX:
sn = js_GetSrcNote(jp->script, pc);
@@ -2973,19 +2986,22 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
/*
* The loop back-edge carries +1 stack balance, for the
* flag processed by JSOP_IFNE. We do not decompile the
* JSOP_IFNE, and instead pass the left-hand side of 'in'
* along the loop edge in this pushed stack slot.
* JSOP_IFNE, and instead push the left-hand side of 'in'
* after the loop edge in this stack slot (the JSOP_FOR*
* opcodes' decompilers do this pushing).
*/
cond = GetJumpOffset(pc, pc);
next = js_GetSrcNoteOffset(sn, 0);
tail = js_GetSrcNoteOffset(sn, 1);
DECOMPILE_CODE(pc + cond, tail - cond);
JS_ASSERT(pc[cond] == JSOP_NEXTITER);
DECOMPILE_CODE(pc + oplen, next - oplen);
lval = POP_STR();
if (ss->inArrayInit || ss->inGenExp) {
lval = POP_STR();
rval = POP_STR();
if (ss->opcodes[ss->top - 1] == JSOP_FORLOCAL) {
ss->sprinter.offset -= PAREN_SLOP;
(void) PopOff(ss, JSOP_NOP);
rval = TOP_STR();
LOCAL_ASSERT(ss->top >= 2);
if (ss->opcodes[ss->top - 2] == JSOP_FORLOCAL) {
ss->sprinter.offset = ss->offsets[ss->top - 1] - PAREN_SLOP;
if (Sprint(&ss->sprinter, " %s (%s in %s)",
foreach ? js_for_each_str : js_for_str,
lval, rval) < 0) {
@@ -3000,7 +3016,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
*/
todo = ss->offsets[ss->top - 1];
} else {
LOCAL_ASSERT(ss->opcodes[ss->top - 1] == JSOP_ENTERBLOCK);
LOCAL_ASSERT(ss->opcodes[ss->top - 2] == JSOP_ENTERBLOCK);
todo = Sprint(&ss->sprinter, " %s (%s in %s)",
foreach ? js_for_each_str : js_for_str,
lval, rval);
@@ -3013,8 +3029,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
* As above, rval or an extension of it must remain
* stacked during loop body decompilation.
*/
lval = POP_STR();
rval = GetStr(ss, ss->top - 1);
rval = GetStr(ss, ss->top - 2);
js_printf(jp, "\t%s (%s in %s) {\n",
foreach ? js_for_each_str : js_for_str,
lval, rval);
@@ -3222,7 +3237,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
i = GET_ARGNO(pc);
goto do_forvarslot;
case JSOP_FORCONST:
case JSOP_FORLOCAL:
sn = js_GetSrcNote(jp->script, pc);
if (!IsVarSlot(jp, pc, &i)) {
@@ -3270,7 +3284,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
break;
case JSOP_FORELEM:
LOCAL_ASSERT(pc[1] == JSOP_IFNE || pc[1] == JSOP_IFNEX);
todo = SprintCString(&ss->sprinter, forelem_cookie);
break;
@@ -4536,12 +4549,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
inXML = JS_FALSE;
break;
case JSOP_ITER:
foreach = (pc[1] & (JSITER_FOREACH | JSITER_KEYVALUE)) ==
JSITER_FOREACH;
todo = -2;
break;
case JSOP_TOXML:
case JSOP_CALLXMLNAME:
case JSOP_XMLNAME:
@@ -4639,7 +4646,9 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
#undef inXML
#undef DECOMPILE_CODE
#undef NEXT_OP
#undef TOP_STR
#undef POP_STR
#undef POP_STR_PREC
#undef LOCAL_ASSERT
#undef ATOM_IS_IDENTIFIER
#undef GET_QUOTE_AND_FMT