mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-19 01:10:22 +00:00
Fix 260106, r=shaver.
This commit is contained in:
parent
f9da9e5c79
commit
2182ce61be
@ -175,6 +175,9 @@ UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target)
|
||||
case JSOP_EVAL:
|
||||
nuses = 2 + GET_ARGC(pc); /* stack: fun, this, [argc arguments] */
|
||||
break;
|
||||
case JSOP_NEWARRAY:
|
||||
nuses = GET_UINT24(pc);
|
||||
break;
|
||||
default:
|
||||
JS_ASSERT(0);
|
||||
}
|
||||
@ -253,7 +256,13 @@ js_EmitN(JSContext *cx, JSCodeGenerator *cg, JSOp op, size_t extra)
|
||||
*next = (jsbytecode)op;
|
||||
memset(next + 1, 0, BYTECODE_SIZE(extra));
|
||||
CG_NEXT(cg) = next + length;
|
||||
UpdateDepth(cx, cg, offset);
|
||||
|
||||
/*
|
||||
* Don't UpdateDepth if op's use-count comes from the immediate
|
||||
* operand yet to be stored in the extra bytes after op.
|
||||
*/
|
||||
if (js_CodeSpec[op].nuses >= 0)
|
||||
UpdateDepth(cx, cg, offset);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
@ -6049,14 +6058,32 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
#endif
|
||||
/*
|
||||
* Emit code for [a, b, c] of the form:
|
||||
*
|
||||
* t = new Array; t[0] = a; t[1] = b; t[2] = c; t;
|
||||
* but use a stack slot for t and avoid dup'ing and popping it via
|
||||
*
|
||||
* but use a stack slot for t and avoid dup'ing and popping it using
|
||||
* the JSOP_NEWINIT and JSOP_INITELEM bytecodes.
|
||||
*
|
||||
* If no sharp variable is defined and the initialiser is not for an
|
||||
* array comprehension, use JSOP_NEWARRAY.
|
||||
*/
|
||||
if (js_Emit2(cx, cg, JSOP_NEWINIT, (jsbytecode) JSProto_Array) < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
pn2 = pn->pn_head;
|
||||
op = JSOP_NEWARRAY;
|
||||
|
||||
#if JS_HAS_SHARP_VARS
|
||||
if (pn2 && pn2->pn_type == TOK_DEFSHARP)
|
||||
op = JSOP_NEWINIT;
|
||||
#endif
|
||||
#if JS_HAS_GENERATORS
|
||||
if (pn->pn_type == TOK_ARRAYCOMP)
|
||||
op = JSOP_NEWINIT;
|
||||
#endif
|
||||
|
||||
if (op == JSOP_NEWINIT &&
|
||||
js_Emit2(cx, cg, op, (jsbytecode) JSProto_Array) < 0) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
#if JS_HAS_SHARP_VARS
|
||||
if (pn2 && pn2->pn_type == TOK_DEFSHARP) {
|
||||
EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid)pn2->pn_num);
|
||||
@ -6088,19 +6115,18 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
#endif /* JS_HAS_GENERATORS */
|
||||
|
||||
for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) {
|
||||
if (!EmitNumberOp(cx, atomIndex, cg))
|
||||
if (op == JSOP_NEWINIT && !EmitNumberOp(cx, atomIndex, cg))
|
||||
return JS_FALSE;
|
||||
|
||||
/* FIXME 260106: holes in a sparse initializer are void-filled. */
|
||||
if (pn2->pn_type == TOK_COMMA) {
|
||||
if (js_Emit1(cx, cg, JSOP_PUSH) < 0)
|
||||
if (js_Emit1(cx, cg, JSOP_HOLE) < 0)
|
||||
return JS_FALSE;
|
||||
} else {
|
||||
if (!js_EmitTree(cx, cg, pn2))
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
if (js_Emit1(cx, cg, JSOP_INITELEM) < 0)
|
||||
if (op == JSOP_NEWINIT && js_Emit1(cx, cg, JSOP_INITELEM) < 0)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
@ -6110,9 +6136,19 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* Emit an op for sharp array cleanup and decompilation. */
|
||||
if (js_Emit1(cx, cg, JSOP_ENDINIT) < 0)
|
||||
return JS_FALSE;
|
||||
if (op == JSOP_NEWARRAY) {
|
||||
JS_ASSERT(atomIndex == pn->pn_count);
|
||||
off = js_EmitN(cx, cg, op, 3);
|
||||
if (off < 0)
|
||||
return JS_FALSE;
|
||||
pc = CG_CODE(cg, off);
|
||||
SET_UINT24(pc, atomIndex);
|
||||
UpdateDepth(cx, cg, off);
|
||||
} else {
|
||||
/* Emit an op for sharp array cleanup and decompilation. */
|
||||
if (js_Emit1(cx, cg, JSOP_ENDINIT) < 0)
|
||||
return JS_FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case TOK_RC:
|
||||
@ -6125,9 +6161,11 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
#endif
|
||||
/*
|
||||
* Emit code for {p:a, '%q':b, 2:c} of the form:
|
||||
*
|
||||
* t = new Object; t.p = a; t['%q'] = b; t[2] = c; t;
|
||||
*
|
||||
* but use a stack slot for t and avoid dup'ing and popping it via
|
||||
* the JSOP_NEWINIT and JSOP_INITELEM bytecodes.
|
||||
* the JSOP_NEWINIT and JSOP_INITELEM/JSOP_INITPROP bytecodes.
|
||||
*/
|
||||
if (js_Emit2(cx, cg, JSOP_NEWINIT, (jsbytecode) JSProto_Object) < 0)
|
||||
return JS_FALSE;
|
||||
|
@ -5936,6 +5936,20 @@ interrupt:
|
||||
DO_NEXT_OP(len);
|
||||
#endif /* JS_HAS_GETTER_SETTER */
|
||||
|
||||
BEGIN_CASE(JSOP_HOLE)
|
||||
PUSH_OPND(JSVAL_HOLE);
|
||||
END_CASE(JSOP_HOLE)
|
||||
|
||||
BEGIN_CASE(JSOP_NEWARRAY)
|
||||
len = GET_UINT24(regs.pc);
|
||||
JS_ASSERT(len <= regs.sp - fp->spbase);
|
||||
obj = js_NewArrayObject(cx, len, regs.sp - len);
|
||||
if (!obj)
|
||||
goto error;
|
||||
regs.sp -= len - 1;
|
||||
STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
|
||||
END_CASE(JSOP_NEWARRAY)
|
||||
|
||||
BEGIN_CASE(JSOP_NEWINIT)
|
||||
i = GET_INT8(regs.pc);
|
||||
JS_ASSERT(i == JSProto_Array || i == JSProto_Object);
|
||||
@ -6096,20 +6110,42 @@ interrupt:
|
||||
/* Pop the element's value into rval. */
|
||||
JS_ASSERT(regs.sp - fp->spbase >= 3);
|
||||
rval = FETCH_OPND(-1);
|
||||
FETCH_ELEMENT_ID(obj, -2, id);
|
||||
|
||||
/* Find the object being initialized at top of stack. */
|
||||
lval = FETCH_OPND(-3);
|
||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(lval));
|
||||
obj = JSVAL_TO_OBJECT(lval);
|
||||
|
||||
/* Set the property named by obj[id] to rval. */
|
||||
/* Fetch id now that we have obj. */
|
||||
FETCH_ELEMENT_ID(obj, -2, id);
|
||||
|
||||
/*
|
||||
* Check for property redeclaration strict warning (we may be in
|
||||
* an object initialiser, not an array initialiser).
|
||||
*/
|
||||
if (!js_CheckRedeclaration(cx, obj, id, JSPROP_INITIALIZER, NULL,
|
||||
NULL)) {
|
||||
goto error;
|
||||
}
|
||||
if (!OBJ_SET_PROPERTY(cx, obj, id, &rval))
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* If rval is a hole, do not call OBJ_SET_PROPERTY. In this case,
|
||||
* obj must be an array, so if the current op is the last element
|
||||
* initialiser, set the array length to one greater than id.
|
||||
*/
|
||||
if (rval == JSVAL_HOLE) {
|
||||
JS_ASSERT(OBJ_IS_ARRAY(cx, obj));
|
||||
JS_ASSERT(JSID_IS_INT(id));
|
||||
JS_ASSERT((jsuint) JSID_TO_INT(id) < ARRAY_INIT_LIMIT);
|
||||
if ((JSOp) regs.pc[JSOP_INITELEM_LENGTH] == JSOP_ENDINIT &&
|
||||
!js_SetLengthProperty(cx, obj,
|
||||
(jsuint) (JSID_TO_INT(id) + 1))) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
if (!OBJ_SET_PROPERTY(cx, obj, id, &rval))
|
||||
goto error;
|
||||
}
|
||||
regs.sp -= 2;
|
||||
END_CASE(JSOP_INITELEM);
|
||||
|
||||
@ -6708,8 +6744,6 @@ interrupt:
|
||||
L_JSOP_DEFXMLNS:
|
||||
# endif
|
||||
|
||||
L_JSOP_UNUSED117:
|
||||
|
||||
#else /* !JS_THREADED_INTERP */
|
||||
default:
|
||||
#endif
|
||||
|
@ -364,7 +364,7 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
break;
|
||||
|
||||
case JOF_UINT24:
|
||||
JS_ASSERT(op == JSOP_UINT24);
|
||||
JS_ASSERT(op == JSOP_UINT24 || op == JSOP_NEWARRAY);
|
||||
i = (jsint)GET_UINT24(pc);
|
||||
goto print_int;
|
||||
|
||||
@ -851,7 +851,11 @@ GetStr(SprintStack *ss, uintN i)
|
||||
return OFF2STR(&ss->sprinter, off);
|
||||
}
|
||||
|
||||
/* Gap between stacked strings to allow for insertion of parens and commas. */
|
||||
/*
|
||||
* Gap between stacked strings to allow for insertion of parens and commas
|
||||
* when auto-parenthesizing expressions and decompiling array initialisers
|
||||
* (see the JSOP_NEWARRAY case in Decompile).
|
||||
*/
|
||||
#define PAREN_SLOP (2 + 1)
|
||||
|
||||
/*
|
||||
@ -4188,6 +4192,59 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
todo = -2;
|
||||
break;
|
||||
|
||||
case JSOP_HOLE:
|
||||
todo = SprintPut(&ss->sprinter, "", 0);
|
||||
break;
|
||||
|
||||
case JSOP_NEWARRAY:
|
||||
{
|
||||
ptrdiff_t off;
|
||||
char *base, *from, *to;
|
||||
|
||||
/*
|
||||
* All operands are stacked and ready for in-place formatting.
|
||||
* We know that PAREN_SLOP is 3 here, and take advantage of it
|
||||
* to avoid strdup'ing.
|
||||
*/
|
||||
argc = GET_UINT24(pc);
|
||||
LOCAL_ASSERT(ss->top >= (uintN) argc);
|
||||
sn = js_GetSrcNote(jp->script, pc);
|
||||
if (argc == 0) {
|
||||
todo = Sprint(&ss->sprinter, "[%s]",
|
||||
(sn && SN_TYPE(sn) == SRC_CONTINUE)
|
||||
? ", "
|
||||
: "");
|
||||
} else {
|
||||
ss->top -= argc;
|
||||
off = GetOff(ss, ss->top);
|
||||
LOCAL_ASSERT(off >= PAREN_SLOP);
|
||||
base = OFF2STR(&ss->sprinter, off);
|
||||
to = base + 1;
|
||||
i = 0;
|
||||
for (;;) {
|
||||
/* Move to the next string that had been stacked. */
|
||||
from = OFF2STR(&ss->sprinter, off);
|
||||
todo = strlen(from);
|
||||
memmove(to, from, todo);
|
||||
to += todo;
|
||||
if (++i == argc &&
|
||||
!(sn && SN_TYPE(sn) == SRC_CONTINUE)) {
|
||||
break;
|
||||
}
|
||||
*to++ = ',';
|
||||
*to++ = ' ';
|
||||
off = GetOff(ss, ss->top + i);
|
||||
}
|
||||
LOCAL_ASSERT(to - base < ss->sprinter.offset - PAREN_SLOP);
|
||||
*base = '[';
|
||||
*to++ = ']';
|
||||
*to = '\0';
|
||||
ss->sprinter.offset = STR2OFF(&ss->sprinter, to);
|
||||
todo = STR2OFF(&ss->sprinter, base);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case JSOP_NEWINIT:
|
||||
{
|
||||
i = GET_INT8(pc);
|
||||
@ -5069,6 +5126,14 @@ ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (op == JSOP_NEWARRAY) {
|
||||
pcdepth -= GET_UINT24(pc) - 1;
|
||||
LOCAL_ASSERT(pcdepth > 0);
|
||||
if (pcstack)
|
||||
pcstack[pcdepth - 1] = pc;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* A (C ? T : E) expression requires skipping either T (if begin is in
|
||||
* E) or both T and E (if begin is after the whole expression) before
|
||||
|
@ -266,7 +266,7 @@ OPDEF(JSOP_RETSUB, 115,"retsub", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
OPDEF(JSOP_EXCEPTION, 116,"exception", NULL, 1, 0, 1, 0, JOF_BYTE)
|
||||
|
||||
/* Embedded lineno to speedup pc->line mapping. */
|
||||
OPDEF(JSOP_LINENO, 117,"lineno", NULL, 3, 0, 0, 0, JOF_UINT16)
|
||||
OPDEF(JSOP_LINENO, 117,"lineno", NULL, 3, 0, 0, 0, JOF_UINT16)
|
||||
|
||||
/*
|
||||
* ECMA-compliant switch statement ops.
|
||||
@ -521,3 +521,11 @@ OPDEF(JSOP_INT32, 228, "int32", NULL, 5, 0, 1, 16, JOF_INT32)
|
||||
* Get the value of the 'length' property from a stacked object.
|
||||
*/
|
||||
OPDEF(JSOP_LENGTH, 229, "length", NULL, 1, 1, 1, 18, JOF_BYTE|JOF_PROP)
|
||||
|
||||
/*
|
||||
* JSOP_NEWARRAY optimizes array literal evaluation using the interpreter stack.
|
||||
* JSOP_HOLE pushes a JSVAL_HOLE (used with JSOP_NEWINIT and JSOP_NEWARRAY).
|
||||
*/
|
||||
OPDEF(JSOP_NEWARRAY, 230,"newarray", NULL, 4, -1, 1, 19, JOF_UINT24)
|
||||
OPDEF(JSOP_HOLE, 231,"hole", NULL, 1, 0, 1, 0, JOF_BYTE)
|
||||
|
||||
|
@ -202,7 +202,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 - 24)
|
||||
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 25)
|
||||
|
||||
/*
|
||||
* Library-private functions.
|
||||
|
Loading…
x
Reference in New Issue
Block a user