Mozilla Home
Privacy
Cookies
Legal
Bugzilla
Browse
Advanced Search
New Bug
Reports
Documentation
Log In
Log In with GitHub
or
Remember me
Browse
Advanced Search
New Bug
Reports
Documentation
Attachment 630031 Details for
Bug 574130
[patch]
array implementation
spread-array.patch (text/plain), 24.35 KB, created by
:Benjamin Peterson
(
hide
)
Description:
array implementation
Filename:
MIME Type:
Creator:
:Benjamin Peterson
Size:
24.35 KB
patch
obsolete
># HG changeset patch ># Parent f918d74f736c84577572626b131b749ca3e1b2a4 ># User Benjamin Peterson <benjamin@python.org> >Bug 574130: JavaScript spread array initializers > >diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp >--- a/js/src/frontend/BytecodeEmitter.cpp >+++ b/js/src/frontend/BytecodeEmitter.cpp >@@ -3681,16 +3681,18 @@ ParseNode::getConstantValue(JSContext *c > vp->setBoolean(true); > return true; > case PNK_FALSE: > vp->setBoolean(false); > return true; > case PNK_NULL: > vp->setNull(); > return true; >+ case PNK_SPREAD: >+ return false; > case PNK_RB: { > JS_ASSERT(isOp(JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST)); > > RootedObject obj(cx, NewDenseAllocatedArray(cx, pn_count)); > if (!obj) > return false; > > unsigned idx = 0; >@@ -5764,39 +5766,65 @@ EmitArray(JSContext *cx, BytecodeEmitter > /* Emit the usual op needed for decompilation. */ > return Emit1(cx, bce, JSOP_ENDINIT) >= 0; > } > #endif /* JS_HAS_GENERATORS */ > > if (!(pn->pn_xflags & PNX_NONCONST) && pn->pn_head && bce->checkSingletonContext()) > return EmitSingletonInitialiser(cx, bce, pn); > >+ int32_t nspread = 0; >+ for (ParseNode *elt = pn->pn_head; elt; elt = elt->pn_next) { >+ if (elt->isKind(PNK_SPREAD)) >+ nspread++; >+ } >+ > ptrdiff_t off = EmitN(cx, bce, JSOP_NEWARRAY, 3); > if (off < 0) > return false; > CheckTypeSet(cx, bce, JSOP_NEWARRAY); > jsbytecode *pc = bce->code(off); >- SET_UINT24(pc, pn->pn_count); >+ >+ // For arrays with spread, this is a very pessimistic allocation, the >+ // minimum possible final size. >+ SET_UINT24(pc, pn->pn_count - nspread); > > ParseNode *pn2 = pn->pn_head; > jsatomid atomIndex; >+ if (nspread && !EmitNumberOp(cx, 0, bce)) >+ return false; > for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) { >- if (!EmitNumberOp(cx, atomIndex, bce)) >+ if (!nspread && !EmitNumberOp(cx, atomIndex, bce)) > return false; > if (pn2->isKind(PNK_COMMA) && pn2->isArity(PN_NULLARY)) { > if (Emit1(cx, bce, JSOP_HOLE) < 0) > return false; > } else { >- if (!EmitTree(cx, bce, pn2)) >+ ParseNode *expr = pn2->isKind(PNK_SPREAD) ? pn2->pn_kid : pn2; >+ if (!EmitTree(cx, bce, expr)) > return false; > } >- if (Emit1(cx, bce, JSOP_INITELEM) < 0) >- return false; >+ if (pn2->isKind(PNK_SPREAD)) { >+ if (Emit2(cx, bce, JSOP_ITER, JSITER_FOR_OF | JSITER_NULL_EMPTY) < 0) >+ return false; >+ if (Emit1(cx, bce, JSOP_SPREAD) < 0) >+ return false; >+ if (Emit1(cx, bce, JSOP_ENDITER) < 0) >+ return false; >+ } else if (Emit1(cx, bce, nspread ? JSOP_INITELEM_INC : JSOP_INITELEM) < 0) { >+ return false; >+ } > } > JS_ASSERT(atomIndex == pn->pn_count); >+ if (nspread) { >+ if (NewSrcNote(cx, bce, SRC_CONTINUE) < 0) >+ return false; >+ if (Emit1(cx, bce, JSOP_POP) < 0) >+ return false; >+ } > > if (pn->pn_xflags & PNX_ENDCOMMA) { > /* Emit a source note so we know to decompile an extra comma. */ > if (NewSrcNote(cx, bce, SRC_CONTINUE) < 0) > return false; > } > > /* Emit an op to finish the array and aid in decompilation. */ >diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h >--- a/js/src/frontend/ParseNode.h >+++ b/js/src/frontend/ParseNode.h >@@ -159,16 +159,17 @@ enum ParseNodeKind { > PNK_ARRAYPUSH, > PNK_LEXICALSCOPE, > PNK_LET, > PNK_SEQ, > PNK_FORIN, > PNK_FORHEAD, > PNK_ARGSBODY, > PNK_UPVARS, >+ PNK_SPREAD, > > /* > * The following parse node kinds occupy contiguous ranges to enable easy > * range-testing. > */ > > /* Equality operators. */ > PNK_STRICTEQ, >@@ -235,16 +236,17 @@ enum ParseNodeKind { > * PNK_STATEMENTLIST node for function body > * statements as final element > * pn_count: 1 + number of formal parameters > * PNK_UPVARS nameset pn_names: lexical dependencies (js::Definitions) > * defined in enclosing scopes, or ultimately not > * defined (free variables, either global property > * references or reference errors). > * pn_tree: PNK_ARGSBODY or PNK_STATEMENTLIST node >+ * PNK_SPREAD unary pn_kid: expression being spread > * > * <Statements> > * PNK_STATEMENTLIST list pn_head: list of pn_count statements > * PNK_IF ternary pn_kid1: cond, pn_kid2: then, pn_kid3: else or null. > * In body of a comprehension or desugared generator > * expression, pn_kid2 is PNK_YIELD, PNK_ARRAYPUSH, > * or (if the push was optimized away) empty > * PNK_STATEMENTLIST. >diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp >--- a/js/src/frontend/Parser.cpp >+++ b/js/src/frontend/Parser.cpp >@@ -6652,16 +6652,17 @@ Parser::primaryExpr(TokenKind tt, bool a > pn->makeEmpty(); > > #if JS_HAS_GENERATORS > pn->pn_blockid = tc->sc->blockidGen; > #endif > > matched = tokenStream.matchToken(TOK_RB, TSF_OPERAND); > if (!matched) { >+ bool spread = false; > for (index = 0; ; index++) { > if (index == StackSpace::ARGS_LENGTH_MAX) { > reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_ARRAY_INIT_TOO_BIG); > return NULL; > } > > tt = tokenStream.peekToken(TSF_OPERAND); > if (tt == TOK_RB) { >@@ -6670,22 +6671,34 @@ Parser::primaryExpr(TokenKind tt, bool a > } > > if (tt == TOK_COMMA) { > /* So CURRENT_TOKEN gets TOK_COMMA and not TOK_LB. */ > tokenStream.matchToken(TOK_COMMA); > pn2 = NullaryNode::create(PNK_COMMA, this); > pn->pn_xflags |= PNX_HOLEY | PNX_NONCONST; > } else { >+ ParseNode *spreadNode = NULL; >+ if (tt == TOK_TRIPLEDOT) { >+ spread = true; >+ spreadNode = UnaryNode::create(PNK_SPREAD, this); >+ if (!spreadNode) >+ return NULL; >+ tokenStream.getToken(); >+ } > pn2 = assignExpr(); > if (pn2) { > if (foldConstants && !FoldConstants(context, pn2, this)) > return NULL; >- if (!pn2->isConstant()) >+ if (!pn2->isConstant() || spreadNode) > pn->pn_xflags |= PNX_NONCONST; >+ if (spreadNode) { >+ spreadNode->pn_kid = pn2; >+ pn2 = spreadNode; >+ } > } > } > if (!pn2) > return NULL; > pn->append(pn2); > > if (tt != TOK_COMMA) { > /* If we didn't already match TOK_COMMA in above case. */ >@@ -6731,17 +6744,17 @@ Parser::primaryExpr(TokenKind tt, bool a > * runtime via JSOP_ENTERBLOCK. A block-local var is accessed by > * the JSOP_GETLOCAL and JSOP_SETLOCAL ops. These ops have an > * immediate operand, the local slot's stack index from fp->spbase. > * > * The array comprehension iteration step, array.push(i * j) in > * the example above, is done by <i * j>; JSOP_ARRAYCOMP <array>, > * where <array> is the index of array's stack slot. > */ >- if (index == 0 && pn->pn_count != 0 && tokenStream.matchToken(TOK_FOR)) { >+ if (index == 0 && !spread && pn->pn_count != 0 && tokenStream.matchToken(TOK_FOR)) { > ParseNode *pnexp, *pntop; > > /* Relabel pn as an array comprehension node. */ > pn->setKind(PNK_ARRAYCOMP); > > /* > * Remove the comprehension expression from pn's linked list > * and save it via pnexp. We'll re-install it underneath the >diff --git a/js/src/jit-test/tests/basic/spread-array-decompile.js b/js/src/jit-test/tests/basic/spread-array-decompile.js >new file mode 100644 >--- /dev/null >+++ b/js/src/jit-test/tests/basic/spread-array-decompile.js >@@ -0,0 +1,14 @@ >+var samples = [ >+ "[...a]", >+ "[...[1]]", >+ "[1, ...a, 2]", >+ "[1, ...[2, 3], 4]", >+ "[...[1], , ]", >+ "[1, , ...[2]]", >+ "[, 1, ...[2], ...[3], , 4, 5, , ]" >+]; >+for (var sample of samples) { >+ var source = "function f() {\n return " + sample + ";\n}"; >+ eval(source); >+ assertEq(f.toString(), source); >+} >diff --git a/js/src/jit-test/tests/basic/spread-array-evaluation-order.js b/js/src/jit-test/tests/basic/spread-array-evaluation-order.js >new file mode 100644 >--- /dev/null >+++ b/js/src/jit-test/tests/basic/spread-array-evaluation-order.js >@@ -0,0 +1,12 @@ >+load(libdir + "eqArrayHelper.js"); >+ >+var check = []; >+function t(token) { >+ check.push(token); >+ return token; >+} >+[3, ...[t(1)],, ...[t(2), t(3)], 34, 42, ...[t(4)]]; >+assertEqArray(check, [1, 2, 3, 4]); >+ >+var arr = [1, 2, 3]; >+assertEqArray([...arr, arr.pop()], [1, 2, 3, 3]); >diff --git a/js/src/jit-test/tests/basic/spread-array-invalid-syntax.js b/js/src/jit-test/tests/basic/spread-array-invalid-syntax.js >new file mode 100644 >--- /dev/null >+++ b/js/src/jit-test/tests/basic/spread-array-invalid-syntax.js >@@ -0,0 +1,14 @@ >+load(libdir + "asserts.js"); >+ >+var offenders = [ >+ "(1 ... n)", >+ "[1 ... n]", >+ "(...x)", >+ "[...x for (x of y)]", >+ "[...]", >+ "(...)", >+ "[...,]" >+]; >+for (var sample of offenders) { >+ assertThrowsInstanceOf(function () { eval(sample); }, SyntaxError); >+} >diff --git a/js/src/jit-test/tests/basic/spread-array-wrap.js b/js/src/jit-test/tests/basic/spread-array-wrap.js >new file mode 100644 >--- /dev/null >+++ b/js/src/jit-test/tests/basic/spread-array-wrap.js >@@ -0,0 +1,4 @@ >+load(libdir + "eqArrayHelper.js"); >+ >+assertEqArray([...wrap([1])], [1]); >+assertEqArray([1,, ...wrap([2, 3, 4]), 5, ...wrap([6])], [1,, 2, 3, 4, 5, 6]); >diff --git a/js/src/jit-test/tests/basic/spread-array.js b/js/src/jit-test/tests/basic/spread-array.js >new file mode 100644 >--- /dev/null >+++ b/js/src/jit-test/tests/basic/spread-array.js >@@ -0,0 +1,11 @@ >+load(libdir + "eqArrayHelper.js"); >+ >+assertEqArray([...[1, 2, 3]], [1, 2, 3]); >+assertEqArray([1, ...[2, 3, 4], 5], [1, 2, 3, 4, 5]); >+assertEqArray([1, ...[], 2], [1, 2]); >+assertEqArray([1, ...[2, 3], 4, ...[5, 6]], [1, 2, 3, 4, 5, 6]); >+assertEqArray([1, ...[], 2], [1, 2]); >+assertEqArray([1,, ...[2]], [1,, 2]); >+assertEqArray([1, ...null, 2], [1, 2]); >+assertEqArray([1, ...undefined, 2], [1, 2]); >+assertEqArray([1,, ...[2],, 3,, 4,], [1,, 2,, 3,, 4,]); >diff --git a/js/src/jsanalyze.cpp b/js/src/jsanalyze.cpp >--- a/js/src/jsanalyze.cpp >+++ b/js/src/jsanalyze.cpp >@@ -1464,16 +1464,25 @@ ScriptAnalysis::analyzeSSA(JSContext *cx > case JSOP_MOREITER: > stack[stackDepth - 2].v = code->poppedValues[0]; > break; > > case JSOP_INITPROP: > stack[stackDepth - 1].v = code->poppedValues[1]; > break; > >+ case JSOP_SPREAD: >+ stack[stackDepth - 3].v = code->poppedValues[2]; >+ stack[stackDepth - 1].v = code->poppedValues[0]; >+ break; >+ >+ case JSOP_INITELEM_INC: >+ stack[stackDepth - 2].v = code->poppedValues[2]; >+ break; >+ > case JSOP_INITELEM: > stack[stackDepth - 1].v = code->poppedValues[2]; > break; > > case JSOP_DUP: > stack[stackDepth - 1].v = stack[stackDepth - 2].v = code->poppedValues[0]; > break; > >diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h >--- a/js/src/jsfriendapi.h >+++ b/js/src/jsfriendapi.h >@@ -473,16 +473,17 @@ IsObjectInContextCompartment(const JSObj > * XDR_BYTECODE_VERSION. > */ > #define JSITER_ENUMERATE 0x1 /* for-in compatible hidden default iterator */ > #define JSITER_FOREACH 0x2 /* return [key, value] pair rather than key */ > #define JSITER_KEYVALUE 0x4 /* destructuring for-in wants [key, value] */ > #define JSITER_OWNONLY 0x8 /* iterate over obj's own properties only */ > #define JSITER_HIDDEN 0x10 /* also enumerate non-enumerable properties */ > #define JSITER_FOR_OF 0x20 /* harmony for-of loop */ >+#define JSITER_NULL_EMPTY 0x40 /* null and undefined should be treated as empty iterator */ > > inline uintptr_t > GetNativeStackLimit(const JSRuntime *rt) > { > return RuntimeFriendFields::get(rt)->nativeStackLimit; > } > > #define JS_CHECK_RECURSION(cx, onerror) \ >diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp >--- a/js/src/jsinfer.cpp >+++ b/js/src/jsinfer.cpp >@@ -3824,17 +3824,19 @@ ScriptAnalysis::analyzeTypesBytecode(JSC > types->addType(cx, Type::UnknownType()); > } > break; > } > > case JSOP_ENDINIT: > break; > >- case JSOP_INITELEM: { >+ case JSOP_INITELEM: >+ case JSOP_INITELEM_INC: >+ case JSOP_SPREAD: { > const SSAValue &objv = poppedValue(pc, 2); > jsbytecode *initpc = script->code + objv.pushedOffset(); > TypeObject *initializer = GetInitializerType(cx, script, initpc); > > if (initializer) { > pushed[0].addType(cx, Type::ObjectType(initializer)); > if (!initializer->unknownProperties()) { > /* >@@ -3845,23 +3847,42 @@ ScriptAnalysis::analyzeTypesBytecode(JSC > TypeSet *types = initializer->getProperty(cx, JSID_VOID, true); > if (!types) > return false; > if (state.hasGetSet) { > types->addType(cx, Type::UnknownType()); > } else if (state.hasHole) { > if (!initializer->unknownProperties()) > initializer->setFlags(cx, OBJECT_FLAG_NON_PACKED_ARRAY); >+ } else if (op != JSOP_SPREAD) { >+ poppedTypes(pc, 0)->addSubset(cx, types); > } else { >- poppedTypes(pc, 0)->addSubset(cx, types); >+ // Iterator could put arbitrary things into the array. >+ types->addType(cx, Type::UnknownType()); > } > } > } else { > pushed[0].addType(cx, Type::UnknownType()); > } >+ switch (op) { >+ case JSOP_SPREAD: >+ // poppedTypes(pc, 0) should go into pushed[2]. However, it is >+ // missing because JSOP_ITER doesn't push anything. We need to put >+ // something at the bottom of the stack, so CheckBytecode doesn't >+ // blow up. Ultimately, it doesn't matter, because it will just be >+ // popped off by JSOP_ENDITER. >+ pushed[2].addType(cx, Type::UnknownType()); >+ >+ // Fall through >+ case JSOP_INITELEM_INC: >+ poppedTypes(pc, 1)->addSubset(cx, &pushed[1]); >+ break; >+ default: >+ break; >+ } > state.hasGetSet = false; > state.hasHole = false; > break; > } > > case JSOP_GETTER: > case JSOP_SETTER: > state.hasGetSet = true; >diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp >--- a/js/src/jsinterp.cpp >+++ b/js/src/jsinterp.cpp >@@ -1499,27 +1499,25 @@ js::Interpret(JSContext *cx, StackFrame > switchMask = moreInterrupts ? -1 : 0; > switchOp = int(op); > goto do_switch; > #endif > } > > /* No-ops for ease of decompilation. */ > ADD_EMPTY_CASE(JSOP_NOP) >-ADD_EMPTY_CASE(JSOP_UNUSED0) > ADD_EMPTY_CASE(JSOP_UNUSED1) > ADD_EMPTY_CASE(JSOP_UNUSED2) > ADD_EMPTY_CASE(JSOP_UNUSED3) > ADD_EMPTY_CASE(JSOP_UNUSED8) > ADD_EMPTY_CASE(JSOP_UNUSED9) > ADD_EMPTY_CASE(JSOP_UNUSED10) > ADD_EMPTY_CASE(JSOP_UNUSED11) > ADD_EMPTY_CASE(JSOP_UNUSED12) > ADD_EMPTY_CASE(JSOP_UNUSED13) >-ADD_EMPTY_CASE(JSOP_UNUSED14) > ADD_EMPTY_CASE(JSOP_UNUSED15) > ADD_EMPTY_CASE(JSOP_UNUSED17) > ADD_EMPTY_CASE(JSOP_UNUSED18) > ADD_EMPTY_CASE(JSOP_UNUSED19) > ADD_EMPTY_CASE(JSOP_UNUSED20) > ADD_EMPTY_CASE(JSOP_UNUSED21) > ADD_EMPTY_CASE(JSOP_UNUSED22) > ADD_EMPTY_CASE(JSOP_UNUSED23) >@@ -3231,16 +3229,17 @@ BEGIN_CASE(JSOP_INITPROP) > JSPROP_ENUMERATE, 0, 0, 0)) { > goto error; > } > > regs.sp--; > } > END_CASE(JSOP_INITPROP); > >+BEGIN_CASE(JSOP_INITELEM_INC) > BEGIN_CASE(JSOP_INITELEM) > { > /* Pop the element's value into rval. */ > JS_ASSERT(regs.sp - regs.fp()->base() >= 3); > const Value &rref = regs.sp[-1]; > > RootedObject &obj = rootObject0; > >@@ -3265,19 +3264,51 @@ BEGIN_CASE(JSOP_INITELEM) > if (JSOp(regs.pc[JSOP_INITELEM_LENGTH]) == JSOP_ENDINIT && > !js_SetLengthProperty(cx, obj, (uint32_t) (JSID_TO_INT(id) + 1))) { > goto error; > } > } else { > if (!obj->defineGeneric(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE)) > goto error; > } >- regs.sp -= 2; >+ if (op == JSOP_INITELEM_INC) { >+ JS_ASSERT(obj->isArray()); >+ regs.sp[-2].setInt32(JSID_TO_INT(id) + 1); >+ regs.sp--; >+ } else { >+ regs.sp -= 2; >+ } > } > END_CASE(JSOP_INITELEM) >+END_CASE(JSOP_INITELEM_INC) >+ >+BEGIN_CASE(JSOP_SPREAD) >+{ >+ RootedObject arr(cx, ®s.sp[-3].toObject()); >+ JS_ASSERT(arr->isArray()); >+ RootedObject iterator(cx, ®s.sp[-1].toObject()); >+ int32_t count = regs.sp[-2].toInt32(); >+ while (true) { >+ Value rval; >+ bool onward; >+ if (!IteratorMore(cx, iterator, &onward, &rval)) >+ goto error; >+ if (!onward) >+ break; >+ Value item; >+ if (!IteratorNext(cx, iterator, &item)) >+ goto error; >+ RootedId id(cx, INT_TO_JSID(count)); >+ if (!arr->defineGeneric(cx, id, item, NULL, NULL, JSPROP_ENUMERATE)) >+ goto error; >+ count++; >+ } >+ regs.sp[-2].setInt32(count); >+} >+END_CASE(JSOP_SPREAD) > > { > BEGIN_CASE(JSOP_GOSUB) > PUSH_BOOLEAN(false); > int32_t i = (regs.pc - script->code) + JSOP_GOSUB_LENGTH; > len = GET_JUMP_OFFSET(regs.pc); > PUSH_INT32(i); > END_VARLEN_CASE >diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp >--- a/js/src/jsiter.cpp >+++ b/js/src/jsiter.cpp >@@ -880,26 +880,27 @@ js::ValueToIterator(JSContext *cx, unsig > } else { > /* > * Enumerating over null and undefined gives an empty enumerator. > * This is contrary to ECMA-262 9.9 ToObject, invoked from step 3 of > * the first production in 12.6.4 and step 4 of the second production, > * but it's "web JS" compatible. ES5 fixed for-in to match this de-facto > * standard. > */ >- if ((flags & JSITER_ENUMERATE)) { >+ if (flags & (JSITER_ENUMERATE | JSITER_NULL_EMPTY)) { > if (!js_ValueToObjectOrNull(cx, *vp, obj.address())) > return false; > /* fall through */ > } else { > obj = js_ValueToNonNullObject(cx, *vp); > if (!obj) > return false; > } > } >+ flags &= ~JSITER_NULL_EMPTY; > > return GetIterator(cx, obj, flags, vp); > } > > bool > js::CloseIterator(JSContext *cx, JSObject *obj) > { > cx->iterValue.setMagic(JS_NO_ITER_VALUE); >diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp >--- a/js/src/jsopcode.cpp >+++ b/js/src/jsopcode.cpp >@@ -5095,35 +5095,51 @@ Decompile(SprintStack *ss, jsbytecode *p > (sn && SN_TYPE(sn) == SRC_CONTINUE) ? ", " : "", > inArray ? ']' : '}'); > break; > } > > { > JSBool isFirst; > const char *maybeComma; >+ const char *maybeSpread; > > case JSOP_INITELEM: >+ case JSOP_INITELEM_INC: >+ case JSOP_SPREAD: >+ JS_ASSERT(ss->top >= 3); > isFirst = IsInitializerOp(ss->opcodes[ss->top - 3]); > > /* Turn off most parens. */ > rval = PopStr(ss, JSOP_SETNAME, &rvalpc); > > /* Turn off all parens for xval and lval, which we control. */ >- xval = PopStr(ss, JSOP_NOP); >+ xval = PopStr(ss, JSOP_NOP, &xvalpc); > lval = PopStr(ss, JSOP_NOP, &lvalpc); > sn = js_GetSrcNote(jp->script, pc); > > if (sn && SN_TYPE(sn) == SRC_INITPROP) { > atom = NULL; > goto do_initprop; > } > maybeComma = isFirst ? "" : ", "; >- todo = Sprint(&ss->sprinter, "%s%s", lval, maybeComma); >+ maybeSpread = op == JSOP_SPREAD ? "..." : ""; >+ todo = Sprint(&ss->sprinter, "%s%s%s", lval, maybeComma, maybeSpread); > SprintOpcode(ss, rval, rvalpc, pc, todo); >+ if (op != JSOP_INITELEM && todo != -1) { >+ if (!UpdateDecompiledText(ss, pushpc, todo)) >+ return NULL; >+ if (!PushOff(ss, todo, saveop, pushpc)) >+ return NULL; >+ if (!PushStr(ss, "", JSOP_NOP)) >+ return NULL; >+ if (op == JSOP_SPREAD && !PushStr(ss, "", JSOP_SPREAD)) >+ return NULL; >+ todo = -2; >+ } > break; > > case JSOP_INITPROP: > LOAD_ATOM(0); > xval = QuoteString(&ss->sprinter, atom, jschar(IsIdentifier(atom) ? 0 : '\'')); > if (!xval) > return NULL; > isFirst = IsInitializerOp(ss->opcodes[ss->top - 2]); >diff --git a/js/src/jsopcode.tbl b/js/src/jsopcode.tbl >--- a/js/src/jsopcode.tbl >+++ b/js/src/jsopcode.tbl >@@ -194,17 +194,17 @@ OPDEF(JSOP_FUNAPPLY, 79, "funapply", > OPDEF(JSOP_OBJECT, 80, "object", NULL, 5, 0, 1, 19, JOF_OBJECT) > > /* Pop value and discard it. */ > OPDEF(JSOP_POP, 81, "pop", NULL, 1, 1, 0, 2, JOF_BYTE) > > /* Call a function as a constructor; operand is argc. */ > OPDEF(JSOP_NEW, 82, js_new_str, NULL, 3, -1, 1, 17, JOF_UINT16|JOF_INVOKE|JOF_TYPESET) > >-OPDEF(JSOP_UNUSED0, 83, "unused0", NULL, 1, 0, 0, 0, JOF_BYTE) >+OPDEF(JSOP_SPREAD, 83, "spread", NULL, 1, 3, 3, 3, JOF_BYTE|JOF_ELEM|JOF_SET) > > /* Fast get/set ops for function arguments and local variables. */ > OPDEF(JSOP_GETARG, 84, "getarg", NULL, 3, 0, 1, 19, JOF_QARG |JOF_NAME) > OPDEF(JSOP_SETARG, 85, "setarg", NULL, 3, 1, 1, 3, JOF_QARG |JOF_NAME|JOF_SET) > OPDEF(JSOP_GETLOCAL, 86,"getlocal", NULL, 3, 0, 1, 19, JOF_LOCAL|JOF_NAME) > OPDEF(JSOP_SETLOCAL, 87,"setlocal", NULL, 3, 1, 1, 3, JOF_LOCAL|JOF_NAME|JOF_SET|JOF_DETECTING) > > /* Push unsigned 16-bit int constant. */ >@@ -219,17 +219,17 @@ OPDEF(JSOP_UINT16, 88, "uint16", > * NEWINIT has an extra byte so it can be exchanged with NEWOBJECT during emit. > */ > OPDEF(JSOP_NEWINIT, 89, "newinit", NULL, 5, 0, 1, 19, JOF_UINT8|JOF_TYPESET) > OPDEF(JSOP_NEWARRAY, 90, "newarray", NULL, 4, 0, 1, 19, JOF_UINT24|JOF_TYPESET) > OPDEF(JSOP_NEWOBJECT, 91, "newobject", NULL, 5, 0, 1, 19, JOF_OBJECT|JOF_TYPESET) > OPDEF(JSOP_ENDINIT, 92, "endinit", NULL, 1, 0, 0, 19, JOF_BYTE) > OPDEF(JSOP_INITPROP, 93, "initprop", NULL, 5, 2, 1, 3, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) > OPDEF(JSOP_INITELEM, 94, "initelem", NULL, 1, 3, 1, 3, JOF_BYTE|JOF_ELEM|JOF_SET|JOF_DETECTING) >-OPDEF(JSOP_UNUSED14, 95, "unused14", NULL, 1, 0, 0, 0, JOF_BYTE) >+OPDEF(JSOP_INITELEM_INC,95, "initelemincr", NULL, 1, 3, 2, 3, JOF_BYTE|JOF_ELEM|JOF_SET) > OPDEF(JSOP_UNUSED15, 96, "unused15", NULL, 1, 0, 0, 0, JOF_BYTE) > > /* Fast inc/dec ops for args and locals. */ > OPDEF(JSOP_INCARG, 97, "incarg", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_INC|JOF_TMPSLOT3) > OPDEF(JSOP_DECARG, 98, "decarg", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_DEC|JOF_TMPSLOT3) > OPDEF(JSOP_ARGINC, 99, "arginc", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3) > OPDEF(JSOP_ARGDEC, 100, "argdec", NULL, 3, 0, 1, 15, JOF_QARG |JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3) >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
Flags:
jorendorff
: review+
Actions:
View
|
Diff
|
Review
Attachments on
bug 574130
:
626236
|
630031
|
630399