mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 458851 - TM: for-in loops skip every other value in certain cases (r=gal/mrbkap).
This commit is contained in:
parent
bf1a78f4fe
commit
51f987553a
@ -2365,14 +2365,14 @@ EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg,
|
|||||||
do_indexconst: {
|
do_indexconst: {
|
||||||
JSAtomListElement *ale;
|
JSAtomListElement *ale;
|
||||||
jsatomid atomIndex;
|
jsatomid atomIndex;
|
||||||
|
|
||||||
ale = js_IndexAtom(cx, pn->pn_atom, &cg->atomList);
|
ale = js_IndexAtom(cx, pn->pn_atom, &cg->atomList);
|
||||||
if (!ale)
|
if (!ale)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
atomIndex = ALE_INDEX(ale);
|
atomIndex = ALE_INDEX(ale);
|
||||||
return EmitSlotIndexOp(cx, op, pn2->pn_slot, atomIndex, cg);
|
return EmitSlotIndexOp(cx, op, pn2->pn_slot, atomIndex, cg);
|
||||||
}
|
}
|
||||||
|
|
||||||
default:;
|
default:;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3849,28 +3849,6 @@ EmitFunctionDefNop(JSContext *cx, JSCodeGenerator *cg, uintN index)
|
|||||||
js_Emit1(cx, cg, JSOP_NOP) >= 0;
|
js_Emit1(cx, cg, JSOP_NOP) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: 458851 -- that bug's patch should re-inline this into one place. */
|
|
||||||
static JSBool
|
|
||||||
EmitForInLoopBody(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *stmt,
|
|
||||||
JSParseNode *body, intN noteIndex, ptrdiff_t jmp)
|
|
||||||
{
|
|
||||||
/* Set the first srcnote offset so we can find the start of the loop body. */
|
|
||||||
if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, CG_OFFSET(cg) - jmp))
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
/* Emit code for the loop body. */
|
|
||||||
if (!js_EmitTree(cx, cg, body))
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
/* Set loop and enclosing "update" offsets, for continue. */
|
|
||||||
do {
|
|
||||||
stmt->update = CG_OFFSET(cg);
|
|
||||||
} while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
|
|
||||||
|
|
||||||
CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
|
|
||||||
return JS_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
{
|
{
|
||||||
@ -3954,7 +3932,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||||||
cg2->staticDepth = cg->staticDepth + 1;
|
cg2->staticDepth = cg->staticDepth + 1;
|
||||||
cg2->parent = cg;
|
cg2->parent = cg;
|
||||||
|
|
||||||
/* We metered the max scope depth when parsed the function. */
|
/* We metered the max scope depth when parsed the function. */
|
||||||
JS_SCOPE_DEPTH_METERING(cg2->treeContext.maxScopeDepth = (uintN) -1);
|
JS_SCOPE_DEPTH_METERING(cg2->treeContext.maxScopeDepth = (uintN) -1);
|
||||||
if (!js_EmitFunctionScript(cx, cg2, pn->pn_body)) {
|
if (!js_EmitFunctionScript(cx, cg2, pn->pn_body)) {
|
||||||
pn = NULL;
|
pn = NULL;
|
||||||
@ -4239,7 +4217,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||||||
* destructuring for-in).
|
* destructuring for-in).
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(pn->pn_op == JSOP_ITER);
|
JS_ASSERT(pn->pn_op == JSOP_ITER);
|
||||||
if (js_Emit2(cx, cg, PN_OP(pn), (uint8) pn->pn_iflags) < 0)
|
if (js_Emit2(cx, cg, JSOP_ITER, (uint8) pn->pn_iflags) < 0)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
/* Annotate so the decompiler can find the loop-closing jump. */
|
/* Annotate so the decompiler can find the loop-closing jump. */
|
||||||
@ -4258,6 +4236,10 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||||||
top = CG_OFFSET(cg);
|
top = CG_OFFSET(cg);
|
||||||
SET_STATEMENT_TOP(&stmtInfo, top);
|
SET_STATEMENT_TOP(&stmtInfo, top);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
intN loopDepth = cg->stackDepth;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compile a JSOP_FOR* bytecode based on the left hand side.
|
* Compile a JSOP_FOR* bytecode based on the left hand side.
|
||||||
*
|
*
|
||||||
@ -4291,9 +4273,6 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||||||
/* FALL THROUGH */
|
/* FALL THROUGH */
|
||||||
|
|
||||||
case TOK_NAME:
|
case TOK_NAME:
|
||||||
if (!EmitForInLoopBody(cx, cg, &stmtInfo, pn->pn_right, noteIndex, jmp))
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Always annotate JSOP_FORLOCAL if given input of the form
|
* Always annotate JSOP_FORLOCAL if given input of the form
|
||||||
* 'for (let x in * o)' -- the decompiler must not hoist the
|
* 'for (let x in * o)' -- the decompiler must not hoist the
|
||||||
@ -4333,7 +4312,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||||||
if (pn3->pn_slot >= 0) {
|
if (pn3->pn_slot >= 0) {
|
||||||
if (pn3->pn_const) {
|
if (pn3->pn_const) {
|
||||||
JS_ASSERT(op == JSOP_FORLOCAL);
|
JS_ASSERT(op == JSOP_FORLOCAL);
|
||||||
op = JSOP_FORCONST;
|
js_ReportCompileErrorNumber(cx, CG_TS(cg), pn3, JSREPORT_ERROR,
|
||||||
|
JSMSG_BAD_FOR_LEFTSIDE);
|
||||||
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
atomIndex = (jsatomid) pn3->pn_slot;
|
atomIndex = (jsatomid) pn3->pn_slot;
|
||||||
EMIT_UINT16_IMM_OP(op, atomIndex);
|
EMIT_UINT16_IMM_OP(op, atomIndex);
|
||||||
@ -4352,8 +4333,6 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||||||
if (!CheckSideEffects(cx, cg, pn3->pn_expr, &useful))
|
if (!CheckSideEffects(cx, cg, pn3->pn_expr, &useful))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
if (!useful) {
|
if (!useful) {
|
||||||
if (!EmitForInLoopBody(cx, cg, &stmtInfo, pn->pn_right, noteIndex, jmp))
|
|
||||||
return JS_FALSE;
|
|
||||||
if (!EmitPropOp(cx, pn3, JSOP_FORPROP, cg, JS_FALSE))
|
if (!EmitPropOp(cx, pn3, JSOP_FORPROP, cg, JS_FALSE))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
break;
|
break;
|
||||||
@ -4364,19 +4343,10 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||||||
destructuring_for:
|
destructuring_for:
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
/*
|
if (js_Emit1(cx, cg, JSOP_FORELEM) < 0)
|
||||||
* We separate the first/next bytecode from the enumerator
|
return JS_FALSE;
|
||||||
* variable binding to avoid any side-effects in the index
|
JS_ASSERT(cg->stackDepth >= 3);
|
||||||
* expression (e.g., for (x[i++] in {}) should not bind x[i]
|
|
||||||
* or increment i at all).
|
|
||||||
*
|
|
||||||
* At this point, JSOP_FORELEM (emitted after the loop body)
|
|
||||||
* has pushed the next value to iterate, but it is downstream
|
|
||||||
* of us in js_Emit* order, so we must adjust the stack depth
|
|
||||||
* manually.
|
|
||||||
*/
|
|
||||||
if ((uintN) ++cg->stackDepth > cg->maxStackDepth)
|
|
||||||
cg->maxStackDepth = cg->stackDepth;
|
|
||||||
#if JS_HAS_DESTRUCTURING
|
#if JS_HAS_DESTRUCTURING
|
||||||
if (pn3->pn_type == TOK_RB || pn3->pn_type == TOK_RC) {
|
if (pn3->pn_type == TOK_RB || pn3->pn_type == TOK_RC) {
|
||||||
if (!EmitDestructuringOps(cx, cg, op, pn3))
|
if (!EmitDestructuringOps(cx, cg, op, pn3))
|
||||||
@ -4405,24 +4375,32 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||||||
#endif
|
#endif
|
||||||
if (!EmitElemOp(cx, pn3, JSOP_ENUMELEM, cg))
|
if (!EmitElemOp(cx, pn3, JSOP_ENUMELEM, cg))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
if (!EmitForInLoopBody(cx, cg, &stmtInfo, pn->pn_right, noteIndex, jmp))
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* JSOP_FORELEM has nuses 1, ndefs 3, modeling the case where
|
|
||||||
* it pushes the next value and then true, to keep iterating.
|
|
||||||
* For symmetry here, we manually drop cg->stackDepth after to
|
|
||||||
* reflect the fact that we've emitted JSOP_ENUMELEM already.
|
|
||||||
*/
|
|
||||||
if (js_Emit1(cx, cg, JSOP_FORELEM) < 0)
|
|
||||||
return JS_FALSE;
|
|
||||||
JS_ASSERT(cg->stackDepth >= 3);
|
|
||||||
--cg->stackDepth;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pop and test the loop condition generated by JSOP_FOR*. */
|
/* The stack should be balanced around the JSOP_FOR* opcode sequence. */
|
||||||
|
JS_ASSERT(cg->stackDepth == loopDepth);
|
||||||
|
|
||||||
|
/* Set the first srcnote offset so we can find the start of the loop body. */
|
||||||
|
if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, CG_OFFSET(cg) - jmp))
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
/* Emit code for the loop body. */
|
||||||
|
if (!js_EmitTree(cx, cg, pn->pn_right))
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
/* Set loop and enclosing "update" offsets, for continue. */
|
||||||
|
stmt = &stmtInfo;
|
||||||
|
do {
|
||||||
|
stmt->update = CG_OFFSET(cg);
|
||||||
|
} while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fixup the goto that starts the loop to jump down to JSOP_NEXTITER.
|
||||||
|
*/
|
||||||
|
CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
|
||||||
|
if (js_Emit1(cx, cg, JSOP_NEXTITER) < 0)
|
||||||
|
return JS_FALSE;
|
||||||
beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg));
|
beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg));
|
||||||
if (beq < 0)
|
if (beq < 0)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
@ -4559,12 +4537,13 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||||||
|
|
||||||
if (pn2->pn_type == TOK_IN) {
|
if (pn2->pn_type == TOK_IN) {
|
||||||
/*
|
/*
|
||||||
* JSOP_ENDITER needs a slot to save an exception thrown from the
|
* JSOP_ENDITER must have a slot to save an exception thrown from
|
||||||
* body of for-in loop when closing the iterator object.
|
* the body of for-in loop when closing the iterator object, and
|
||||||
|
* fortunately it does: the slot that was set by JSOP_NEXTITER to
|
||||||
|
* the return value of iterator.next().
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(js_CodeSpec[JSOP_ENDITER].format & JOF_TMPSLOT);
|
JS_ASSERT(js_CodeSpec[JSOP_ENDITER].nuses == 2);
|
||||||
if (!NewTryNote(cx, cg, JSTRY_ITER, cg->stackDepth, top,
|
if (!NewTryNote(cx, cg, JSTRY_ITER, cg->stackDepth, top, CG_OFFSET(cg)) ||
|
||||||
CG_OFFSET(cg)) ||
|
|
||||||
js_Emit1(cx, cg, JSOP_ENDITER) < 0) {
|
js_Emit1(cx, cg, JSOP_ENDITER) < 0) {
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
@ -5856,7 +5835,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||||||
argc = pn->pn_count - 1;
|
argc = pn->pn_count - 1;
|
||||||
if (js_Emit3(cx, cg, PN_OP(pn), ARGC_HI(argc), ARGC_LO(argc)) < 0)
|
if (js_Emit3(cx, cg, PN_OP(pn), ARGC_HI(argc), ARGC_LO(argc)) < 0)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
if (PN_OP(pn) == JSOP_EVAL)
|
if (PN_OP(pn) == JSOP_EVAL)
|
||||||
EMIT_UINT16_IMM_OP(JSOP_LINENO, pn->pn_pos.begin.lineno);
|
EMIT_UINT16_IMM_OP(JSOP_LINENO, pn->pn_pos.begin.lineno);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2002,8 +2002,6 @@ js_TraceOpcode(JSContext *cx, jsint len)
|
|||||||
prevop = (JSOp) regs->pc[-len];
|
prevop = (JSOp) regs->pc[-len];
|
||||||
ndefs = js_CodeSpec[prevop].ndefs;
|
ndefs = js_CodeSpec[prevop].ndefs;
|
||||||
if (ndefs != 0) {
|
if (ndefs != 0) {
|
||||||
if (prevop == JSOP_FORELEM && regs->sp[-1] == JSVAL_FALSE)
|
|
||||||
--ndefs;
|
|
||||||
for (n = -ndefs; n < 0; n++) {
|
for (n = -ndefs; n < 0; n++) {
|
||||||
char *bytes = js_DecompileValueGenerator(cx, n, regs->sp[n],
|
char *bytes = js_DecompileValueGenerator(cx, n, regs->sp[n],
|
||||||
NULL);
|
NULL);
|
||||||
@ -3192,130 +3190,88 @@ js_Interpret(JSContext *cx)
|
|||||||
END_CASE(JSOP_IN)
|
END_CASE(JSOP_IN)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_ITER)
|
BEGIN_CASE(JSOP_ITER)
|
||||||
flags = regs.pc[1];
|
|
||||||
JS_ASSERT(regs.sp > StackBase(fp));
|
JS_ASSERT(regs.sp > StackBase(fp));
|
||||||
|
flags = regs.pc[1];
|
||||||
if (!js_ValueToIterator(cx, flags, ®s.sp[-1]))
|
if (!js_ValueToIterator(cx, flags, ®s.sp[-1]))
|
||||||
goto error;
|
goto error;
|
||||||
|
LOAD_INTERRUPT_HANDLER(cx);
|
||||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs.sp[-1]));
|
JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs.sp[-1]));
|
||||||
|
PUSH(JSVAL_VOID);
|
||||||
END_CASE(JSOP_ITER)
|
END_CASE(JSOP_ITER)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_FORPROP)
|
BEGIN_CASE(JSOP_NEXTITER)
|
||||||
/*
|
JS_ASSERT(regs.sp - 2 >= StackBase(fp));
|
||||||
* Handle JSOP_FORPROP first, so the cost of the goto do_forinloop
|
JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs.sp[-2]));
|
||||||
* is not paid for the more common cases.
|
if (!js_CallIteratorNext(cx, JSVAL_TO_OBJECT(regs.sp[-2]), ®s.sp[-1]))
|
||||||
*/
|
goto error;
|
||||||
LOAD_ATOM(0);
|
LOAD_INTERRUPT_HANDLER(cx);
|
||||||
id = ATOM_TO_JSID(atom);
|
PUSH(BOOLEAN_TO_JSVAL(regs.sp[-1] != JSVAL_HOLE));
|
||||||
i = -2;
|
TRACE_0(IteratorNextComplete);
|
||||||
goto do_forinloop;
|
END_CASE(JSOP_NEXTITER)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_FORNAME)
|
BEGIN_CASE(JSOP_ENDITER)
|
||||||
LOAD_ATOM(0);
|
/*
|
||||||
id = ATOM_TO_JSID(atom);
|
* Decrease the stack pointer even when !ok -- see comments in the
|
||||||
/* FALL THROUGH */
|
* exception capturing code for details.
|
||||||
|
*/
|
||||||
|
JS_ASSERT(regs.sp - 2 >= StackBase(fp));
|
||||||
|
ok = js_CloseIterator(cx, regs.sp[-2]);
|
||||||
|
regs.sp -= 2;
|
||||||
|
if (!ok)
|
||||||
|
goto error;
|
||||||
|
END_CASE(JSOP_ENDITER)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_FORARG)
|
BEGIN_CASE(JSOP_FORARG)
|
||||||
BEGIN_CASE(JSOP_FORCONST)
|
JS_ASSERT(regs.sp - 2 >= StackBase(fp));
|
||||||
|
slot = GET_ARGNO(regs.pc);
|
||||||
|
JS_ASSERT(slot < fp->fun->nargs);
|
||||||
|
fp->argv[slot] = regs.sp[-1];
|
||||||
|
END_CASE(JSOP_FORARG)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_FORLOCAL)
|
BEGIN_CASE(JSOP_FORLOCAL)
|
||||||
/*
|
JS_ASSERT(regs.sp - 2 >= StackBase(fp));
|
||||||
* These bytecodes don't require any lval computation here,
|
slot = GET_SLOTNO(regs.pc);
|
||||||
* because they address slots on the stack (in fp->args or
|
JS_ASSERT(slot < fp->script->nslots);
|
||||||
* fp->slots).
|
vp = &fp->slots[slot];
|
||||||
*/
|
GC_POKE(cx, *vp);
|
||||||
/* FALL THROUGH */
|
*vp = regs.sp[-1];
|
||||||
|
END_CASE(JSOP_FORLOCAL)
|
||||||
|
|
||||||
|
BEGIN_CASE(JSOP_FORNAME)
|
||||||
|
JS_ASSERT(regs.sp - 2 >= StackBase(fp));
|
||||||
|
LOAD_ATOM(0);
|
||||||
|
id = ATOM_TO_JSID(atom);
|
||||||
|
if (!js_FindProperty(cx, id, &obj, &obj2, &prop))
|
||||||
|
goto error;
|
||||||
|
if (prop)
|
||||||
|
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
||||||
|
ok = OBJ_SET_PROPERTY(cx, obj, id, ®s.sp[-1]);
|
||||||
|
if (!ok)
|
||||||
|
goto error;
|
||||||
|
END_CASE(JSOP_FORNAME)
|
||||||
|
|
||||||
|
BEGIN_CASE(JSOP_FORPROP)
|
||||||
|
JS_ASSERT(regs.sp - 2 >= StackBase(fp));
|
||||||
|
LOAD_ATOM(0);
|
||||||
|
id = ATOM_TO_JSID(atom);
|
||||||
|
FETCH_OBJECT(cx, -1, lval, obj);
|
||||||
|
ok = OBJ_SET_PROPERTY(cx, obj, id, ®s.sp[-2]);
|
||||||
|
if (!ok)
|
||||||
|
goto error;
|
||||||
|
regs.sp--;
|
||||||
|
END_CASE(JSOP_FORPROP)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_FORELEM)
|
BEGIN_CASE(JSOP_FORELEM)
|
||||||
/*
|
/*
|
||||||
* JSOP_FORELEM simply initializes or updates the iteration state
|
* JSOP_FORELEM simply dups the property identifier at top of stack
|
||||||
* and leaves the index expression evaluation and assignment to the
|
* and lets the subsequent JSOP_ENUMELEM opcode sequence handle the
|
||||||
* enumerator until after the next property has been acquired, via
|
* left-hand side expression evaluation and assignment. This opcode
|
||||||
* a JSOP_ENUMELEM bytecode.
|
* exists solely to help the decompiler.
|
||||||
*/
|
*/
|
||||||
i = -1;
|
JS_ASSERT(regs.sp - 2 >= StackBase(fp));
|
||||||
|
rval = FETCH_OPND(-1);
|
||||||
do_forinloop:
|
PUSH(rval);
|
||||||
/*
|
END_CASE(JSOP_FORELEM)
|
||||||
* Reach under the top of stack to find our property iterator, a
|
|
||||||
* JSObject that contains the iteration state.
|
|
||||||
*/
|
|
||||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs.sp[i]));
|
|
||||||
if (!js_CallIteratorNext(cx, JSVAL_TO_OBJECT(regs.sp[i]), &rval))
|
|
||||||
goto error;
|
|
||||||
if (rval == JSVAL_HOLE) {
|
|
||||||
rval = JSVAL_FALSE;
|
|
||||||
#ifdef JS_TRACER
|
|
||||||
if (TRACE_RECORDER(cx)) {
|
|
||||||
js_AbortRecording(cx, "Untraceable for-in loop");
|
|
||||||
ENABLE_TRACER(0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
goto end_forinloop;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (op) {
|
|
||||||
case JSOP_FORARG:
|
|
||||||
slot = GET_ARGNO(regs.pc);
|
|
||||||
JS_ASSERT(slot < fp->fun->nargs);
|
|
||||||
fp->argv[slot] = rval;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JSOP_FORCONST:
|
|
||||||
/* Don't update the const slot. */
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JSOP_FORLOCAL:
|
|
||||||
slot = GET_SLOTNO(regs.pc);
|
|
||||||
JS_ASSERT(slot < fp->script->nslots);
|
|
||||||
vp = &fp->slots[slot];
|
|
||||||
GC_POKE(cx, *vp);
|
|
||||||
*vp = rval;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JSOP_FORELEM:
|
|
||||||
/* FORELEM is not a SET operation, it's more like BINDNAME. */
|
|
||||||
PUSH_OPND(rval);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JSOP_FORPROP:
|
|
||||||
/*
|
|
||||||
* We fetch object here to ensure that the iterator is called
|
|
||||||
* even if lval is null or undefined that throws in
|
|
||||||
* FETCH_OBJECT. See bug 372331.
|
|
||||||
*/
|
|
||||||
FETCH_OBJECT(cx, -1, lval, obj);
|
|
||||||
goto set_for_property;
|
|
||||||
|
|
||||||
default:
|
|
||||||
JS_ASSERT(op == JSOP_FORNAME);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We find property here after the iterator call to ensure
|
|
||||||
* that we take into account side effects of the iterator
|
|
||||||
* call. See bug 372331.
|
|
||||||
*/
|
|
||||||
if (!js_FindProperty(cx, id, &obj, &obj2, &prop))
|
|
||||||
goto error;
|
|
||||||
if (prop)
|
|
||||||
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
|
||||||
|
|
||||||
set_for_property:
|
|
||||||
/* Set the variable obj[id] to refer to rval. */
|
|
||||||
fp->flags |= JSFRAME_ASSIGNING;
|
|
||||||
ok = OBJ_SET_PROPERTY(cx, obj, id, &rval);
|
|
||||||
fp->flags &= ~JSFRAME_ASSIGNING;
|
|
||||||
if (!ok)
|
|
||||||
goto error;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Push true to keep looping through properties. */
|
|
||||||
rval = JSVAL_TRUE;
|
|
||||||
|
|
||||||
end_forinloop:
|
|
||||||
regs.sp += i + 1;
|
|
||||||
PUSH_OPND(rval);
|
|
||||||
len = js_CodeSpec[op].length;
|
|
||||||
DO_NEXT_OP(len);
|
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_DUP)
|
BEGIN_CASE(JSOP_DUP)
|
||||||
JS_ASSERT(regs.sp > StackBase(fp));
|
JS_ASSERT(regs.sp > StackBase(fp));
|
||||||
@ -6712,17 +6668,6 @@ js_Interpret(JSContext *cx)
|
|||||||
}
|
}
|
||||||
END_CASE(JSOP_LEAVEBLOCK)
|
END_CASE(JSOP_LEAVEBLOCK)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_ENDITER)
|
|
||||||
/*
|
|
||||||
* Decrease the stack pointer even when !ok, see comments in the
|
|
||||||
* exception capturing code for details.
|
|
||||||
*/
|
|
||||||
ok = js_CloseIterator(cx, regs.sp[-1]);
|
|
||||||
regs.sp--;
|
|
||||||
if (!ok)
|
|
||||||
goto error;
|
|
||||||
END_CASE(JSOP_ENDITER)
|
|
||||||
|
|
||||||
#if JS_HAS_GENERATORS
|
#if JS_HAS_GENERATORS
|
||||||
BEGIN_CASE(JSOP_GENERATOR)
|
BEGIN_CASE(JSOP_GENERATOR)
|
||||||
ASSERT_NOT_THROWING(cx);
|
ASSERT_NOT_THROWING(cx);
|
||||||
@ -6823,11 +6768,9 @@ js_Interpret(JSContext *cx)
|
|||||||
L_JSOP_DEFXMLNS:
|
L_JSOP_DEFXMLNS:
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
L_JSOP_UNUSED74:
|
|
||||||
L_JSOP_UNUSED76:
|
|
||||||
L_JSOP_UNUSED77:
|
|
||||||
L_JSOP_UNUSED78:
|
L_JSOP_UNUSED78:
|
||||||
L_JSOP_UNUSED79:
|
L_JSOP_UNUSED79:
|
||||||
|
L_JSOP_UNUSED103:
|
||||||
L_JSOP_UNUSED131:
|
L_JSOP_UNUSED131:
|
||||||
L_JSOP_UNUSED201:
|
L_JSOP_UNUSED201:
|
||||||
L_JSOP_UNUSED202:
|
L_JSOP_UNUSED202:
|
||||||
@ -6836,6 +6779,8 @@ js_Interpret(JSContext *cx)
|
|||||||
L_JSOP_UNUSED205:
|
L_JSOP_UNUSED205:
|
||||||
L_JSOP_UNUSED206:
|
L_JSOP_UNUSED206:
|
||||||
L_JSOP_UNUSED207:
|
L_JSOP_UNUSED207:
|
||||||
|
L_JSOP_UNUSED208:
|
||||||
|
L_JSOP_UNUSED209:
|
||||||
L_JSOP_UNUSED219:
|
L_JSOP_UNUSED219:
|
||||||
L_JSOP_UNUSED226:
|
L_JSOP_UNUSED226:
|
||||||
|
|
||||||
@ -6984,12 +6929,14 @@ js_Interpret(JSContext *cx)
|
|||||||
|
|
||||||
case JSTRY_ITER:
|
case JSTRY_ITER:
|
||||||
/*
|
/*
|
||||||
* This is similar to JSOP_ENDITER in the interpreter loop
|
* This is similar to JSOP_ENDITER in the interpreter loop,
|
||||||
* except the code now uses a reserved stack slot to save and
|
* except the code now uses the stack slot normally used by
|
||||||
* restore the exception.
|
* JSOP_NEXTITER, namely regs.sp[-1] before the regs.sp -= 2
|
||||||
|
* adjustment and regs.sp[1] after, to save and restore the
|
||||||
|
* pending exception.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(*regs.pc == JSOP_ENDITER);
|
JS_ASSERT(*regs.pc == JSOP_ENDITER);
|
||||||
PUSH(cx->exception);
|
regs.sp[-1] = cx->exception;
|
||||||
cx->throwing = JS_FALSE;
|
cx->throwing = JS_FALSE;
|
||||||
ok = js_CloseIterator(cx, regs.sp[-2]);
|
ok = js_CloseIterator(cx, regs.sp[-2]);
|
||||||
regs.sp -= 2;
|
regs.sp -= 2;
|
||||||
|
@ -3414,7 +3414,7 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
|||||||
format = cs->format;
|
format = cs->format;
|
||||||
if (JOF_MODE(format) != JOF_NAME)
|
if (JOF_MODE(format) != JOF_NAME)
|
||||||
flags |= JSRESOLVE_QUALIFIED;
|
flags |= JSRESOLVE_QUALIFIED;
|
||||||
if ((format & JOF_ASSIGNING) ||
|
if ((format & (JOF_SET | JOF_FOR)) ||
|
||||||
(cx->fp->flags & JSFRAME_ASSIGNING)) {
|
(cx->fp->flags & JSFRAME_ASSIGNING)) {
|
||||||
flags |= JSRESOLVE_ASSIGNING;
|
flags |= JSRESOLVE_ASSIGNING;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1740,6 +1740,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
|
|
||||||
static const char exception_cookie[] = "/*EXCEPTION*/";
|
static const char exception_cookie[] = "/*EXCEPTION*/";
|
||||||
static const char retsub_pc_cookie[] = "/*RETSUB_PC*/";
|
static const char retsub_pc_cookie[] = "/*RETSUB_PC*/";
|
||||||
|
static const char iter_cookie[] = "/*ITER*/";
|
||||||
static const char forelem_cookie[] = "/*FORELEM*/";
|
static const char forelem_cookie[] = "/*FORELEM*/";
|
||||||
static const char with_cookie[] = "/*WITH*/";
|
static const char with_cookie[] = "/*WITH*/";
|
||||||
static const char dot_format[] = "%s.%s";
|
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 LOCAL_ASSERT(expr) LOCAL_ASSERT_RV(expr, NULL)
|
||||||
#define DECOMPILE_CODE(pc,nb) if (!Decompile(ss, pc, nb, JSOP_NOP)) return 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 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() PopStr(ss, op)
|
||||||
#define POP_STR_PREC(prec) PopStrPrec(ss, prec)
|
#define POP_STR_PREC(prec) PopStrPrec(ss, prec)
|
||||||
|
|
||||||
@ -2502,14 +2504,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
sn = NULL;
|
sn = NULL;
|
||||||
break;
|
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:
|
case JSOP_ENTERWITH:
|
||||||
LOCAL_ASSERT(!js_GetSrcNote(jp->script, pc));
|
LOCAL_ASSERT(!js_GetSrcNote(jp->script, pc));
|
||||||
rval = POP_STR();
|
rval = POP_STR();
|
||||||
@ -2883,7 +2877,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
pos = ss->top;
|
pos = ss->top;
|
||||||
while (pos != 0) {
|
while (pos != 0) {
|
||||||
op = (JSOp) ss->opcodes[--pos];
|
op = (JSOp) ss->opcodes[--pos];
|
||||||
if (op != JSOP_FORLOCAL)
|
if (op == JSOP_ENTERBLOCK)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
JS_ASSERT(op == JSOP_ENTERBLOCK);
|
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
|
* in the single string of accumulated |for| heads and optional
|
||||||
* final |if (condition)|.
|
* final |if (condition)|.
|
||||||
*/
|
*/
|
||||||
forpos = pos + 1;
|
forpos = pos + 2;
|
||||||
LOCAL_ASSERT(forpos < ss->top);
|
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);
|
js_printf(jp, "\t%s %s;\n", js_throw_str, rval);
|
||||||
break;
|
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_GOTO:
|
||||||
case JSOP_GOTOX:
|
case JSOP_GOTOX:
|
||||||
sn = js_GetSrcNote(jp->script, pc);
|
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
|
* The loop back-edge carries +1 stack balance, for the
|
||||||
* flag processed by JSOP_IFNE. We do not decompile the
|
* flag processed by JSOP_IFNE. We do not decompile the
|
||||||
* JSOP_IFNE, and instead pass the left-hand side of 'in'
|
* JSOP_IFNE, and instead push the left-hand side of 'in'
|
||||||
* along the loop edge in this pushed stack slot.
|
* after the loop edge in this stack slot (the JSOP_FOR*
|
||||||
|
* opcodes' decompilers do this pushing).
|
||||||
*/
|
*/
|
||||||
cond = GetJumpOffset(pc, pc);
|
cond = GetJumpOffset(pc, pc);
|
||||||
next = js_GetSrcNoteOffset(sn, 0);
|
next = js_GetSrcNoteOffset(sn, 0);
|
||||||
tail = js_GetSrcNoteOffset(sn, 1);
|
tail = js_GetSrcNoteOffset(sn, 1);
|
||||||
DECOMPILE_CODE(pc + cond, tail - cond);
|
JS_ASSERT(pc[cond] == JSOP_NEXTITER);
|
||||||
DECOMPILE_CODE(pc + oplen, next - oplen);
|
DECOMPILE_CODE(pc + oplen, next - oplen);
|
||||||
|
lval = POP_STR();
|
||||||
if (ss->inArrayInit || ss->inGenExp) {
|
if (ss->inArrayInit || ss->inGenExp) {
|
||||||
lval = POP_STR();
|
(void) PopOff(ss, JSOP_NOP);
|
||||||
rval = POP_STR();
|
rval = TOP_STR();
|
||||||
if (ss->opcodes[ss->top - 1] == JSOP_FORLOCAL) {
|
LOCAL_ASSERT(ss->top >= 2);
|
||||||
ss->sprinter.offset -= PAREN_SLOP;
|
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)",
|
if (Sprint(&ss->sprinter, " %s (%s in %s)",
|
||||||
foreach ? js_for_each_str : js_for_str,
|
foreach ? js_for_each_str : js_for_str,
|
||||||
lval, rval) < 0) {
|
lval, rval) < 0) {
|
||||||
@ -3000,7 +3016,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
*/
|
*/
|
||||||
todo = ss->offsets[ss->top - 1];
|
todo = ss->offsets[ss->top - 1];
|
||||||
} else {
|
} 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)",
|
todo = Sprint(&ss->sprinter, " %s (%s in %s)",
|
||||||
foreach ? js_for_each_str : js_for_str,
|
foreach ? js_for_each_str : js_for_str,
|
||||||
lval, rval);
|
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
|
* As above, rval or an extension of it must remain
|
||||||
* stacked during loop body decompilation.
|
* stacked during loop body decompilation.
|
||||||
*/
|
*/
|
||||||
lval = POP_STR();
|
rval = GetStr(ss, ss->top - 2);
|
||||||
rval = GetStr(ss, ss->top - 1);
|
|
||||||
js_printf(jp, "\t%s (%s in %s) {\n",
|
js_printf(jp, "\t%s (%s in %s) {\n",
|
||||||
foreach ? js_for_each_str : js_for_str,
|
foreach ? js_for_each_str : js_for_str,
|
||||||
lval, rval);
|
lval, rval);
|
||||||
@ -3222,7 +3237,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
i = GET_ARGNO(pc);
|
i = GET_ARGNO(pc);
|
||||||
goto do_forvarslot;
|
goto do_forvarslot;
|
||||||
|
|
||||||
case JSOP_FORCONST:
|
|
||||||
case JSOP_FORLOCAL:
|
case JSOP_FORLOCAL:
|
||||||
sn = js_GetSrcNote(jp->script, pc);
|
sn = js_GetSrcNote(jp->script, pc);
|
||||||
if (!IsVarSlot(jp, pc, &i)) {
|
if (!IsVarSlot(jp, pc, &i)) {
|
||||||
@ -3270,7 +3284,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case JSOP_FORELEM:
|
case JSOP_FORELEM:
|
||||||
LOCAL_ASSERT(pc[1] == JSOP_IFNE || pc[1] == JSOP_IFNEX);
|
|
||||||
todo = SprintCString(&ss->sprinter, forelem_cookie);
|
todo = SprintCString(&ss->sprinter, forelem_cookie);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -4536,12 +4549,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
inXML = JS_FALSE;
|
inXML = JS_FALSE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JSOP_ITER:
|
|
||||||
foreach = (pc[1] & (JSITER_FOREACH | JSITER_KEYVALUE)) ==
|
|
||||||
JSITER_FOREACH;
|
|
||||||
todo = -2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JSOP_TOXML:
|
case JSOP_TOXML:
|
||||||
case JSOP_CALLXMLNAME:
|
case JSOP_CALLXMLNAME:
|
||||||
case JSOP_XMLNAME:
|
case JSOP_XMLNAME:
|
||||||
@ -4639,7 +4646,9 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
#undef inXML
|
#undef inXML
|
||||||
#undef DECOMPILE_CODE
|
#undef DECOMPILE_CODE
|
||||||
#undef NEXT_OP
|
#undef NEXT_OP
|
||||||
|
#undef TOP_STR
|
||||||
#undef POP_STR
|
#undef POP_STR
|
||||||
|
#undef POP_STR_PREC
|
||||||
#undef LOCAL_ASSERT
|
#undef LOCAL_ASSERT
|
||||||
#undef ATOM_IS_IDENTIFIER
|
#undef ATOM_IS_IDENTIFIER
|
||||||
#undef GET_QUOTE_AND_FMT
|
#undef GET_QUOTE_AND_FMT
|
||||||
|
@ -97,7 +97,7 @@ typedef enum JSOp {
|
|||||||
#define JOF_INC (2U<<10) /* increment (++, not --) opcode */
|
#define JOF_INC (2U<<10) /* increment (++, not --) opcode */
|
||||||
#define JOF_INCDEC (3U<<10) /* increment or decrement opcode */
|
#define JOF_INCDEC (3U<<10) /* increment or decrement opcode */
|
||||||
#define JOF_POST (1U<<12) /* postorder increment or decrement */
|
#define JOF_POST (1U<<12) /* postorder increment or decrement */
|
||||||
#define JOF_FOR (1U<<13) /* for-in property op */
|
#define JOF_FOR (1U<<13) /* for-in property op (akin to JOF_SET) */
|
||||||
#define JOF_ASSIGNING JOF_SET /* hint for JSClass.resolve, used for ops
|
#define JOF_ASSIGNING JOF_SET /* hint for JSClass.resolve, used for ops
|
||||||
that do simplex assignment */
|
that do simplex assignment */
|
||||||
#define JOF_DETECTING (1U<<14) /* object detection for JSNewResolveOp */
|
#define JOF_DETECTING (1U<<14) /* object detection for JSNewResolveOp */
|
||||||
@ -118,8 +118,6 @@ typedef enum JSOp {
|
|||||||
#define JOF_TMPSLOT_SHIFT 22
|
#define JOF_TMPSLOT_SHIFT 22
|
||||||
#define JOF_TMPSLOT_MASK (JS_BITMASK(2) << JOF_TMPSLOT_SHIFT)
|
#define JOF_TMPSLOT_MASK (JS_BITMASK(2) << JOF_TMPSLOT_SHIFT)
|
||||||
|
|
||||||
#define JOF_RETVAL (1U<<24) /* op leaves jsval return value on stack */
|
|
||||||
|
|
||||||
/* Shorthands for type from format and type from opcode. */
|
/* Shorthands for type from format and type from opcode. */
|
||||||
#define JOF_TYPE(fmt) ((fmt) & JOF_TYPEMASK)
|
#define JOF_TYPE(fmt) ((fmt) & JOF_TYPEMASK)
|
||||||
#define JOF_OPTYPE(op) JOF_TYPE(js_CodeSpec[op].format)
|
#define JOF_OPTYPE(op) JOF_TYPE(js_CodeSpec[op].format)
|
||||||
|
@ -111,8 +111,8 @@ OPDEF(JSOP_IFNE, 8, "ifne", NULL, 3, 1, 0, 0, JOF_JUMP|J
|
|||||||
OPDEF(JSOP_ARGUMENTS, 9, js_arguments_str, js_arguments_str, 1, 0, 1, 18, JOF_BYTE)
|
OPDEF(JSOP_ARGUMENTS, 9, js_arguments_str, js_arguments_str, 1, 0, 1, 18, JOF_BYTE)
|
||||||
|
|
||||||
/* ECMA-compliant for-in loop with argument or local loop control. */
|
/* ECMA-compliant for-in loop with argument or local loop control. */
|
||||||
OPDEF(JSOP_FORARG, 10, "forarg", NULL, 3, 0, 1, 19, JOF_QARG|JOF_NAME|JOF_FOR)
|
OPDEF(JSOP_FORARG, 10, "forarg", NULL, 3, 2, 2, 19, JOF_QARG|JOF_NAME|JOF_FOR)
|
||||||
OPDEF(JSOP_FORLOCAL, 11, "forlocal", NULL, 3, 0, 1, 19, JOF_LOCAL|JOF_NAME|JOF_FOR)
|
OPDEF(JSOP_FORLOCAL, 11, "forlocal", NULL, 3, 2, 2, 19, JOF_LOCAL|JOF_NAME|JOF_FOR)
|
||||||
|
|
||||||
/* More longstanding bytecodes. */
|
/* More longstanding bytecodes. */
|
||||||
OPDEF(JSOP_DUP, 12, "dup", NULL, 1, 1, 2, 0, JOF_BYTE)
|
OPDEF(JSOP_DUP, 12, "dup", NULL, 1, 1, 2, 0, JOF_BYTE)
|
||||||
@ -163,7 +163,7 @@ OPDEF(JSOP_SETPROP, 54, "setprop", NULL, 3, 2, 1, 3, JOF_ATOM|J
|
|||||||
OPDEF(JSOP_GETELEM, 55, "getelem", NULL, 1, 2, 1, 18, JOF_BYTE |JOF_ELEM|JOF_LEFTASSOC)
|
OPDEF(JSOP_GETELEM, 55, "getelem", NULL, 1, 2, 1, 18, JOF_BYTE |JOF_ELEM|JOF_LEFTASSOC)
|
||||||
OPDEF(JSOP_SETELEM, 56, "setelem", NULL, 1, 3, 1, 3, JOF_BYTE |JOF_ELEM|JOF_SET|JOF_DETECTING)
|
OPDEF(JSOP_SETELEM, 56, "setelem", NULL, 1, 3, 1, 3, JOF_BYTE |JOF_ELEM|JOF_SET|JOF_DETECTING)
|
||||||
OPDEF(JSOP_CALLNAME, 57, "callname", NULL, 3, 0, 2, 19, JOF_ATOM|JOF_NAME|JOF_CALLOP)
|
OPDEF(JSOP_CALLNAME, 57, "callname", NULL, 3, 0, 2, 19, JOF_ATOM|JOF_NAME|JOF_CALLOP)
|
||||||
OPDEF(JSOP_CALL, 58, "call", NULL, 3, -1, 1, 18, JOF_UINT16|JOF_INVOKE|JOF_RETVAL)
|
OPDEF(JSOP_CALL, 58, "call", NULL, 3, -1, 1, 18, JOF_UINT16|JOF_INVOKE)
|
||||||
OPDEF(JSOP_NAME, 59, "name", NULL, 3, 0, 1, 19, JOF_ATOM|JOF_NAME)
|
OPDEF(JSOP_NAME, 59, "name", NULL, 3, 0, 1, 19, JOF_ATOM|JOF_NAME)
|
||||||
OPDEF(JSOP_DOUBLE, 60, "double", NULL, 3, 0, 1, 16, JOF_ATOM)
|
OPDEF(JSOP_DOUBLE, 60, "double", NULL, 3, 0, 1, 16, JOF_ATOM)
|
||||||
OPDEF(JSOP_STRING, 61, "string", NULL, 3, 0, 1, 19, JOF_ATOM)
|
OPDEF(JSOP_STRING, 61, "string", NULL, 3, 0, 1, 19, JOF_ATOM)
|
||||||
@ -184,13 +184,25 @@ OPDEF(JSOP_LOOKUPSWITCH, 71, "lookupswitch", NULL, -1, 1, 0, 0, JOF_LOOKUP
|
|||||||
OPDEF(JSOP_STRICTEQ, 72, "stricteq", "===", 1, 2, 1, 10, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC)
|
OPDEF(JSOP_STRICTEQ, 72, "stricteq", "===", 1, 2, 1, 10, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC)
|
||||||
OPDEF(JSOP_STRICTNE, 73, "strictne", "!==", 1, 2, 1, 10, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC)
|
OPDEF(JSOP_STRICTNE, 73, "strictne", "!==", 1, 2, 1, 10, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC)
|
||||||
|
|
||||||
OPDEF(JSOP_UNUSED74, 74, "unused74", NULL, 1, 0, 0, 0, JOF_BYTE)
|
|
||||||
|
|
||||||
/* Variant of JSOP_NULL for default (global) |this| parameter pushing. */
|
/* Variant of JSOP_NULL for default (global) |this| parameter pushing. */
|
||||||
OPDEF(JSOP_NULLTHIS, 75, js_null_str, js_null_str, 1, 0, 1, 19, JOF_BYTE)
|
OPDEF(JSOP_NULLTHIS, 74, js_null_str, js_null_str, 1, 0, 1, 19, JOF_BYTE)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* JSOP_ITER sets up a for-in or for-each-in loop using the JSITER_* flag bits
|
||||||
|
* in this op's uint8 immediate operand. It replaces the top of stack object
|
||||||
|
* with an iterator for that object, and pushes a slot used by JSOP_NEXTITER.
|
||||||
|
*
|
||||||
|
* JSOP_NEXTITER stores the next iterated value in the top of stack slot which
|
||||||
|
* was allocated by JSOP_ITER and pushes true, or stores JSVAL_HOLE and pushes
|
||||||
|
* false. It is followed immediately by JSOP_IFNE{,X}.
|
||||||
|
*
|
||||||
|
* JSOP_ENDITER cleans up after the loop. It uses the slot above the iterator
|
||||||
|
* for temporary GC rooting.
|
||||||
|
*/
|
||||||
|
OPDEF(JSOP_ITER, 75, "iter", NULL, 2, 1, 2, 0, JOF_UINT8)
|
||||||
|
OPDEF(JSOP_NEXTITER, 76, "nextiter", NULL, 1, 2, 3, 0, JOF_BYTE)
|
||||||
|
OPDEF(JSOP_ENDITER, 77, "enditer", NULL, 1, 2, 0, 0, JOF_BYTE)
|
||||||
|
|
||||||
OPDEF(JSOP_UNUSED76, 76, "unused76", NULL, 1, 0, 0, 0, JOF_BYTE)
|
|
||||||
OPDEF(JSOP_UNUSED77, 77, "unused77", NULL, 1, 0, 0, 0, JOF_BYTE)
|
|
||||||
OPDEF(JSOP_UNUSED78, 78, "unused78", NULL, 1, 0, 0, 0, JOF_BYTE)
|
OPDEF(JSOP_UNUSED78, 78, "unused78", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||||
OPDEF(JSOP_UNUSED79, 79, "unused79", NULL, 1, 0, 0, 0, JOF_BYTE)
|
OPDEF(JSOP_UNUSED79, 79, "unused79", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||||
|
|
||||||
@ -234,16 +246,12 @@ OPDEF(JSOP_DECLOCAL, 100,"declocal", NULL, 3, 0, 1, 15, JOF_LOCAL|
|
|||||||
OPDEF(JSOP_LOCALINC, 101,"localinc", NULL, 3, 0, 1, 15, JOF_LOCAL|JOF_NAME|JOF_INC|JOF_POST)
|
OPDEF(JSOP_LOCALINC, 101,"localinc", NULL, 3, 0, 1, 15, JOF_LOCAL|JOF_NAME|JOF_INC|JOF_POST)
|
||||||
OPDEF(JSOP_LOCALDEC, 102,"localdec", NULL, 3, 0, 1, 15, JOF_LOCAL|JOF_NAME|JOF_DEC|JOF_POST)
|
OPDEF(JSOP_LOCALDEC, 102,"localdec", NULL, 3, 0, 1, 15, JOF_LOCAL|JOF_NAME|JOF_DEC|JOF_POST)
|
||||||
|
|
||||||
/*
|
OPDEF(JSOP_UNUSED103, 103,"unused103", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||||
* Initialize for-in iterator using the JSITER_* flag bits in this op's uint8
|
|
||||||
* immediate operand. See also JSOP_ENDITER.
|
|
||||||
*/
|
|
||||||
OPDEF(JSOP_ITER, 103,"iter", NULL, 2, 1, 1, 0, JOF_UINT8)
|
|
||||||
|
|
||||||
/* ECMA-compliant for/in ops. */
|
/* ECMA-compliant for/in ops. */
|
||||||
OPDEF(JSOP_FORNAME, 104,"forname", NULL, 3, 0, 1, 19, JOF_ATOM|JOF_NAME|JOF_FOR)
|
OPDEF(JSOP_FORNAME, 104,"forname", NULL, 3, 2, 2, 19, JOF_ATOM|JOF_NAME|JOF_FOR)
|
||||||
OPDEF(JSOP_FORPROP, 105,"forprop", NULL, 3, 1, 1, 18, JOF_ATOM|JOF_PROP|JOF_FOR)
|
OPDEF(JSOP_FORPROP, 105,"forprop", NULL, 3, 3, 2, 18, JOF_ATOM|JOF_PROP|JOF_FOR)
|
||||||
OPDEF(JSOP_FORELEM, 106,"forelem", NULL, 1, 1, 3, 18, JOF_BYTE |JOF_ELEM|JOF_FOR)
|
OPDEF(JSOP_FORELEM, 106,"forelem", NULL, 1, 2, 3, 18, JOF_BYTE |JOF_ELEM|JOF_FOR)
|
||||||
OPDEF(JSOP_POPN, 107,"popn", NULL, 3, -1, 0, 0, JOF_UINT16)
|
OPDEF(JSOP_POPN, 107,"popn", NULL, 3, -1, 0, 0, JOF_UINT16)
|
||||||
|
|
||||||
/* ECMA-compliant assignment ops. */
|
/* ECMA-compliant assignment ops. */
|
||||||
@ -474,12 +482,12 @@ OPDEF(JSOP_UNUSED204, 204,"unused204", NULL, 1, 0, 0, 0, JOF_BYTE)
|
|||||||
OPDEF(JSOP_UNUSED205, 205,"unused205", NULL, 1, 0, 0, 0, JOF_BYTE)
|
OPDEF(JSOP_UNUSED205, 205,"unused205", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||||
OPDEF(JSOP_UNUSED206, 206,"unused206", NULL, 1, 0, 0, 0, JOF_BYTE)
|
OPDEF(JSOP_UNUSED206, 206,"unused206", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||||
OPDEF(JSOP_UNUSED207, 207,"unused207", NULL, 1, 0, 0, 0, JOF_BYTE)
|
OPDEF(JSOP_UNUSED207, 207,"unused207", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||||
|
OPDEF(JSOP_UNUSED208, 208,"unused208", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||||
|
OPDEF(JSOP_UNUSED209, 209,"unused209", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Iterator, generator, and array comprehension support.
|
* Generator and array comprehension support.
|
||||||
*/
|
*/
|
||||||
OPDEF(JSOP_FORCONST, 208,"forconst", NULL, 3, 0, 1, 19, JOF_LOCAL|JOF_NAME|JOF_FOR)
|
|
||||||
OPDEF(JSOP_ENDITER, 209,"enditer", NULL, 1, 1, 0, 0, JOF_BYTE|JOF_TMPSLOT)
|
|
||||||
OPDEF(JSOP_GENERATOR, 210,"generator", NULL, 1, 0, 0, 0, JOF_BYTE)
|
OPDEF(JSOP_GENERATOR, 210,"generator", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||||
OPDEF(JSOP_YIELD, 211,"yield", NULL, 1, 1, 1, 1, JOF_BYTE)
|
OPDEF(JSOP_YIELD, 211,"yield", NULL, 1, 1, 1, 1, JOF_BYTE)
|
||||||
OPDEF(JSOP_ARRAYPUSH, 212,"arraypush", NULL, 3, 1, 0, 3, JOF_LOCAL)
|
OPDEF(JSOP_ARRAYPUSH, 212,"arraypush", NULL, 3, 1, 0, 3, JOF_LOCAL)
|
||||||
|
@ -165,7 +165,7 @@ jitstats_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
|||||||
#define JITSTAT(x) case STAT ## x ## ID: result = jitstats.x; break;
|
#define JITSTAT(x) case STAT ## x ## ID: result = jitstats.x; break;
|
||||||
#include "jitstats.tbl"
|
#include "jitstats.tbl"
|
||||||
#undef JITSTAT
|
#undef JITSTAT
|
||||||
default:
|
default:
|
||||||
*vp = JSVAL_VOID;
|
*vp = JSVAL_VOID;
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
@ -1695,13 +1695,13 @@ static bool
|
|||||||
js_IsLoopEdge(jsbytecode* pc, jsbytecode* header)
|
js_IsLoopEdge(jsbytecode* pc, jsbytecode* header)
|
||||||
{
|
{
|
||||||
switch (*pc) {
|
switch (*pc) {
|
||||||
case JSOP_IFEQ:
|
case JSOP_IFEQ:
|
||||||
case JSOP_IFNE:
|
case JSOP_IFNE:
|
||||||
return ((pc + GET_JUMP_OFFSET(pc)) == header);
|
return ((pc + GET_JUMP_OFFSET(pc)) == header);
|
||||||
case JSOP_IFEQX:
|
case JSOP_IFEQX:
|
||||||
case JSOP_IFNEX:
|
case JSOP_IFNEX:
|
||||||
return ((pc + GET_JUMPX_OFFSET(pc)) == header);
|
return ((pc + GET_JUMPX_OFFSET(pc)) == header);
|
||||||
default:
|
default:
|
||||||
JS_ASSERT((*pc == JSOP_AND) || (*pc == JSOP_ANDX) ||
|
JS_ASSERT((*pc == JSOP_AND) || (*pc == JSOP_ANDX) ||
|
||||||
(*pc == JSOP_OR) || (*pc == JSOP_ORX));
|
(*pc == JSOP_OR) || (*pc == JSOP_ORX));
|
||||||
}
|
}
|
||||||
@ -1788,7 +1788,7 @@ TraceRecorder::snapshot(ExitType exitType)
|
|||||||
bool resumeAfter = (pendingTraceableNative &&
|
bool resumeAfter = (pendingTraceableNative &&
|
||||||
JSTN_ERRTYPE(pendingTraceableNative) == FAIL_JSVAL);
|
JSTN_ERRTYPE(pendingTraceableNative) == FAIL_JSVAL);
|
||||||
if (resumeAfter) {
|
if (resumeAfter) {
|
||||||
JS_ASSERT(cs.format & JOF_RETVAL);
|
JS_ASSERT(*pc == JSOP_CALL || *pc == JSOP_NEXTITER);
|
||||||
pc += cs.length;
|
pc += cs.length;
|
||||||
regs->pc = pc;
|
regs->pc = pc;
|
||||||
MUST_FLOW_THROUGH(restore_pc);
|
MUST_FLOW_THROUGH(restore_pc);
|
||||||
@ -1815,10 +1815,11 @@ TraceRecorder::snapshot(ExitType exitType)
|
|||||||
);
|
);
|
||||||
JS_ASSERT(unsigned(m - typemap) == ngslots + stackSlots);
|
JS_ASSERT(unsigned(m - typemap) == ngslots + stackSlots);
|
||||||
|
|
||||||
/* If we are capturing the stack state on a JOF_RETVAL instruction, the value on top of
|
/* If we are capturing the stack state on a specific instruction, the value on or near
|
||||||
the stack is a boxed value. */
|
the top of the stack is a boxed value. Either pc[-cs.length] is JSOP_NEXTITER and we
|
||||||
|
want one below top of stack, or else it's JSOP_CALL and we want top of stack. */
|
||||||
if (resumeAfter) {
|
if (resumeAfter) {
|
||||||
m[-1] = JSVAL_BOXED;
|
m[(pc[-cs.length] == JSOP_NEXTITER) ? -2 : -1] = JSVAL_BOXED;
|
||||||
|
|
||||||
/* Now restore the the original pc (after which early returns are ok). */
|
/* Now restore the the original pc (after which early returns are ok). */
|
||||||
MUST_FLOW_LABEL(restore_pc);
|
MUST_FLOW_LABEL(restore_pc);
|
||||||
@ -1958,7 +1959,8 @@ TraceRecorder::checkType(jsval& v, uint8 t, jsval*& stage_val, LIns*& stage_ins,
|
|||||||
typeChar[t]););
|
typeChar[t]););
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
debug_only_v(printf("checkType(tag=%d, t=%d) stage_count=%d\n", JSVAL_TAG(v), t, stage_count);)
|
debug_only_v(printf("checkType(tag=%d, t=%d) stage_count=%d\n",
|
||||||
|
(int) JSVAL_TAG(v), t, stage_count);)
|
||||||
return JSVAL_TAG(v) == t;
|
return JSVAL_TAG(v) == t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2374,17 +2376,17 @@ TraceRecorder::flipIf(jsbytecode* pc, bool& cond)
|
|||||||
{
|
{
|
||||||
if (js_IsLoopEdge(pc, (jsbytecode*)fragment->root->ip)) {
|
if (js_IsLoopEdge(pc, (jsbytecode*)fragment->root->ip)) {
|
||||||
switch (*pc) {
|
switch (*pc) {
|
||||||
case JSOP_IFEQ:
|
case JSOP_IFEQ:
|
||||||
case JSOP_IFEQX:
|
case JSOP_IFEQX:
|
||||||
if (!cond)
|
if (!cond)
|
||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
case JSOP_IFNE:
|
case JSOP_IFNE:
|
||||||
case JSOP_IFNEX:
|
case JSOP_IFNEX:
|
||||||
if (cond)
|
if (cond)
|
||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
JS_NOT_REACHED("flipIf");
|
JS_NOT_REACHED("flipIf");
|
||||||
}
|
}
|
||||||
/* We are about to walk out of the loop, so terminate it with
|
/* We are about to walk out of the loop, so terminate it with
|
||||||
@ -2956,7 +2958,7 @@ js_RecordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCallCount)
|
|||||||
}
|
}
|
||||||
Fragment* old;
|
Fragment* old;
|
||||||
switch (lr->exitType) {
|
switch (lr->exitType) {
|
||||||
case LOOP_EXIT:
|
case LOOP_EXIT:
|
||||||
/* If the inner tree exited on an unknown loop exit, grow the tree around it. */
|
/* If the inner tree exited on an unknown loop exit, grow the tree around it. */
|
||||||
if (innermostNestedGuard) {
|
if (innermostNestedGuard) {
|
||||||
js_AbortRecording(cx, "Inner tree took different side exit, abort recording");
|
js_AbortRecording(cx, "Inner tree took different side exit, abort recording");
|
||||||
@ -3493,15 +3495,15 @@ monitor_loop:
|
|||||||
of a branch exit), or the tree nested around the tree we exited from (in case of the
|
of a branch exit), or the tree nested around the tree we exited from (in case of the
|
||||||
tree call guard). */
|
tree call guard). */
|
||||||
switch (lr->exitType) {
|
switch (lr->exitType) {
|
||||||
case UNSTABLE_LOOP_EXIT:
|
case UNSTABLE_LOOP_EXIT:
|
||||||
return js_AttemptToStabilizeTree(cx, lr, match, NULL);
|
return js_AttemptToStabilizeTree(cx, lr, match, NULL);
|
||||||
case BRANCH_EXIT:
|
case BRANCH_EXIT:
|
||||||
return js_AttemptToExtendTree(cx, lr, NULL, NULL);
|
return js_AttemptToExtendTree(cx, lr, NULL, NULL);
|
||||||
case LOOP_EXIT:
|
case LOOP_EXIT:
|
||||||
if (innermostNestedGuard)
|
if (innermostNestedGuard)
|
||||||
return js_AttemptToExtendTree(cx, innermostNestedGuard, lr, NULL);
|
return js_AttemptToExtendTree(cx, innermostNestedGuard, lr, NULL);
|
||||||
return false;
|
return false;
|
||||||
default:
|
default:
|
||||||
/* No, this was an unusual exit (i.e. out of memory/GC), so just resume interpretation. */
|
/* No, this was an unusual exit (i.e. out of memory/GC), so just resume interpretation. */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -5951,28 +5953,28 @@ TraceRecorder::record_FastNativeCallComplete()
|
|||||||
function, which might have side effects.
|
function, which might have side effects.
|
||||||
|
|
||||||
Instead, snapshot(), which is invoked from unbox_jsval(), will see that
|
Instead, snapshot(), which is invoked from unbox_jsval(), will see that
|
||||||
we are currently parked on a JOF_RETVAL instruction, and it will advance
|
we are currently parked on a traceable native's JSOP_CALL instruction,
|
||||||
the pc to restore by the length of the current opcode, and indicate in
|
and it will advance the pc to restore by the length of the current
|
||||||
the type map that the element on top of the stack is a boxed value which
|
opcode, and indicate in the type map that the element on top of the
|
||||||
doesn't need to be boxed if the type guard generated by unbox_jsval()
|
stack is a boxed value which doesn't need to be boxed if the type guard
|
||||||
fails. */
|
generated by unbox_jsval() fails. */
|
||||||
JS_ASSERT(js_CodeSpec[*cx->fp->regs->pc].format & JOF_RETVAL);
|
JS_ASSERT(*cx->fp->regs->pc == JSOP_CALL);
|
||||||
|
|
||||||
jsval& v = stackval(-1);
|
jsval& v = stackval(-1);
|
||||||
LIns* v_ins = get(&v);
|
LIns* v_ins = get(&v);
|
||||||
|
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
switch (JSTN_ERRTYPE(pendingTraceableNative)) {
|
switch (JSTN_ERRTYPE(pendingTraceableNative)) {
|
||||||
case FAIL_JSVAL:
|
case FAIL_JSVAL:
|
||||||
ok = unbox_jsval(v, v_ins);
|
ok = unbox_jsval(v, v_ins);
|
||||||
if (ok)
|
if (ok)
|
||||||
set(&v, v_ins);
|
set(&v, v_ins);
|
||||||
break;
|
break;
|
||||||
case FAIL_NEG:
|
case FAIL_NEG:
|
||||||
/* Already added i2f in functionCall. */
|
/* Already added i2f in functionCall. */
|
||||||
JS_ASSERT(JSVAL_IS_NUMBER(v));
|
JS_ASSERT(JSVAL_IS_NUMBER(v));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* Convert the result to double if the builtin returns int32. */
|
/* Convert the result to double if the builtin returns int32. */
|
||||||
if (JSVAL_IS_NUMBER(v) &&
|
if (JSVAL_IS_NUMBER(v) &&
|
||||||
(pendingTraceableNative->builtin->_argtypes & 3) == nanojit::ARGSIZE_LO) {
|
(pendingTraceableNative->builtin->_argtypes & 3) == nanojit::ARGSIZE_LO) {
|
||||||
@ -6486,41 +6488,62 @@ TraceRecorder::record_JSOP_ITER()
|
|||||||
LIns* v_ins = lir->insCall(&js_FastValueToIterator_ci, args);
|
LIns* v_ins = lir->insCall(&js_FastValueToIterator_ci, args);
|
||||||
guard(false, lir->ins_eq0(v_ins), MISMATCH_EXIT);
|
guard(false, lir->ins_eq0(v_ins), MISMATCH_EXIT);
|
||||||
set(&v, v_ins);
|
set(&v, v_ins);
|
||||||
|
|
||||||
|
LIns* void_ins = INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID));
|
||||||
|
stack(0, void_ins);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ABORT_TRACE("for-in on a primitive value");
|
ABORT_TRACE("for-in on a primitive value");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static JSTraceableNative js_FastCallIteratorNext_tn = {
|
||||||
|
NULL, // JSFastNative native;
|
||||||
|
&js_FastCallIteratorNext_ci, // const nanojit::CallInfo *builtin;
|
||||||
|
"C", // const char *prefix;
|
||||||
|
"o", // const char *argtypes;
|
||||||
|
FAIL_JSVAL // uintN flags;
|
||||||
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TraceRecorder::forInLoop(jsval* vp)
|
TraceRecorder::record_JSOP_NEXTITER()
|
||||||
{
|
{
|
||||||
jsval& iterobj_val = stackval(-1);
|
jsval& iterobj_val = stackval(-2);
|
||||||
if (!JSVAL_IS_PRIMITIVE(iterobj_val)) {
|
if (!JSVAL_IS_PRIMITIVE(iterobj_val)) {
|
||||||
LIns* args[] = { get(&iterobj_val), cx_ins };
|
LIns* args[] = { get(&iterobj_val), cx_ins };
|
||||||
LIns* v_ins = lir->insCall(&js_FastCallIteratorNext_ci, args);
|
LIns* v_ins = lir->insCall(&js_FastCallIteratorNext_ci, args);
|
||||||
guard(false, lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_ERROR_COOKIE)), OOM_EXIT);
|
guard(false, lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_ERROR_COOKIE)), OOM_EXIT);
|
||||||
|
|
||||||
LIns* flag_ins = lir->ins_eq0(lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_HOLE)));
|
LIns* flag_ins = lir->ins_eq0(lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_HOLE)));
|
||||||
LIns* iter_ins = get(vp);
|
stack(-1, v_ins);
|
||||||
jsval expected = JSVAL_IS_VOID(*vp) ? JSVAL_STRING : JSVAL_TAG(*vp);
|
|
||||||
if (!box_jsval(expected, iter_ins))
|
|
||||||
return false;
|
|
||||||
iter_ins = lir->ins_choose(flag_ins, v_ins, iter_ins);
|
|
||||||
if (!unbox_jsval(expected, iter_ins))
|
|
||||||
return false;
|
|
||||||
set(vp, iter_ins);
|
|
||||||
stack(0, flag_ins);
|
stack(0, flag_ins);
|
||||||
|
|
||||||
|
pendingTraceableNative = &js_FastCallIteratorNext_tn;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ABORT_TRACE("for-in on a primitive value");
|
ABORT_TRACE("for-in on a primitive value");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TraceRecorder::record_IteratorNextComplete()
|
||||||
|
{
|
||||||
|
JS_ASSERT(pendingTraceableNative);
|
||||||
|
JS_ASSERT(*cx->fp->regs->pc == JSOP_NEXTITER);
|
||||||
|
|
||||||
|
jsval& v = stackval(-2);
|
||||||
|
LIns* v_ins = get(&v);
|
||||||
|
if (unbox_jsval(v, v_ins)) {
|
||||||
|
set(&v, v_ins);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TraceRecorder::record_JSOP_ENDITER()
|
TraceRecorder::record_JSOP_ENDITER()
|
||||||
{
|
{
|
||||||
LIns* args[] = { stack(-1), cx_ins };
|
LIns* args[] = { stack(-2), cx_ins };
|
||||||
LIns* ok_ins = lir->insCall(&js_CloseIterator_ci, args);
|
LIns* ok_ins = lir->insCall(&js_CloseIterator_ci, args);
|
||||||
guard(false, lir->ins_eq0(ok_ins), MISMATCH_EXIT);
|
guard(false, lir->ins_eq0(ok_ins), MISMATCH_EXIT);
|
||||||
return true;
|
return true;
|
||||||
@ -6530,7 +6553,11 @@ bool
|
|||||||
TraceRecorder::record_JSOP_FORNAME()
|
TraceRecorder::record_JSOP_FORNAME()
|
||||||
{
|
{
|
||||||
jsval* vp;
|
jsval* vp;
|
||||||
return name(vp) && forInLoop(vp);
|
if (name(vp)) {
|
||||||
|
set(vp, stack(-1));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -6542,25 +6569,19 @@ TraceRecorder::record_JSOP_FORPROP()
|
|||||||
bool
|
bool
|
||||||
TraceRecorder::record_JSOP_FORELEM()
|
TraceRecorder::record_JSOP_FORELEM()
|
||||||
{
|
{
|
||||||
return false;
|
return record_JSOP_DUP();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TraceRecorder::record_JSOP_FORARG()
|
TraceRecorder::record_JSOP_FORARG()
|
||||||
{
|
{
|
||||||
return forInLoop(&argval(GET_ARGNO(cx->fp->regs->pc)));
|
return record_JSOP_SETARG();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TraceRecorder::record_JSOP_FORLOCAL()
|
TraceRecorder::record_JSOP_FORLOCAL()
|
||||||
{
|
{
|
||||||
return forInLoop(&varval(GET_SLOTNO(cx->fp->regs->pc)));
|
return record_JSOP_SETLOCAL();
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TraceRecorder::record_JSOP_FORCONST()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -6635,7 +6656,8 @@ TraceRecorder::record_JSOP_IN()
|
|||||||
|
|
||||||
// Expect what we see at trace recording time (hit or miss) to be the same
|
// Expect what we see at trace recording time (hit or miss) to be the same
|
||||||
// when executing the trace. Use a builtin helper for named properties, as
|
// when executing the trace. Use a builtin helper for named properties, as
|
||||||
// forInLoop does. First, handle indexes in dense arrays as a special case.
|
// the for-in tracing code does. First, handle indexes in dense arrays as a
|
||||||
|
// special case.
|
||||||
JSObject* obj = JSVAL_TO_OBJECT(rval);
|
JSObject* obj = JSVAL_TO_OBJECT(rval);
|
||||||
LIns* obj_ins = get(&rval);
|
LIns* obj_ins = get(&rval);
|
||||||
|
|
||||||
@ -7635,11 +7657,9 @@ js_DumpPeerStability(Fragmento* frago, const void* ip)
|
|||||||
|
|
||||||
#define UNUSED(n) bool TraceRecorder::record_JSOP_UNUSED##n() { return false; }
|
#define UNUSED(n) bool TraceRecorder::record_JSOP_UNUSED##n() { return false; }
|
||||||
|
|
||||||
UNUSED(74)
|
|
||||||
UNUSED(76)
|
|
||||||
UNUSED(77)
|
|
||||||
UNUSED(78)
|
UNUSED(78)
|
||||||
UNUSED(79)
|
UNUSED(79)
|
||||||
|
UNUSED(103)
|
||||||
UNUSED(131)
|
UNUSED(131)
|
||||||
UNUSED(201)
|
UNUSED(201)
|
||||||
UNUSED(202)
|
UNUSED(202)
|
||||||
@ -7648,5 +7668,7 @@ UNUSED(204)
|
|||||||
UNUSED(205)
|
UNUSED(205)
|
||||||
UNUSED(206)
|
UNUSED(206)
|
||||||
UNUSED(207)
|
UNUSED(207)
|
||||||
|
UNUSED(208)
|
||||||
|
UNUSED(209)
|
||||||
UNUSED(219)
|
UNUSED(219)
|
||||||
UNUSED(226)
|
UNUSED(226)
|
||||||
|
@ -378,6 +378,7 @@ public:
|
|||||||
bool record_SetPropMiss(JSPropCacheEntry* entry);
|
bool record_SetPropMiss(JSPropCacheEntry* entry);
|
||||||
bool record_DefLocalFunSetSlot(uint32 slot, JSObject* obj);
|
bool record_DefLocalFunSetSlot(uint32 slot, JSObject* obj);
|
||||||
bool record_FastNativeCallComplete();
|
bool record_FastNativeCallComplete();
|
||||||
|
bool record_IteratorNextComplete();
|
||||||
|
|
||||||
nanojit::Fragment* getOuterToBlacklist() { return outerToBlacklist; }
|
nanojit::Fragment* getOuterToBlacklist() { return outerToBlacklist; }
|
||||||
void deepAbort() { deepAborted = true; }
|
void deepAbort() { deepAborted = true; }
|
||||||
|
@ -204,7 +204,7 @@ JS_XDRFindClassById(JSXDRState *xdr, uint32 id);
|
|||||||
* before deserialization of bytecode. If the saved version does not match
|
* before deserialization of bytecode. If the saved version does not match
|
||||||
* the current version, abort deserialization and invalidate the file.
|
* the current version, abort deserialization and invalidate the file.
|
||||||
*/
|
*/
|
||||||
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 35)
|
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 36)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Library-private functions.
|
* Library-private functions.
|
||||||
|
Loading…
Reference in New Issue
Block a user