Bug 686381 - JSOP_AND/JSOP_OR should always leave the value on the stack. r=dvander

This commit is contained in:
Jan de Mooij 2011-11-09 17:43:46 +01:00
parent 0c9c517ff5
commit ce234d64bb
6 changed files with 33 additions and 41 deletions

View File

@ -6488,21 +6488,22 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
case PNK_OR:
case PNK_AND:
/*
* JSOP_OR converts the operand on the stack to boolean, and if true,
* leaves the original operand value on the stack and jumps; otherwise
* it pops and falls into the next bytecode, which evaluates the right
* operand. The jump goes around the right operand evaluation.
* JSOP_OR converts the operand on the stack to boolean, leaves the original
* value on the stack and jumps if true; otherwise it falls into the next
* bytecode, which pops the left operand and then evaluates the right operand.
* The jump goes around the right operand evaluation.
*
* JSOP_AND converts the operand on the stack to boolean, and if false,
* leaves the original operand value on the stack and jumps; otherwise
* it pops and falls into the right operand's bytecode.
* JSOP_AND converts the operand on the stack to boolean and jumps if false;
* otherwise it falls into the right operand's bytecode.
*/
if (pn->isArity(PN_BINARY)) {
if (!EmitTree(cx, bce, pn->pn_left))
return JS_FALSE;
top = EmitJump(cx, bce, JSOP_BACKPATCH_POP, 0);
top = EmitJump(cx, bce, JSOP_BACKPATCH, 0);
if (top < 0)
return JS_FALSE;
if (Emit1(cx, bce, JSOP_POP) < 0)
return JS_FALSE;
if (!EmitTree(cx, bce, pn->pn_right))
return JS_FALSE;
off = bce->offset();
@ -6517,18 +6518,22 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
pn2 = pn->pn_head;
if (!EmitTree(cx, bce, pn2))
return JS_FALSE;
top = EmitJump(cx, bce, JSOP_BACKPATCH_POP, 0);
top = EmitJump(cx, bce, JSOP_BACKPATCH, 0);
if (top < 0)
return JS_FALSE;
if (Emit1(cx, bce, JSOP_POP) < 0)
return JS_FALSE;
/* Emit nodes between the head and the tail. */
jmp = top;
while ((pn2 = pn2->pn_next)->pn_next) {
if (!EmitTree(cx, bce, pn2))
return JS_FALSE;
off = EmitJump(cx, bce, JSOP_BACKPATCH_POP, 0);
off = EmitJump(cx, bce, JSOP_BACKPATCH, 0);
if (off < 0)
return JS_FALSE;
if (Emit1(cx, bce, JSOP_POP) < 0)
return JS_FALSE;
if (!SetBackPatchDelta(cx, bce, bce->code(jmp), off - jmp))
return JS_FALSE;
jmp = off;

View File

@ -568,18 +568,6 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
unsigned newStackDepth = stackDepth;
switch (op) {
case JSOP_OR:
case JSOP_AND:
case JSOP_ORX:
case JSOP_ANDX:
/*
* OR/AND instructions push the operation result when branching.
* We accounted for this in GetDefCount, so subtract the pushed value
* for the fallthrough case.
*/
stackDepth--;
break;
case JSOP_CASE:
case JSOP_CASEX:
/* Case instructions do not push the lvalue back when branching. */

View File

@ -1332,7 +1332,7 @@ js::FindUpvarFrame(JSContext *cx, uintN targetLevel)
#define POP_COPY_TO(v) v = *--regs.sp
#define POP_RETURN_VALUE() regs.fp()->setReturnValue(*--regs.sp)
#define POP_BOOLEAN(cx, vp, b) \
#define VALUE_TO_BOOLEAN(cx, vp, b) \
JS_BEGIN_MACRO \
vp = &regs.sp[-1]; \
if (vp->isNull()) { \
@ -1342,9 +1342,10 @@ js::FindUpvarFrame(JSContext *cx, uintN targetLevel)
} else { \
b = !!js_ValueToBoolean(*vp); \
} \
regs.sp--; \
JS_END_MACRO
#define POP_BOOLEAN(cx, vp, b) do { VALUE_TO_BOOLEAN(cx, vp, b); regs.sp--; } while(0)
#define VALUE_TO_OBJECT(cx, vp, obj) \
JS_BEGIN_MACRO \
if ((vp)->isObject()) { \
@ -2326,11 +2327,10 @@ END_CASE(JSOP_IFNE)
BEGIN_CASE(JSOP_OR)
{
bool cond;
Value *vp;
POP_BOOLEAN(cx, vp, cond);
Value *_;
VALUE_TO_BOOLEAN(cx, _, cond);
if (cond == true) {
len = GET_JUMP_OFFSET(regs.pc);
PUSH_COPY(*vp);
DO_NEXT_OP(len);
}
}
@ -2339,11 +2339,10 @@ END_CASE(JSOP_OR)
BEGIN_CASE(JSOP_AND)
{
bool cond;
Value *vp;
POP_BOOLEAN(cx, vp, cond);
Value *_;
VALUE_TO_BOOLEAN(cx, _, cond);
if (cond == false) {
len = GET_JUMP_OFFSET(regs.pc);
PUSH_COPY(*vp);
DO_NEXT_OP(len);
}
}
@ -2386,11 +2385,10 @@ END_CASE(JSOP_IFNEX)
BEGIN_CASE(JSOP_ORX)
{
bool cond;
Value *vp;
POP_BOOLEAN(cx, vp, cond);
Value *_;
VALUE_TO_BOOLEAN(cx, _, cond);
if (cond == true) {
len = GET_JUMPX_OFFSET(regs.pc);
PUSH_COPY(*vp);
DO_NEXT_OP(len);
}
}
@ -2399,11 +2397,10 @@ END_CASE(JSOP_ORX)
BEGIN_CASE(JSOP_ANDX)
{
bool cond;
Value *vp;
POP_BOOLEAN(cx, vp, cond);
Value *_;
VALUE_TO_BOOLEAN(cx, _, cond);
if (cond == JS_FALSE) {
len = GET_JUMPX_OFFSET(regs.pc);
PUSH_COPY(*vp);
DO_NEXT_OP(len);
}
}

View File

@ -3475,6 +3475,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
return NULL;
done = pc + GetJumpOffset(pc, pc);
pc += len;
JS_ASSERT(*pc == JSOP_POP);
pc += JSOP_POP_LENGTH;
len = done - pc;
if (!Decompile(ss, pc, len)) {
cx->free_((char *)lval);

View File

@ -187,8 +187,8 @@ OPDEF(JSOP_NULL, 64, js_null_str, js_null_str, 1, 0, 1, 19, JOF_BYTE)
OPDEF(JSOP_THIS, 65, js_this_str, js_this_str, 1, 0, 1, 19, JOF_BYTE)
OPDEF(JSOP_FALSE, 66, js_false_str, js_false_str, 1, 0, 1, 19, JOF_BYTE)
OPDEF(JSOP_TRUE, 67, js_true_str, js_true_str, 1, 0, 1, 19, JOF_BYTE)
OPDEF(JSOP_OR, 68, "or", NULL, 3, 1, 0, 5, JOF_JUMP|JOF_DETECTING|JOF_LEFTASSOC)
OPDEF(JSOP_AND, 69, "and", NULL, 3, 1, 0, 6, JOF_JUMP|JOF_DETECTING|JOF_LEFTASSOC)
OPDEF(JSOP_OR, 68, "or", NULL, 3, 1, 1, 5, JOF_JUMP|JOF_DETECTING|JOF_LEFTASSOC)
OPDEF(JSOP_AND, 69, "and", NULL, 3, 1, 1, 6, JOF_JUMP|JOF_DETECTING|JOF_LEFTASSOC)
/* The switch bytecodes have variable length. */
OPDEF(JSOP_TABLESWITCH, 70, "tableswitch", NULL, -1, 1, 0, 0, JOF_TABLESWITCH|JOF_DETECTING|JOF_PARENHEAD)
@ -384,8 +384,8 @@ OPDEF(JSOP_DEFLOCALFUN, 138,"deflocalfun",NULL, 5, 0, 0, 0, JOF_SLOTOB
OPDEF(JSOP_GOTOX, 139,"gotox", NULL, 5, 0, 0, 0, JOF_JUMPX)
OPDEF(JSOP_IFEQX, 140,"ifeqx", NULL, 5, 1, 0, 4, JOF_JUMPX|JOF_DETECTING)
OPDEF(JSOP_IFNEX, 141,"ifnex", NULL, 5, 1, 0, 0, JOF_JUMPX|JOF_PARENHEAD)
OPDEF(JSOP_ORX, 142,"orx", NULL, 5, 1, 0, 5, JOF_JUMPX|JOF_DETECTING)
OPDEF(JSOP_ANDX, 143,"andx", NULL, 5, 1, 0, 6, JOF_JUMPX|JOF_DETECTING)
OPDEF(JSOP_ORX, 142,"orx", NULL, 5, 1, 1, 5, JOF_JUMPX|JOF_DETECTING)
OPDEF(JSOP_ANDX, 143,"andx", NULL, 5, 1, 1, 6, JOF_JUMPX|JOF_DETECTING)
OPDEF(JSOP_GOSUBX, 144,"gosubx", NULL, 5, 0, 0, 0, JOF_JUMPX)
OPDEF(JSOP_CASEX, 145,"casex", NULL, 5, 2, 1, 0, JOF_JUMPX)
OPDEF(JSOP_DEFAULTX, 146,"defaultx", NULL, 5, 1, 0, 0, JOF_JUMPX)

View File

@ -225,7 +225,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 - 97)
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 98)
/*
* Library-private functions.