Bug 460501 - Round-trip change due to "&&" constant-folding leaving extra parens. r=brendan.

This commit is contained in:
Jason Orendorff
2008-10-21 13:35:22 -05:00
parent 21577c9a4c
commit e74beaa953
8 changed files with 77 additions and 98 deletions

View File

@@ -965,10 +965,10 @@ PushOff(SprintStack *ss, ptrdiff_t off, JSOp op)
}
static ptrdiff_t
PopOff(SprintStack *ss, JSOp op)
PopOffPrec(SprintStack *ss, uint8 prec)
{
uintN top;
const JSCodeSpec *cs, *topcs;
const JSCodeSpec *topcs;
ptrdiff_t off;
/* ss->top points to the next free slot; be paranoid about underflow. */
@@ -980,8 +980,7 @@ PopOff(SprintStack *ss, JSOp op)
ss->top = --top;
off = GetOff(ss, top);
topcs = &js_CodeSpec[ss->opcodes[top]];
cs = &js_CodeSpec[op];
if (topcs->prec != 0 && topcs->prec < cs->prec) {
if (topcs->prec != 0 && topcs->prec < prec) {
ss->sprinter.offset = ss->offsets[top] = off - 2;
off = Sprint(&ss->sprinter, "(%s)", OFF2STR(&ss->sprinter, off));
} else {
@@ -991,14 +990,26 @@ PopOff(SprintStack *ss, JSOp op)
}
static const char *
PopStr(SprintStack *ss, JSOp op)
PopStrPrec(SprintStack *ss, uint8 prec)
{
ptrdiff_t off;
off = PopOff(ss, op);
off = PopOffPrec(ss, prec);
return OFF2STR(&ss->sprinter, off);
}
static ptrdiff_t
PopOff(SprintStack *ss, JSOp op)
{
return PopOffPrec(ss, js_CodeSpec[op].prec);
}
static const char *
PopStr(SprintStack *ss, JSOp op)
{
return PopStrPrec(ss, js_CodeSpec[op].prec);
}
typedef struct TableEntry {
jsval key;
ptrdiff_t offset;
@@ -1744,10 +1755,17 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
/*
* Local macros
*/
#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 POP_STR() PopStr(ss, op)
#define LOCAL_ASSERT(expr) LOCAL_ASSERT_RV(expr, NULL)
#define POP_STR_PREC(prec) PopStrPrec(ss, prec)
/*
* Pop a condition expression for if/for/while. JSOP_IFEQ's precedence forces
* extra parens around assignment, which avoids a strict-mode warning.
*/
#define POP_COND_STR() PopStr(ss, JSOP_IFEQ)
/*
* Callers know that ATOM_IS_STRING(atom), and we leave it to the optimizer to
@@ -1808,6 +1826,23 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
GET_QUOTE_AND_FMT(qfmt, ufmt, rval); \
JS_END_MACRO
/*
* Per spec, new x(y).z means (new x(y))).z. For example new (x(y).z) must
* decompile with the constructor parenthesized, but new x.z should not. The
* normal rules give x(y).z and x.z identical precedence: both are produced by
* JSOP_GETPROP.
*
* Therefore, we need to know in case JSOP_NEW whether the constructor
* expression contains any unparenthesized function calls. So when building a
* MemberExpression or CallExpression, we set ss->opcodes[n] to JSOP_CALL if
* this is true. x(y).z gets JSOP_CALL, not JSOP_GETPROP.
*/
#define PROPAGATE_CALLNESS() \
JS_BEGIN_MACRO \
if (ss->opcodes[ss->top - 1] == JSOP_CALL) \
saveop = JSOP_CALL; \
JS_END_MACRO
cx = ss->sprinter.context;
JS_CHECK_RECURSION(cx, return NULL);
@@ -1986,8 +2021,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
op = (JSOp) pc[oplen];
LOCAL_ASSERT(op != saveop);
}
rval = POP_STR();
lval = POP_STR();
rval = POP_STR_PREC(cs->prec + (!inXML && !!(cs->format & JOF_LEFTASSOC)));
lval = POP_STR_PREC(cs->prec + (!inXML && !(cs->format & JOF_LEFTASSOC)));
if (op != saveop) {
/* Print only the right operand of the assignment-op. */
todo = SprintCString(&ss->sprinter, rval);
@@ -2035,7 +2070,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
jp->indent += 4;
DECOMPILE_CODE(pc, tail);
jp->indent -= 4;
js_printf(jp, "\t} while (%s);\n", POP_STR());
js_printf(jp, "\t} while (%s);\n", POP_COND_STR());
pc += tail;
len = js_CodeSpec[*pc].length;
todo = -2;
@@ -2071,7 +2106,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
if (cond != tail) {
/* Decompile the loop condition. */
DECOMPILE_CODE(pc + cond, tail - cond);
js_printf(jp, " %s", POP_STR());
js_printf(jp, " %s", POP_COND_STR());
}
/* Need a semicolon whether or not there was a cond. */
@@ -2153,44 +2188,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
}
break;
case JSOP_GROUP:
cs = &js_CodeSpec[lastop];
if ((cs->prec != 0 &&
cs->prec <= js_CodeSpec[NEXT_OP(pc)].prec) ||
pc[JSOP_GROUP_LENGTH] == JSOP_NULL ||
pc[JSOP_GROUP_LENGTH] == JSOP_NULLTHIS ||
pc[JSOP_GROUP_LENGTH] == JSOP_DUP ||
pc[JSOP_GROUP_LENGTH] == JSOP_IFEQ ||
pc[JSOP_GROUP_LENGTH] == JSOP_IFNE) {
/*
* Force parens if this JSOP_GROUP forced re-association
* against precedence, or if this is a call or constructor
* expression, or if it is destructured (JSOP_DUP), or if
* it is an if or loop condition test.
*
* This is necessary to handle the operator new grammar,
* by which new x(y).z means (new x(y))).z. For example
* new (x(y).z) must decompile with the constructor
* parenthesized, but normal precedence has JSOP_GETPROP
* (for the final .z) higher than JSOP_NEW. In general,
* if the call or constructor expression is parenthesized,
* we preserve parens.
*/
op = JSOP_NAME;
rval = POP_STR();
todo = SprintCString(&ss->sprinter, rval);
} else {
/*
* Don't explicitly parenthesize -- just fix the top
* opcode so that the auto-parens magic in PopOff can do
* its thing.
*/
LOCAL_ASSERT(ss->top != 0);
ss->opcodes[ss->top-1] = saveop = lastop;
todo = -2;
}
break;
case JSOP_PUSH:
#if JS_HAS_DESTRUCTURING
sn = js_GetSrcNote(jp->script, pc);
@@ -2816,6 +2813,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
LOCAL_ASSERT(jp->fun);
fun = jp->fun;
if (fun->flags & JSFUN_EXPR_CLOSURE) {
/* Turn on parens around comma-expression here. */
op = JSOP_SETNAME;
rval = POP_STR();
js_printf(jp, (*rval == '{') ? "(%s)%s" : ss_format,
rval,
@@ -2967,8 +2966,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
cond = GetJumpOffset(pc, pc);
tail = js_GetSrcNoteOffset(sn, 0);
DECOMPILE_CODE(pc + cond, tail - cond);
rval = POP_STR();
js_printf(jp, "\twhile (%s) {\n", rval);
js_printf(jp, "\twhile (%s) {\n", POP_COND_STR());
jp->indent += 4;
DECOMPILE_CODE(pc + oplen, cond - oplen);
jp->indent -= 4;
@@ -3023,8 +3021,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
switch (sn ? SN_TYPE(sn) : SRC_NULL) {
case SRC_IF:
case SRC_IF_ELSE:
op = JSOP_NOP; /* turn off parens */
rval = POP_STR();
rval = POP_COND_STR();
if (ss->inArrayInit || ss->inGenExp) {
LOCAL_ASSERT(SN_TYPE(sn) == SRC_IF);
ss->sprinter.offset -= PAREN_SLOP;
@@ -3467,6 +3464,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
/*
* Special case: new (x(y)(z)) must be parenthesized like so.
* Same for new (x(y).z) -- contrast with new x(y).z.
* See PROPAGATE_CALLNESS.
*/
op = (JSOp) ss->opcodes[ss->top-1];
lval = PopStr(ss,
@@ -3535,6 +3533,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_DELPROP:
GET_ATOM_QUOTE_AND_FMT("%s %s[%s]", "%s %s.%s", rval);
op = JSOP_GETPROP;
lval = POP_STR();
todo = Sprint(&ss->sprinter, fmt, js_delete_str, lval, rval);
break;
@@ -3542,7 +3541,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_DELELEM:
op = JSOP_NOP; /* turn off parens */
xval = POP_STR();
op = saveop;
op = JSOP_GETPROP;
lval = POP_STR();
if (*xval == '\0')
goto do_delete_lval;
@@ -3556,6 +3555,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
#if JS_HAS_XML_SUPPORT
case JSOP_DELDESC:
xval = POP_STR();
op = JSOP_GETPROP;
lval = POP_STR();
todo = Sprint(&ss->sprinter, "%s %s..%s",
js_delete_str, lval, xval);
@@ -3700,6 +3700,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
do_getprop:
GET_QUOTE_AND_FMT(index_format, dot_format, rval);
do_getprop_lval:
PROPAGATE_CALLNESS();
lval = POP_STR();
todo = Sprint(&ss->sprinter, fmt, lval, rval);
break;
@@ -3773,6 +3774,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
op = JSOP_NOP; /* turn off parens */
xval = POP_STR();
op = saveop;
PROPAGATE_CALLNESS();
lval = POP_STR();
if (*xval == '\0') {
todo = Sprint(&ss->sprinter, "%s", lval);
@@ -4243,14 +4245,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
break;
}
case JSOP_STRICTEQ:
case JSOP_STRICTNE:
rval = POP_STR();
lval = POP_STR();
todo = Sprint(&ss->sprinter, "%s %c== %s",
lval, (op == JSOP_STRICTEQ) ? '=' : '!', rval);
break;
case JSOP_DEFFUN:
LOAD_FUNCTION(0);
todo = -2;
@@ -4607,12 +4601,14 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_ENDFILTER:
rval = POP_STR();
PROPAGATE_CALLNESS();
lval = POP_STR();
todo = Sprint(&ss->sprinter, "%s.(%s)", lval, rval);
break;
case JSOP_DESCENDANTS:
rval = POP_STR();
PROPAGATE_CALLNESS();
lval = POP_STR();
todo = Sprint(&ss->sprinter, "%s..%s", lval, rval);
break;