mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge.
This commit is contained in:
commit
06ec3d4965
@ -2365,14 +2365,14 @@ EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg,
|
||||
do_indexconst: {
|
||||
JSAtomListElement *ale;
|
||||
jsatomid atomIndex;
|
||||
|
||||
|
||||
ale = js_IndexAtom(cx, pn->pn_atom, &cg->atomList);
|
||||
if (!ale)
|
||||
return JS_FALSE;
|
||||
atomIndex = ALE_INDEX(ale);
|
||||
return EmitSlotIndexOp(cx, op, pn2->pn_slot, atomIndex, cg);
|
||||
}
|
||||
|
||||
|
||||
default:;
|
||||
}
|
||||
}
|
||||
@ -3849,6 +3849,28 @@ EmitFunctionDefNop(JSContext *cx, JSCodeGenerator *cg, uintN index)
|
||||
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
|
||||
js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
{
|
||||
@ -3932,7 +3954,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
cg2->staticDepth = cg->staticDepth + 1;
|
||||
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);
|
||||
if (!js_EmitFunctionScript(cx, cg2, pn->pn_body)) {
|
||||
pn = NULL;
|
||||
@ -4217,7 +4239,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
* destructuring for-in).
|
||||
*/
|
||||
JS_ASSERT(pn->pn_op == JSOP_ITER);
|
||||
if (js_Emit2(cx, cg, JSOP_ITER, (uint8) pn->pn_iflags) < 0)
|
||||
if (js_Emit2(cx, cg, PN_OP(pn), (uint8) pn->pn_iflags) < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
/* Annotate so the decompiler can find the loop-closing jump. */
|
||||
@ -4236,10 +4258,6 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
top = CG_OFFSET(cg);
|
||||
SET_STATEMENT_TOP(&stmtInfo, top);
|
||||
|
||||
#ifdef DEBUG
|
||||
intN loopDepth = cg->stackDepth;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compile a JSOP_FOR* bytecode based on the left hand side.
|
||||
*
|
||||
@ -4273,6 +4291,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
/* FALL THROUGH */
|
||||
|
||||
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
|
||||
* 'for (let x in * o)' -- the decompiler must not hoist the
|
||||
@ -4312,9 +4333,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
if (pn3->pn_slot >= 0) {
|
||||
if (pn3->pn_const) {
|
||||
JS_ASSERT(op == JSOP_FORLOCAL);
|
||||
js_ReportCompileErrorNumber(cx, CG_TS(cg), pn3, JSREPORT_ERROR,
|
||||
JSMSG_BAD_FOR_LEFTSIDE);
|
||||
return JS_FALSE;
|
||||
op = JSOP_FORCONST;
|
||||
}
|
||||
atomIndex = (jsatomid) pn3->pn_slot;
|
||||
EMIT_UINT16_IMM_OP(op, atomIndex);
|
||||
@ -4333,6 +4352,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
if (!CheckSideEffects(cx, cg, pn3->pn_expr, &useful))
|
||||
return JS_FALSE;
|
||||
if (!useful) {
|
||||
if (!EmitForInLoopBody(cx, cg, &stmtInfo, pn->pn_right, noteIndex, jmp))
|
||||
return JS_FALSE;
|
||||
if (!EmitPropOp(cx, pn3, JSOP_FORPROP, cg, JS_FALSE))
|
||||
return JS_FALSE;
|
||||
break;
|
||||
@ -4343,10 +4364,19 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
destructuring_for:
|
||||
#endif
|
||||
default:
|
||||
if (js_Emit1(cx, cg, JSOP_FORELEM) < 0)
|
||||
return JS_FALSE;
|
||||
JS_ASSERT(cg->stackDepth >= 3);
|
||||
|
||||
/*
|
||||
* We separate the first/next bytecode from the enumerator
|
||||
* variable binding to avoid any side-effects in the index
|
||||
* 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 (pn3->pn_type == TOK_RB || pn3->pn_type == TOK_RC) {
|
||||
if (!EmitDestructuringOps(cx, cg, op, pn3))
|
||||
@ -4375,32 +4405,24 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
#endif
|
||||
if (!EmitElemOp(cx, pn3, JSOP_ENUMELEM, cg))
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
/* Pop and test the loop condition generated by JSOP_FOR*. */
|
||||
beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg));
|
||||
if (beq < 0)
|
||||
return JS_FALSE;
|
||||
@ -4537,13 +4559,12 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
|
||||
if (pn2->pn_type == TOK_IN) {
|
||||
/*
|
||||
* JSOP_ENDITER must have a slot to save an exception thrown from
|
||||
* 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().
|
||||
* JSOP_ENDITER needs a slot to save an exception thrown from the
|
||||
* body of for-in loop when closing the iterator object.
|
||||
*/
|
||||
JS_ASSERT(js_CodeSpec[JSOP_ENDITER].nuses == 2);
|
||||
if (!NewTryNote(cx, cg, JSTRY_ITER, cg->stackDepth, top, CG_OFFSET(cg)) ||
|
||||
JS_ASSERT(js_CodeSpec[JSOP_ENDITER].format & JOF_TMPSLOT);
|
||||
if (!NewTryNote(cx, cg, JSTRY_ITER, cg->stackDepth, top,
|
||||
CG_OFFSET(cg)) ||
|
||||
js_Emit1(cx, cg, JSOP_ENDITER) < 0) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
@ -5835,7 +5856,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
argc = pn->pn_count - 1;
|
||||
if (js_Emit3(cx, cg, PN_OP(pn), ARGC_HI(argc), ARGC_LO(argc)) < 0)
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
@ -2002,6 +2002,8 @@ js_TraceOpcode(JSContext *cx, jsint len)
|
||||
prevop = (JSOp) regs->pc[-len];
|
||||
ndefs = js_CodeSpec[prevop].ndefs;
|
||||
if (ndefs != 0) {
|
||||
if (prevop == JSOP_FORELEM && regs->sp[-1] == JSVAL_FALSE)
|
||||
--ndefs;
|
||||
for (n = -ndefs; n < 0; n++) {
|
||||
char *bytes = js_DecompileValueGenerator(cx, n, regs->sp[n],
|
||||
NULL);
|
||||
@ -3190,88 +3192,130 @@ js_Interpret(JSContext *cx)
|
||||
END_CASE(JSOP_IN)
|
||||
|
||||
BEGIN_CASE(JSOP_ITER)
|
||||
JS_ASSERT(regs.sp > StackBase(fp));
|
||||
flags = regs.pc[1];
|
||||
JS_ASSERT(regs.sp > StackBase(fp));
|
||||
if (!js_ValueToIterator(cx, flags, ®s.sp[-1]))
|
||||
goto error;
|
||||
LOAD_INTERRUPT_HANDLER(cx);
|
||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs.sp[-1]));
|
||||
PUSH(JSVAL_VOID);
|
||||
END_CASE(JSOP_ITER)
|
||||
|
||||
BEGIN_CASE(JSOP_NEXTITER)
|
||||
JS_ASSERT(regs.sp - 2 >= StackBase(fp));
|
||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs.sp[-2]));
|
||||
if (!js_CallIteratorNext(cx, JSVAL_TO_OBJECT(regs.sp[-2]), ®s.sp[-1]))
|
||||
goto error;
|
||||
LOAD_INTERRUPT_HANDLER(cx);
|
||||
PUSH(BOOLEAN_TO_JSVAL(regs.sp[-1] != JSVAL_HOLE));
|
||||
TRACE_0(IteratorNextComplete);
|
||||
END_CASE(JSOP_NEXTITER)
|
||||
|
||||
BEGIN_CASE(JSOP_ENDITER)
|
||||
BEGIN_CASE(JSOP_FORPROP)
|
||||
/*
|
||||
* Decrease the stack pointer even when !ok -- see comments in the
|
||||
* exception capturing code for details.
|
||||
* Handle JSOP_FORPROP first, so the cost of the goto do_forinloop
|
||||
* is not paid for the more common cases.
|
||||
*/
|
||||
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)
|
||||
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)
|
||||
JS_ASSERT(regs.sp - 2 >= StackBase(fp));
|
||||
slot = GET_SLOTNO(regs.pc);
|
||||
JS_ASSERT(slot < fp->script->nslots);
|
||||
vp = &fp->slots[slot];
|
||||
GC_POKE(cx, *vp);
|
||||
*vp = regs.sp[-1];
|
||||
END_CASE(JSOP_FORLOCAL)
|
||||
LOAD_ATOM(0);
|
||||
id = ATOM_TO_JSID(atom);
|
||||
i = -2;
|
||||
goto do_forinloop;
|
||||
|
||||
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)
|
||||
/* FALL THROUGH */
|
||||
|
||||
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_FORARG)
|
||||
BEGIN_CASE(JSOP_FORCONST)
|
||||
BEGIN_CASE(JSOP_FORLOCAL)
|
||||
/*
|
||||
* These bytecodes don't require any lval computation here,
|
||||
* because they address slots on the stack (in fp->args or
|
||||
* fp->slots).
|
||||
*/
|
||||
/* FALL THROUGH */
|
||||
|
||||
BEGIN_CASE(JSOP_FORELEM)
|
||||
/*
|
||||
* JSOP_FORELEM simply dups the property identifier at top of stack
|
||||
* and lets the subsequent JSOP_ENUMELEM opcode sequence handle the
|
||||
* left-hand side expression evaluation and assignment. This opcode
|
||||
* exists solely to help the decompiler.
|
||||
* JSOP_FORELEM simply initializes or updates the iteration state
|
||||
* and leaves the index expression evaluation and assignment to the
|
||||
* enumerator until after the next property has been acquired, via
|
||||
* a JSOP_ENUMELEM bytecode.
|
||||
*/
|
||||
JS_ASSERT(regs.sp - 2 >= StackBase(fp));
|
||||
rval = FETCH_OPND(-1);
|
||||
PUSH(rval);
|
||||
END_CASE(JSOP_FORELEM)
|
||||
i = -1;
|
||||
|
||||
do_forinloop:
|
||||
/*
|
||||
* 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)
|
||||
JS_ASSERT(regs.sp > StackBase(fp));
|
||||
@ -6668,6 +6712,17 @@ js_Interpret(JSContext *cx)
|
||||
}
|
||||
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
|
||||
BEGIN_CASE(JSOP_GENERATOR)
|
||||
ASSERT_NOT_THROWING(cx);
|
||||
@ -6768,9 +6823,11 @@ js_Interpret(JSContext *cx)
|
||||
L_JSOP_DEFXMLNS:
|
||||
# endif
|
||||
|
||||
L_JSOP_UNUSED74:
|
||||
L_JSOP_UNUSED76:
|
||||
L_JSOP_UNUSED77:
|
||||
L_JSOP_UNUSED78:
|
||||
L_JSOP_UNUSED79:
|
||||
L_JSOP_UNUSED103:
|
||||
L_JSOP_UNUSED131:
|
||||
L_JSOP_UNUSED201:
|
||||
L_JSOP_UNUSED202:
|
||||
@ -6779,8 +6836,6 @@ js_Interpret(JSContext *cx)
|
||||
L_JSOP_UNUSED205:
|
||||
L_JSOP_UNUSED206:
|
||||
L_JSOP_UNUSED207:
|
||||
L_JSOP_UNUSED208:
|
||||
L_JSOP_UNUSED209:
|
||||
L_JSOP_UNUSED219:
|
||||
L_JSOP_UNUSED226:
|
||||
|
||||
@ -6929,14 +6984,12 @@ js_Interpret(JSContext *cx)
|
||||
|
||||
case JSTRY_ITER:
|
||||
/*
|
||||
* This is similar to JSOP_ENDITER in the interpreter loop,
|
||||
* except the code now uses the stack slot normally used by
|
||||
* JSOP_NEXTITER, namely regs.sp[-1] before the regs.sp -= 2
|
||||
* adjustment and regs.sp[1] after, to save and restore the
|
||||
* pending exception.
|
||||
* This is similar to JSOP_ENDITER in the interpreter loop
|
||||
* except the code now uses a reserved stack slot to save and
|
||||
* restore the exception.
|
||||
*/
|
||||
JS_ASSERT(*regs.pc == JSOP_ENDITER);
|
||||
regs.sp[-1] = cx->exception;
|
||||
PUSH(cx->exception);
|
||||
cx->throwing = JS_FALSE;
|
||||
ok = js_CloseIterator(cx, regs.sp[-2]);
|
||||
regs.sp -= 2;
|
||||
|
@ -3414,7 +3414,7 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
||||
format = cs->format;
|
||||
if (JOF_MODE(format) != JOF_NAME)
|
||||
flags |= JSRESOLVE_QUALIFIED;
|
||||
if ((format & (JOF_SET | JOF_FOR)) ||
|
||||
if ((format & JOF_ASSIGNING) ||
|
||||
(cx->fp->flags & JSFRAME_ASSIGNING)) {
|
||||
flags |= JSRESOLVE_ASSIGNING;
|
||||
} else {
|
||||
|
@ -1740,7 +1740,6 @@ 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";
|
||||
@ -1761,7 +1760,6 @@ 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)
|
||||
|
||||
@ -2504,6 +2502,14 @@ 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();
|
||||
@ -2877,7 +2883,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
pos = ss->top;
|
||||
while (pos != 0) {
|
||||
op = (JSOp) ss->opcodes[--pos];
|
||||
if (op == JSOP_ENTERBLOCK)
|
||||
if (op != JSOP_FORLOCAL)
|
||||
break;
|
||||
}
|
||||
JS_ASSERT(op == JSOP_ENTERBLOCK);
|
||||
@ -2887,7 +2893,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 + 2;
|
||||
forpos = pos + 1;
|
||||
LOCAL_ASSERT(forpos < ss->top);
|
||||
|
||||
/*
|
||||
@ -2959,25 +2965,6 @@ 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);
|
||||
@ -2986,22 +2973,19 @@ 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 push the left-hand side of 'in'
|
||||
* after the loop edge in this stack slot (the JSOP_FOR*
|
||||
* opcodes' decompilers do this pushing).
|
||||
* JSOP_IFNE, and instead pass the left-hand side of 'in'
|
||||
* along the loop edge in this pushed stack slot.
|
||||
*/
|
||||
cond = GetJumpOffset(pc, pc);
|
||||
next = js_GetSrcNoteOffset(sn, 0);
|
||||
tail = js_GetSrcNoteOffset(sn, 1);
|
||||
JS_ASSERT(pc[cond] == JSOP_NEXTITER);
|
||||
DECOMPILE_CODE(pc + cond, tail - cond);
|
||||
DECOMPILE_CODE(pc + oplen, next - oplen);
|
||||
lval = POP_STR();
|
||||
if (ss->inArrayInit || ss->inGenExp) {
|
||||
(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;
|
||||
lval = POP_STR();
|
||||
rval = POP_STR();
|
||||
if (ss->opcodes[ss->top - 1] == JSOP_FORLOCAL) {
|
||||
ss->sprinter.offset -= PAREN_SLOP;
|
||||
if (Sprint(&ss->sprinter, " %s (%s in %s)",
|
||||
foreach ? js_for_each_str : js_for_str,
|
||||
lval, rval) < 0) {
|
||||
@ -3016,7 +3000,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
*/
|
||||
todo = ss->offsets[ss->top - 1];
|
||||
} else {
|
||||
LOCAL_ASSERT(ss->opcodes[ss->top - 2] == JSOP_ENTERBLOCK);
|
||||
LOCAL_ASSERT(ss->opcodes[ss->top - 1] == JSOP_ENTERBLOCK);
|
||||
todo = Sprint(&ss->sprinter, " %s (%s in %s)",
|
||||
foreach ? js_for_each_str : js_for_str,
|
||||
lval, rval);
|
||||
@ -3029,7 +3013,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
* As above, rval or an extension of it must remain
|
||||
* stacked during loop body decompilation.
|
||||
*/
|
||||
rval = GetStr(ss, ss->top - 2);
|
||||
lval = POP_STR();
|
||||
rval = GetStr(ss, ss->top - 1);
|
||||
js_printf(jp, "\t%s (%s in %s) {\n",
|
||||
foreach ? js_for_each_str : js_for_str,
|
||||
lval, rval);
|
||||
@ -3237,6 +3222,7 @@ 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)) {
|
||||
@ -3284,6 +3270,7 @@ 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;
|
||||
|
||||
@ -4549,6 +4536,12 @@ 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:
|
||||
@ -4646,9 +4639,7 @@ 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
|
||||
|
@ -97,7 +97,7 @@ typedef enum JSOp {
|
||||
#define JOF_INC (2U<<10) /* increment (++, not --) opcode */
|
||||
#define JOF_INCDEC (3U<<10) /* increment or decrement opcode */
|
||||
#define JOF_POST (1U<<12) /* postorder increment or decrement */
|
||||
#define JOF_FOR (1U<<13) /* for-in property op (akin to JOF_SET) */
|
||||
#define JOF_FOR (1U<<13) /* for-in property op */
|
||||
#define JOF_ASSIGNING JOF_SET /* hint for JSClass.resolve, used for ops
|
||||
that do simplex assignment */
|
||||
#define JOF_DETECTING (1U<<14) /* object detection for JSNewResolveOp */
|
||||
@ -118,6 +118,8 @@ typedef enum JSOp {
|
||||
#define JOF_TMPSLOT_SHIFT 22
|
||||
#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. */
|
||||
#define JOF_TYPE(fmt) ((fmt) & JOF_TYPEMASK)
|
||||
#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)
|
||||
|
||||
/* ECMA-compliant for-in loop with argument or local loop control. */
|
||||
OPDEF(JSOP_FORARG, 10, "forarg", NULL, 3, 2, 2, 19, JOF_QARG|JOF_NAME|JOF_FOR)
|
||||
OPDEF(JSOP_FORLOCAL, 11, "forlocal", NULL, 3, 2, 2, 19, JOF_LOCAL|JOF_NAME|JOF_FOR)
|
||||
OPDEF(JSOP_FORARG, 10, "forarg", NULL, 3, 0, 1, 19, JOF_QARG|JOF_NAME|JOF_FOR)
|
||||
OPDEF(JSOP_FORLOCAL, 11, "forlocal", NULL, 3, 0, 1, 19, JOF_LOCAL|JOF_NAME|JOF_FOR)
|
||||
|
||||
/* More longstanding bytecodes. */
|
||||
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_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_CALL, 58, "call", NULL, 3, -1, 1, 18, JOF_UINT16|JOF_INVOKE)
|
||||
OPDEF(JSOP_CALL, 58, "call", NULL, 3, -1, 1, 18, JOF_UINT16|JOF_INVOKE|JOF_RETVAL)
|
||||
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_STRING, 61, "string", NULL, 3, 0, 1, 19, JOF_ATOM)
|
||||
@ -184,25 +184,13 @@ 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_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. */
|
||||
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_NULLTHIS, 75, js_null_str, js_null_str, 1, 0, 1, 19, 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_UNUSED79, 79, "unused79", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
|
||||
@ -246,12 +234,16 @@ 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_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. */
|
||||
OPDEF(JSOP_FORNAME, 104,"forname", NULL, 3, 2, 2, 19, JOF_ATOM|JOF_NAME|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, 2, 3, 18, JOF_BYTE |JOF_ELEM|JOF_FOR)
|
||||
OPDEF(JSOP_FORNAME, 104,"forname", NULL, 3, 0, 1, 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_FORELEM, 106,"forelem", NULL, 1, 1, 3, 18, JOF_BYTE |JOF_ELEM|JOF_FOR)
|
||||
OPDEF(JSOP_POPN, 107,"popn", NULL, 3, -1, 0, 0, JOF_UINT16)
|
||||
|
||||
/* ECMA-compliant assignment ops. */
|
||||
@ -482,12 +474,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_UNUSED206, 206,"unused206", 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)
|
||||
|
||||
/*
|
||||
* Generator and array comprehension support.
|
||||
* Iterator, 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_YIELD, 211,"yield", NULL, 1, 1, 1, 1, JOF_BYTE)
|
||||
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;
|
||||
#include "jitstats.tbl"
|
||||
#undef JITSTAT
|
||||
default:
|
||||
default:
|
||||
*vp = JSVAL_VOID;
|
||||
return JS_TRUE;
|
||||
}
|
||||
@ -1695,13 +1695,13 @@ static bool
|
||||
js_IsLoopEdge(jsbytecode* pc, jsbytecode* header)
|
||||
{
|
||||
switch (*pc) {
|
||||
case JSOP_IFEQ:
|
||||
case JSOP_IFNE:
|
||||
case JSOP_IFEQ:
|
||||
case JSOP_IFNE:
|
||||
return ((pc + GET_JUMP_OFFSET(pc)) == header);
|
||||
case JSOP_IFEQX:
|
||||
case JSOP_IFNEX:
|
||||
case JSOP_IFEQX:
|
||||
case JSOP_IFNEX:
|
||||
return ((pc + GET_JUMPX_OFFSET(pc)) == header);
|
||||
default:
|
||||
default:
|
||||
JS_ASSERT((*pc == JSOP_AND) || (*pc == JSOP_ANDX) ||
|
||||
(*pc == JSOP_OR) || (*pc == JSOP_ORX));
|
||||
}
|
||||
@ -1788,7 +1788,7 @@ TraceRecorder::snapshot(ExitType exitType)
|
||||
bool resumeAfter = (pendingTraceableNative &&
|
||||
JSTN_ERRTYPE(pendingTraceableNative) == FAIL_JSVAL);
|
||||
if (resumeAfter) {
|
||||
JS_ASSERT(*pc == JSOP_CALL || *pc == JSOP_NEXTITER);
|
||||
JS_ASSERT(cs.format & JOF_RETVAL);
|
||||
pc += cs.length;
|
||||
regs->pc = pc;
|
||||
MUST_FLOW_THROUGH(restore_pc);
|
||||
@ -1815,11 +1815,10 @@ TraceRecorder::snapshot(ExitType exitType)
|
||||
);
|
||||
JS_ASSERT(unsigned(m - typemap) == ngslots + stackSlots);
|
||||
|
||||
/* If we are capturing the stack state on a specific instruction, the value on or near
|
||||
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 we are capturing the stack state on a JOF_RETVAL instruction, the value on top of
|
||||
the stack is a boxed value. */
|
||||
if (resumeAfter) {
|
||||
m[(pc[-cs.length] == JSOP_NEXTITER) ? -2 : -1] = JSVAL_BOXED;
|
||||
m[-1] = JSVAL_BOXED;
|
||||
|
||||
/* Now restore the the original pc (after which early returns are ok). */
|
||||
MUST_FLOW_LABEL(restore_pc);
|
||||
@ -1959,8 +1958,7 @@ TraceRecorder::checkType(jsval& v, uint8 t, jsval*& stage_val, LIns*& stage_ins,
|
||||
typeChar[t]););
|
||||
}
|
||||
#endif
|
||||
debug_only_v(printf("checkType(tag=%d, t=%d) stage_count=%d\n",
|
||||
(int) JSVAL_TAG(v), t, stage_count);)
|
||||
debug_only_v(printf("checkType(tag=%d, t=%d) stage_count=%d\n", JSVAL_TAG(v), t, stage_count);)
|
||||
return JSVAL_TAG(v) == t;
|
||||
}
|
||||
|
||||
@ -2376,17 +2374,17 @@ TraceRecorder::flipIf(jsbytecode* pc, bool& cond)
|
||||
{
|
||||
if (js_IsLoopEdge(pc, (jsbytecode*)fragment->root->ip)) {
|
||||
switch (*pc) {
|
||||
case JSOP_IFEQ:
|
||||
case JSOP_IFEQX:
|
||||
case JSOP_IFEQ:
|
||||
case JSOP_IFEQX:
|
||||
if (!cond)
|
||||
return;
|
||||
break;
|
||||
case JSOP_IFNE:
|
||||
case JSOP_IFNEX:
|
||||
case JSOP_IFNE:
|
||||
case JSOP_IFNEX:
|
||||
if (cond)
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
default:
|
||||
JS_NOT_REACHED("flipIf");
|
||||
}
|
||||
/* We are about to walk out of the loop, so terminate it with
|
||||
@ -2958,7 +2956,7 @@ js_RecordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCallCount)
|
||||
}
|
||||
Fragment* old;
|
||||
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 (innermostNestedGuard) {
|
||||
js_AbortRecording(cx, "Inner tree took different side exit, abort recording");
|
||||
@ -3495,15 +3493,15 @@ monitor_loop:
|
||||
of a branch exit), or the tree nested around the tree we exited from (in case of the
|
||||
tree call guard). */
|
||||
switch (lr->exitType) {
|
||||
case UNSTABLE_LOOP_EXIT:
|
||||
case UNSTABLE_LOOP_EXIT:
|
||||
return js_AttemptToStabilizeTree(cx, lr, match, NULL);
|
||||
case BRANCH_EXIT:
|
||||
case BRANCH_EXIT:
|
||||
return js_AttemptToExtendTree(cx, lr, NULL, NULL);
|
||||
case LOOP_EXIT:
|
||||
case LOOP_EXIT:
|
||||
if (innermostNestedGuard)
|
||||
return js_AttemptToExtendTree(cx, innermostNestedGuard, lr, NULL);
|
||||
return false;
|
||||
default:
|
||||
default:
|
||||
/* No, this was an unusual exit (i.e. out of memory/GC), so just resume interpretation. */
|
||||
return false;
|
||||
}
|
||||
@ -4271,12 +4269,14 @@ TraceRecorder::binary(LOpcode op)
|
||||
rightNumber = true;
|
||||
}
|
||||
}
|
||||
if (l == JSVAL_VOID) {
|
||||
a = lir->insImmq(0);
|
||||
if (JSVAL_TAG(l) == JSVAL_BOOLEAN) {
|
||||
LIns* args[] = { a, cx_ins };
|
||||
a = lir->insCall(&js_BooleanToNumber_ci, args);
|
||||
leftNumber = true;
|
||||
}
|
||||
if (r == JSVAL_VOID) {
|
||||
b = lir->insImmq(0);
|
||||
if (JSVAL_TAG(r) == JSVAL_BOOLEAN) {
|
||||
LIns* args[] = { b, cx_ins };
|
||||
b = lir->insCall(&js_BooleanToNumber_ci, args);
|
||||
rightNumber = true;
|
||||
}
|
||||
if (leftNumber && rightNumber) {
|
||||
@ -5953,28 +5953,28 @@ TraceRecorder::record_FastNativeCallComplete()
|
||||
function, which might have side effects.
|
||||
|
||||
Instead, snapshot(), which is invoked from unbox_jsval(), will see that
|
||||
we are currently parked on a traceable native's JSOP_CALL instruction,
|
||||
and it will advance the pc to restore by the length of the current
|
||||
opcode, and indicate in the type map that the element on top of the
|
||||
stack is a boxed value which doesn't need to be boxed if the type guard
|
||||
generated by unbox_jsval() fails. */
|
||||
JS_ASSERT(*cx->fp->regs->pc == JSOP_CALL);
|
||||
we are currently parked on a JOF_RETVAL instruction, and it will advance
|
||||
the pc to restore by the length of the current opcode, and indicate in
|
||||
the type map that the element on top of the stack is a boxed value which
|
||||
doesn't need to be boxed if the type guard generated by unbox_jsval()
|
||||
fails. */
|
||||
JS_ASSERT(js_CodeSpec[*cx->fp->regs->pc].format & JOF_RETVAL);
|
||||
|
||||
jsval& v = stackval(-1);
|
||||
LIns* v_ins = get(&v);
|
||||
|
||||
bool ok = true;
|
||||
switch (JSTN_ERRTYPE(pendingTraceableNative)) {
|
||||
case FAIL_JSVAL:
|
||||
case FAIL_JSVAL:
|
||||
ok = unbox_jsval(v, v_ins);
|
||||
if (ok)
|
||||
set(&v, v_ins);
|
||||
break;
|
||||
case FAIL_NEG:
|
||||
case FAIL_NEG:
|
||||
/* Already added i2f in functionCall. */
|
||||
JS_ASSERT(JSVAL_IS_NUMBER(v));
|
||||
break;
|
||||
default:
|
||||
default:
|
||||
/* Convert the result to double if the builtin returns int32. */
|
||||
if (JSVAL_IS_NUMBER(v) &&
|
||||
(pendingTraceableNative->builtin->_argtypes & 3) == nanojit::ARGSIZE_LO) {
|
||||
@ -6488,62 +6488,41 @@ TraceRecorder::record_JSOP_ITER()
|
||||
LIns* v_ins = lir->insCall(&js_FastValueToIterator_ci, args);
|
||||
guard(false, lir->ins_eq0(v_ins), MISMATCH_EXIT);
|
||||
set(&v, v_ins);
|
||||
|
||||
LIns* void_ins = INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID));
|
||||
stack(0, void_ins);
|
||||
return true;
|
||||
}
|
||||
|
||||
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
|
||||
TraceRecorder::record_JSOP_NEXTITER()
|
||||
TraceRecorder::forInLoop(jsval* vp)
|
||||
{
|
||||
jsval& iterobj_val = stackval(-2);
|
||||
jsval& iterobj_val = stackval(-1);
|
||||
if (!JSVAL_IS_PRIMITIVE(iterobj_val)) {
|
||||
LIns* args[] = { get(&iterobj_val), cx_ins };
|
||||
LIns* v_ins = lir->insCall(&js_FastCallIteratorNext_ci, args);
|
||||
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)));
|
||||
stack(-1, v_ins);
|
||||
LIns* iter_ins = get(vp);
|
||||
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);
|
||||
|
||||
pendingTraceableNative = &js_FastCallIteratorNext_tn;
|
||||
return true;
|
||||
}
|
||||
|
||||
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
|
||||
TraceRecorder::record_JSOP_ENDITER()
|
||||
{
|
||||
LIns* args[] = { stack(-2), cx_ins };
|
||||
LIns* args[] = { stack(-1), cx_ins };
|
||||
LIns* ok_ins = lir->insCall(&js_CloseIterator_ci, args);
|
||||
guard(false, lir->ins_eq0(ok_ins), MISMATCH_EXIT);
|
||||
return true;
|
||||
@ -6553,11 +6532,7 @@ bool
|
||||
TraceRecorder::record_JSOP_FORNAME()
|
||||
{
|
||||
jsval* vp;
|
||||
if (name(vp)) {
|
||||
set(vp, stack(-1));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return name(vp) && forInLoop(vp);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -6569,19 +6544,25 @@ TraceRecorder::record_JSOP_FORPROP()
|
||||
bool
|
||||
TraceRecorder::record_JSOP_FORELEM()
|
||||
{
|
||||
return record_JSOP_DUP();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::record_JSOP_FORARG()
|
||||
{
|
||||
return record_JSOP_SETARG();
|
||||
return forInLoop(&argval(GET_ARGNO(cx->fp->regs->pc)));
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::record_JSOP_FORLOCAL()
|
||||
{
|
||||
return record_JSOP_SETLOCAL();
|
||||
return forInLoop(&varval(GET_SLOTNO(cx->fp->regs->pc)));
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::record_JSOP_FORCONST()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -6656,8 +6637,7 @@ TraceRecorder::record_JSOP_IN()
|
||||
|
||||
// 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
|
||||
// the for-in tracing code does. First, handle indexes in dense arrays as a
|
||||
// special case.
|
||||
// forInLoop does. First, handle indexes in dense arrays as a special case.
|
||||
JSObject* obj = JSVAL_TO_OBJECT(rval);
|
||||
LIns* obj_ins = get(&rval);
|
||||
|
||||
@ -7657,9 +7637,11 @@ js_DumpPeerStability(Fragmento* frago, const void* ip)
|
||||
|
||||
#define UNUSED(n) bool TraceRecorder::record_JSOP_UNUSED##n() { return false; }
|
||||
|
||||
UNUSED(74)
|
||||
UNUSED(76)
|
||||
UNUSED(77)
|
||||
UNUSED(78)
|
||||
UNUSED(79)
|
||||
UNUSED(103)
|
||||
UNUSED(131)
|
||||
UNUSED(201)
|
||||
UNUSED(202)
|
||||
@ -7668,7 +7650,5 @@ UNUSED(204)
|
||||
UNUSED(205)
|
||||
UNUSED(206)
|
||||
UNUSED(207)
|
||||
UNUSED(208)
|
||||
UNUSED(209)
|
||||
UNUSED(219)
|
||||
UNUSED(226)
|
||||
|
@ -378,7 +378,6 @@ public:
|
||||
bool record_SetPropMiss(JSPropCacheEntry* entry);
|
||||
bool record_DefLocalFunSetSlot(uint32 slot, JSObject* obj);
|
||||
bool record_FastNativeCallComplete();
|
||||
bool record_IteratorNextComplete();
|
||||
|
||||
nanojit::Fragment* getOuterToBlacklist() { return outerToBlacklist; }
|
||||
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
|
||||
* the current version, abort deserialization and invalidate the file.
|
||||
*/
|
||||
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 36)
|
||||
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 35)
|
||||
|
||||
/*
|
||||
* Library-private functions.
|
||||
|
@ -2216,6 +2216,12 @@ this.__proto__.a = 3; for (var j = 0; j < 4; ++j) { [a]; }
|
||||
testGlobalProtoAccess.expected = "ok";
|
||||
test(testGlobalProtoAccess);
|
||||
|
||||
function testAddUndefined() {
|
||||
for (var j = 0; j < 3; ++j)
|
||||
(0 + void 0) && 0;
|
||||
}
|
||||
test(testAddUndefined);
|
||||
|
||||
/* Keep these at the end so that we can see the summary after the trace-debug spew. */
|
||||
print("\npassed:", passes.length && passes.join(","));
|
||||
print("\nFAILED:", fails.length && fails.join(","));
|
||||
|
Loading…
Reference in New Issue
Block a user