Redo merge changeset d3e9df9be570. The first time, it deleted a file it shouldn't have.

This commit is contained in:
Jason Orendorff 2008-06-06 17:50:34 -05:00
Родитель 9a029e57bc 7d3ff26c38
Коммит 317d27f968
7 изменённых файлов: 203 добавлений и 33 удалений

Просмотреть файл

@ -1461,7 +1461,8 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint end,
}
static JSBool
InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, jsval *vector)
InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, jsval *vector,
JSBool holey = JS_FALSE)
{
JS_ASSERT(OBJ_IS_ARRAY(cx, obj));
@ -1470,8 +1471,18 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, jsval *vector)
if (vector) {
if (!EnsureLength(cx, obj, length))
return JS_FALSE;
jsuint count = length;
if (!holey) {
memcpy(obj->dslots, vector, length * sizeof (jsval));
obj->fslots[JSSLOT_ARRAY_COUNT] = length;
} else {
for (jsuint i = 0; i < length; i++) {
if (vector[i] == JSVAL_HOLE)
--count;
obj->dslots[i] = vector[i];
}
}
obj->fslots[JSSLOT_ARRAY_COUNT] = count;
} else {
obj->fslots[JSSLOT_ARRAY_COUNT] = 0;
}
@ -2335,7 +2346,7 @@ static JSBool
array_concat(JSContext *cx, uintN argc, jsval *vp)
{
jsval *argv, v;
JSObject *nobj, *aobj;
JSObject *aobj, *nobj;
jsuint length, alength, slot;
uintN i;
JSBool hole, ok;
@ -2348,10 +2359,21 @@ array_concat(JSContext *cx, uintN argc, jsval *vp)
/* Create a new Array object and root it using *vp. */
aobj = JS_THIS_OBJECT(cx, vp);
if (OBJ_IS_DENSE_ARRAY(cx, aobj)) {
nobj = js_NewArrayObject(cx, ARRAY_DENSE_LENGTH(aobj), aobj->dslots);
/*
* Clone aobj but pass the minimum of its length and capacity (aka
* "dense length"), to handle a = [1,2,3]; a.length = 10000 "dense"
* cases efficiently. In such a case we'll pass 8 (not 3) due to the
* ARRAY_GROWBY over-allocation policy, which will cause nobj to be
* over-allocated to 16. But in the normal case where length is <=
* capacity, nobj and aobj will have the same dense length.
*/
length = aobj->fslots[JSSLOT_ARRAY_LENGTH];
jsuint capacity = ARRAY_DENSE_LENGTH(aobj);
nobj = js_NewArrayObject(cx, JS_MIN(length, capacity), aobj->dslots,
aobj->fslots[JSSLOT_ARRAY_COUNT] !=
(jsval) length);
if (!nobj)
return JS_FALSE;
length = aobj->fslots[JSSLOT_ARRAY_LENGTH];
nobj->fslots[JSSLOT_ARRAY_LENGTH] = length;
*vp = OBJECT_TO_JSVAL(nobj);
if (argc == 0)
@ -2479,7 +2501,9 @@ array_slice(JSContext *cx, uintN argc, jsval *vp)
begin = end;
if (OBJ_IS_DENSE_ARRAY(cx, obj) && end <= ARRAY_DENSE_LENGTH(obj)) {
nobj = js_NewArrayObject(cx, end - begin, obj->dslots + begin);
nobj = js_NewArrayObject(cx, end - begin, obj->dslots + begin,
obj->fslots[JSSLOT_ARRAY_COUNT] !=
obj->fslots[JSSLOT_ARRAY_LENGTH]);
if (!nobj)
return JS_FALSE;
*vp = OBJECT_TO_JSVAL(nobj);
@ -2924,7 +2948,7 @@ js_InitArrayClass(JSContext *cx, JSObject *obj)
}
JSObject *
js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector)
js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector, JSBool holey)
{
JSTempValueRooter tvr;
JSObject *obj;
@ -2934,7 +2958,7 @@ js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector)
return NULL;
JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr);
if (!InitArrayObject(cx, obj, length, vector))
if (!InitArrayObject(cx, obj, length, vector, holey))
obj = NULL;
JS_POP_TEMP_ROOT(cx, &tvr);

Просмотреть файл

@ -64,7 +64,8 @@ extern JSObject *
js_InitArrayClass(JSContext *cx, JSObject *obj);
extern JSObject *
js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector);
js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector,
JSBool holey = JS_FALSE);
/* Create an array object that starts out already made slow/sparse. */
extern JSObject *

Просмотреть файл

@ -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,6 +256,12 @@ 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;
/*
* 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;
}
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, JS_TRUE);
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 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

Просмотреть файл

@ -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.