mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 923028 - Part 2: Emit loop instead of JSOP_SPREAD. r=jandem
This commit is contained in:
parent
8ee77df43a
commit
af71ab7b52
@ -333,6 +333,7 @@ static const char * const statementName[] = {
|
||||
"for/in loop", /* FOR_IN_LOOP */
|
||||
"for/of loop", /* FOR_OF_LOOP */
|
||||
"while loop", /* WHILE_LOOP */
|
||||
"spread", /* SPREAD */
|
||||
};
|
||||
|
||||
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(statementName) == STMT_LIMIT);
|
||||
@ -603,6 +604,10 @@ NonLocalExitScope::prepareForNonLocalJump(StmtInfoBCE *toStmt)
|
||||
return false;
|
||||
break;
|
||||
|
||||
case STMT_SPREAD:
|
||||
MOZ_ASSERT_UNREACHABLE("can't break/continue/return from inside a spread");
|
||||
break;
|
||||
|
||||
case STMT_SUBROUTINE:
|
||||
/*
|
||||
* There's a [exception or hole, retsub pc-index] pair on the
|
||||
@ -706,13 +711,17 @@ PushLoopStatement(BytecodeEmitter *bce, LoopStmtInfo *stmt, StmtType type, ptrdi
|
||||
stmt->loopDepth = downLoop ? downLoop->loopDepth + 1 : 1;
|
||||
|
||||
int loopSlots;
|
||||
if (type == STMT_FOR_OF_LOOP)
|
||||
if (type == STMT_SPREAD)
|
||||
loopSlots = 3;
|
||||
else if (type == STMT_FOR_OF_LOOP)
|
||||
loopSlots = 2;
|
||||
else if (type == STMT_FOR_IN_LOOP)
|
||||
loopSlots = 1;
|
||||
else
|
||||
loopSlots = 0;
|
||||
|
||||
MOZ_ASSERT(loopSlots <= stmt->stackDepth);
|
||||
|
||||
if (downLoop)
|
||||
stmt->canIonOsr = (downLoop->canIonOsr &&
|
||||
stmt->stackDepth == downLoop->stackDepth + loopSlots);
|
||||
@ -4436,13 +4445,26 @@ EmitIterator(ExclusiveContext *cx, BytecodeEmitter *bce)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* If type is STMT_FOR_OF_LOOP, it emits bytecode for for-of loop.
|
||||
* pn should be PNK_FOR, and pn->pn_left should be PNK_FOROF.
|
||||
*
|
||||
* If type is STMT_SPREAD, it emits bytecode for spread operator.
|
||||
* pn should be nullptr.
|
||||
* Please refer the comment above EmitSpread for additional information about
|
||||
* stack convention.
|
||||
*/
|
||||
static bool
|
||||
EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
|
||||
EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, StmtType type, ParseNode *pn, ptrdiff_t top)
|
||||
{
|
||||
ParseNode *forHead = pn->pn_left;
|
||||
ParseNode *forBody = pn->pn_right;
|
||||
JS_ASSERT(type == STMT_FOR_OF_LOOP || type == STMT_SPREAD);
|
||||
JS_ASSERT_IF(type == STMT_FOR_OF_LOOP, pn && pn->pn_left->isKind(PNK_FOROF));
|
||||
JS_ASSERT_IF(type == STMT_SPREAD, !pn);
|
||||
|
||||
ParseNode *pn1 = forHead->pn_kid1;
|
||||
ParseNode *forHead = pn ? pn->pn_left : nullptr;
|
||||
ParseNode *forBody = pn ? pn->pn_right : nullptr;
|
||||
|
||||
ParseNode *pn1 = forHead ? forHead->pn_kid1 : nullptr;
|
||||
bool letDecl = pn1 && pn1->isKind(PNK_LEXICALSCOPE);
|
||||
JS_ASSERT_IF(letDecl, pn1->isLet());
|
||||
|
||||
@ -4457,19 +4479,27 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
|
||||
bce->emittingForInit = false;
|
||||
}
|
||||
|
||||
// For-of loops run with two values on the stack: the iterator and the
|
||||
// current result object.
|
||||
if (type == STMT_FOR_OF_LOOP) {
|
||||
// For-of loops run with two values on the stack: the iterator and the
|
||||
// current result object.
|
||||
|
||||
// Compile the object expression to the right of 'of'.
|
||||
if (!EmitTree(cx, bce, forHead->pn_kid3))
|
||||
return false;
|
||||
// Compile the object expression to the right of 'of'.
|
||||
if (!EmitTree(cx, bce, forHead->pn_kid3))
|
||||
return false;
|
||||
if (!EmitIterator(cx, bce))
|
||||
return false;
|
||||
|
||||
if (!EmitIterator(cx, bce))
|
||||
return false;
|
||||
|
||||
// Push a dummy result so that we properly enter iteration midstream.
|
||||
if (Emit1(cx, bce, JSOP_UNDEFINED) < 0) // ITER RESULT
|
||||
return false;
|
||||
// Push a dummy result so that we properly enter iteration midstream.
|
||||
if (Emit1(cx, bce, JSOP_UNDEFINED) < 0) // ITER RESULT
|
||||
return false;
|
||||
} else {
|
||||
// If type is STMT_SPREAD, it expects that iterator to be already on
|
||||
// the stack.
|
||||
if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)2) < 0) // I ITER ARR
|
||||
return false;
|
||||
if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)2) < 0) // ITER ARR I
|
||||
return false;
|
||||
}
|
||||
|
||||
// Enter the block before the loop body, after evaluating the obj.
|
||||
StmtInfoBCE letStmt(cx);
|
||||
@ -4479,7 +4509,7 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
|
||||
}
|
||||
|
||||
LoopStmtInfo stmtInfo(cx);
|
||||
PushLoopStatement(bce, &stmtInfo, STMT_FOR_OF_LOOP, top);
|
||||
PushLoopStatement(bce, &stmtInfo, type, top);
|
||||
|
||||
// Jump down to the loop condition to minimize overhead assuming at least
|
||||
// one iteration, as the other loop forms do. Annotate so IonMonkey can
|
||||
@ -4496,59 +4526,76 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
|
||||
if (EmitLoopHead(cx, bce, nullptr) < 0)
|
||||
return false;
|
||||
|
||||
if (type == STMT_SPREAD)
|
||||
bce->stackDepth++;
|
||||
|
||||
#ifdef DEBUG
|
||||
int loopDepth = bce->stackDepth;
|
||||
#endif
|
||||
|
||||
// Emit code to assign result.value to the iteration variable.
|
||||
if (Emit1(cx, bce, JSOP_DUP) < 0) // ITER RESULT RESULT
|
||||
return false;
|
||||
if (!EmitAtomOp(cx, cx->names().value, JSOP_GETPROP, bce)) // ITER RESULT VALUE
|
||||
return false;
|
||||
if (!EmitAssignment(cx, bce, forHead->pn_kid2, JSOP_NOP, nullptr)) // ITER RESULT VALUE
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_POP) < 0) // ITER RESULT
|
||||
if (type == STMT_FOR_OF_LOOP) {
|
||||
if (Emit1(cx, bce, JSOP_DUP) < 0) // ITER RESULT RESULT
|
||||
return false;
|
||||
}
|
||||
if (!EmitAtomOp(cx, cx->names().value, JSOP_GETPROP, bce)) // ... RESULT VALUE
|
||||
return false;
|
||||
if (type == STMT_FOR_OF_LOOP) {
|
||||
if (!EmitAssignment(cx, bce, forHead->pn_kid2, JSOP_NOP, nullptr)) // ITER RESULT VALUE
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_POP) < 0) // ITER RESULT
|
||||
return false;
|
||||
|
||||
// The stack should be balanced around the assignment opcode sequence.
|
||||
JS_ASSERT(bce->stackDepth == loopDepth);
|
||||
// The stack should be balanced around the assignment opcode sequence.
|
||||
JS_ASSERT(bce->stackDepth == loopDepth);
|
||||
|
||||
// Emit code for the loop body.
|
||||
if (!EmitTree(cx, bce, forBody))
|
||||
return false;
|
||||
// Emit code for the loop body.
|
||||
if (!EmitTree(cx, bce, forBody))
|
||||
return false;
|
||||
|
||||
// Set loop and enclosing "update" offsets, for continue.
|
||||
StmtInfoBCE *stmt = &stmtInfo;
|
||||
do {
|
||||
stmt->update = bce->offset();
|
||||
} while ((stmt = stmt->down) != nullptr && stmt->type == STMT_LABEL);
|
||||
// Set loop and enclosing "update" offsets, for continue.
|
||||
StmtInfoBCE *stmt = &stmtInfo;
|
||||
do {
|
||||
stmt->update = bce->offset();
|
||||
} while ((stmt = stmt->down) != nullptr && stmt->type == STMT_LABEL);
|
||||
} else {
|
||||
if (Emit1(cx, bce, JSOP_INITELEM_INC) < 0) // ITER ARR (I+1)
|
||||
return false;
|
||||
|
||||
JS_ASSERT(bce->stackDepth == loopDepth - 1);
|
||||
|
||||
// STMT_SPREAD never contain continue, so do not set "update" offset.
|
||||
}
|
||||
|
||||
// COME FROM the beginning of the loop to here.
|
||||
SetJumpOffsetAt(bce, jmp);
|
||||
if (!EmitLoopEntry(cx, bce, nullptr))
|
||||
return false;
|
||||
|
||||
if (Emit1(cx, bce, JSOP_POP) < 0) // ITER
|
||||
if (type == STMT_FOR_OF_LOOP) {
|
||||
if (Emit1(cx, bce, JSOP_POP) < 0) // ITER
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_DUP) < 0) // ITER ITER
|
||||
return false;
|
||||
} else {
|
||||
if (!EmitDupAt(cx, bce, bce->stackDepth - 1 - 2)) // ITER ARR I ITER
|
||||
return false;
|
||||
}
|
||||
if (Emit1(cx, bce, JSOP_DUP) < 0) // ... ITER ITER
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_DUP) < 0) // ITER ITER
|
||||
if (!EmitAtomOp(cx, cx->names().next, JSOP_CALLPROP, bce)) // ... ITER NEXT
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_DUP) < 0) // ITER ITER ITER
|
||||
if (Emit1(cx, bce, JSOP_SWAP) < 0) // ... NEXT ITER
|
||||
return false;
|
||||
if (!EmitAtomOp(cx, cx->names().next, JSOP_CALLPROP, bce)) // ITER ITER NEXT
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_SWAP) < 0) // ITER NEXT ITER
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_UNDEFINED) < 0) // ITER NEXT ITER UNDEFINED
|
||||
return false;
|
||||
if (EmitCall(cx, bce, JSOP_CALL, 1, forHead) < 0) // ITER RESULT
|
||||
if (EmitCall(cx, bce, JSOP_CALL, 0, forHead) < 0) // ... RESULT
|
||||
return false;
|
||||
CheckTypeSet(cx, bce, JSOP_CALL);
|
||||
if (Emit1(cx, bce, JSOP_DUP) < 0) // ITER RESULT RESULT
|
||||
if (Emit1(cx, bce, JSOP_DUP) < 0) // ... RESULT RESULT
|
||||
return false;
|
||||
if (!EmitAtomOp(cx, cx->names().done, JSOP_GETPROP, bce)) // ITER RESULT DONE?
|
||||
if (!EmitAtomOp(cx, cx->names().done, JSOP_GETPROP, bce)) // ... RESULT DONE?
|
||||
return false;
|
||||
|
||||
ptrdiff_t beq = EmitJump(cx, bce, JSOP_IFEQ, top - bce->offset()); // ITER RESULT
|
||||
ptrdiff_t beq = EmitJump(cx, bce, JSOP_IFEQ, top - bce->offset()); // ... RESULT
|
||||
if (beq < 0)
|
||||
return false;
|
||||
|
||||
@ -4559,6 +4606,7 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
|
||||
return false;
|
||||
|
||||
// Fixup breaks and continues.
|
||||
// For STMT_SPREAD, just pop pc->topStmt.
|
||||
if (!PopStatementBCE(cx, bce))
|
||||
return false;
|
||||
|
||||
@ -4567,6 +4615,11 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type == STMT_SPREAD) {
|
||||
if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)3) < 0) // ARR I RESULT ITER
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pop the result and the iter.
|
||||
EMIT_UINT16_IMM_OP(JSOP_POPN, 2);
|
||||
|
||||
@ -4856,7 +4909,7 @@ EmitFor(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top
|
||||
return EmitForIn(cx, bce, pn, top);
|
||||
|
||||
if (pn->pn_left->isKind(PNK_FOROF))
|
||||
return EmitForOf(cx, bce, pn, top);
|
||||
return EmitForOf(cx, bce, STMT_FOR_OF_LOOP, pn, top);
|
||||
|
||||
JS_ASSERT(pn->pn_left->isKind(PNK_FORHEAD));
|
||||
return EmitNormalFor(cx, bce, pn, top);
|
||||
@ -6079,6 +6132,19 @@ EmitArrayComp(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
return Emit1(cx, bce, JSOP_ENDINIT) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* EmitSpread expects the iterator, the current index (I) of the array, and the
|
||||
* array itself to be on the stack in that order (iterator on the top). It will
|
||||
* pop the iterator and I, then iterate over the iterator by calling |.next()|
|
||||
* and put the results into the I-th element of array with incrementing I, then
|
||||
* push the result I (it will be original I + iteration count).
|
||||
*/
|
||||
static bool
|
||||
EmitSpread(ExclusiveContext *cx, BytecodeEmitter *bce)
|
||||
{
|
||||
return EmitForOf(cx, bce, STMT_SPREAD, nullptr, -1);
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitArray(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, uint32_t count)
|
||||
{
|
||||
@ -6129,7 +6195,7 @@ EmitArray(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, uint32_t co
|
||||
if (pn2->isKind(PNK_SPREAD)) {
|
||||
if (!EmitIterator(cx, bce))
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_SPREAD) < 0)
|
||||
if (!EmitSpread(cx, bce))
|
||||
return false;
|
||||
} else if (afterSpread) {
|
||||
if (Emit1(cx, bce, JSOP_INITELEM_INC) < 0)
|
||||
|
@ -359,6 +359,7 @@ enum StmtType {
|
||||
STMT_FOR_IN_LOOP, /* for/in loop statement */
|
||||
STMT_FOR_OF_LOOP, /* for/of loop statement */
|
||||
STMT_WHILE_LOOP, /* while loop statement */
|
||||
STMT_SPREAD, /* spread operator (pseudo for/of) */
|
||||
STMT_LIMIT
|
||||
};
|
||||
|
||||
|
@ -7,7 +7,7 @@ var log = '';
|
||||
function Iter() {
|
||||
function next() {
|
||||
log += 'n';
|
||||
assertEq(arguments.length, 1)
|
||||
assertEq(arguments.length, 0)
|
||||
assertEq(arguments[0], undefined)
|
||||
return { get value() { throw 42; }, done: true }
|
||||
}
|
||||
|
@ -2370,34 +2370,6 @@ BaselineCompiler::emit_JSOP_INITELEM_INC()
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*SpreadFn)(JSContext *, HandleObject, HandleValue,
|
||||
HandleValue, MutableHandleValue);
|
||||
static const VMFunction SpreadInfo = FunctionInfo<SpreadFn>(js::SpreadOperation);
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_SPREAD()
|
||||
{
|
||||
// Load index and iterator in R0 and R1, but keep values on the stack for
|
||||
// the decompiler.
|
||||
frame.syncStack(0);
|
||||
masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
|
||||
masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
|
||||
|
||||
prepareVMCall();
|
||||
|
||||
pushArg(R1);
|
||||
pushArg(R0);
|
||||
masm.extractObject(frame.addressOfStackValue(frame.peek(-3)), R0.scratchReg());
|
||||
pushArg(R0.scratchReg());
|
||||
|
||||
if (!callVM(SpreadInfo))
|
||||
return false;
|
||||
|
||||
frame.popn(2);
|
||||
frame.push(R0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_GETLOCAL()
|
||||
{
|
||||
|
@ -98,7 +98,6 @@ namespace jit {
|
||||
_(JSOP_INITELEM_GETTER) \
|
||||
_(JSOP_INITELEM_SETTER) \
|
||||
_(JSOP_INITELEM_INC) \
|
||||
_(JSOP_SPREAD) \
|
||||
_(JSOP_MUTATEPROTO) \
|
||||
_(JSOP_INITPROP) \
|
||||
_(JSOP_INITPROP_GETTER) \
|
||||
|
@ -1,13 +1,11 @@
|
||||
// Test corner cases of for-of iteration over Arrays.
|
||||
// The current spidermonky JSOP_SPREAD implementation for function calls
|
||||
// with '...rest' arguments uses a ForOfIterator to extract values from
|
||||
// the array, so we use that mechanism to test ForOfIterator here.
|
||||
|
||||
// The current SetObject::construct method uses a ForOfIterator to extract
|
||||
// values from the array, so we use that mechanism to test ForOfIterator here.
|
||||
|
||||
// Test the properties and prototype of a generator object.
|
||||
function TestManySmallArrays() {
|
||||
function doIter(f, arr) {
|
||||
return f(...arr)
|
||||
return f(...new Set(arr));
|
||||
}
|
||||
|
||||
function fun(a, b, c) {
|
||||
@ -37,7 +35,7 @@ TestManySmallArrays();
|
||||
// Test the properties and prototype of a generator object.
|
||||
function TestSingleSmallArray() {
|
||||
function doIter(f, arr) {
|
||||
return f(...arr)
|
||||
return f(...new Set(arr));
|
||||
}
|
||||
|
||||
function fun(a, b, c) {
|
||||
@ -69,7 +67,7 @@ TestSingleSmallArray();
|
||||
|
||||
function TestChangeArrayPrototype() {
|
||||
function doIter(f, arr) {
|
||||
return f(...arr)
|
||||
return f(...new Set(arr));
|
||||
}
|
||||
|
||||
function fun(a, b, c) {
|
||||
@ -106,7 +104,7 @@ TestChangeArrayPrototype();
|
||||
|
||||
function TestChangeManyArrayShape() {
|
||||
function doIter(f, arr) {
|
||||
return f(...arr)
|
||||
return f(...new Set(arr));
|
||||
}
|
||||
|
||||
function fun(a, b, c) {
|
||||
|
@ -1,14 +1,13 @@
|
||||
// Test corner cases of for-of iteration over Arrays.
|
||||
// The current spidermonky JSOP_SPREAD implementation for function calls
|
||||
// with '...rest' arguments uses a ForOfIterator to extract values from
|
||||
// the array, so we use that mechanism to test ForOfIterator here.
|
||||
// The current SetObject::construct method uses a ForOfIterator to extract
|
||||
// values from the array, so we use that mechanism to test ForOfIterator here.
|
||||
|
||||
//
|
||||
// Check case where ArrayIterator.prototype.next changes in the middle of iteration.
|
||||
//
|
||||
function TestChangeArrayIteratorNext() {
|
||||
function doIter(f, arr) {
|
||||
return f(...arr)
|
||||
return f(...new Set(arr));
|
||||
}
|
||||
|
||||
function fun(a, b, c) {
|
||||
|
@ -1,14 +1,13 @@
|
||||
// Test corner cases of for-of iteration over Arrays.
|
||||
// The current spidermonkey JSOP_SPREAD implementation for function calls
|
||||
// with '...rest' arguments uses a ForOfIterator to extract values from
|
||||
// the array, so we use that mechanism to test ForOfIterator here.
|
||||
// The current SetObject::construct method uses a ForOfIterator to extract
|
||||
// values from the array, so we use that mechanism to test ForOfIterator here.
|
||||
|
||||
//
|
||||
// Check array length increases changes during iteration.
|
||||
//
|
||||
function TestIncreaseArrayLength() {
|
||||
function doIter(f, arr) {
|
||||
return f(...arr)
|
||||
return f(...new Set(arr));
|
||||
}
|
||||
|
||||
function fun(a, b, c) {
|
||||
|
@ -1,14 +1,13 @@
|
||||
// Test corner cases of for-of iteration over Arrays.
|
||||
// The current spidermonkey JSOP_SPREAD implementation for function calls
|
||||
// with '...rest' arguments uses a ForOfIterator to extract values from
|
||||
// the array, so we use that mechanism to test ForOfIterator here.
|
||||
// The current SetObject::construct method uses a ForOfIterator to extract
|
||||
// values from the array, so we use that mechanism to test ForOfIterator here.
|
||||
|
||||
//
|
||||
// Check array length decreases changes during iteration.
|
||||
//
|
||||
function TestDecreaseArrayLength() {
|
||||
function doIter(f, arr) {
|
||||
return f(...arr)
|
||||
return f(...new Set(arr));
|
||||
}
|
||||
|
||||
function fun(a, b, c) {
|
||||
|
@ -1597,6 +1597,7 @@ CASE(JSOP_UNUSED50)
|
||||
CASE(JSOP_UNUSED51)
|
||||
CASE(JSOP_UNUSED52)
|
||||
CASE(JSOP_UNUSED57)
|
||||
CASE(JSOP_UNUSED83)
|
||||
CASE(JSOP_UNUSED101)
|
||||
CASE(JSOP_UNUSED102)
|
||||
CASE(JSOP_UNUSED103)
|
||||
@ -3178,21 +3179,6 @@ CASE(JSOP_INITELEM_INC)
|
||||
}
|
||||
END_CASE(JSOP_INITELEM_INC)
|
||||
|
||||
CASE(JSOP_SPREAD)
|
||||
{
|
||||
HandleValue countVal = REGS.stackHandleAt(-2);
|
||||
RootedObject &arr = rootObject0;
|
||||
arr = ®S.sp[-3].toObject();
|
||||
HandleValue iterator = REGS.stackHandleAt(-1);
|
||||
MutableHandleValue resultCountVal = REGS.stackHandleAt(-2);
|
||||
|
||||
if (!SpreadOperation(cx, arr, countVal, iterator, resultCountVal))
|
||||
goto error;
|
||||
|
||||
REGS.sp--;
|
||||
}
|
||||
END_CASE(JSOP_SPREAD)
|
||||
|
||||
CASE(JSOP_GOSUB)
|
||||
{
|
||||
PUSH_BOOLEAN(false);
|
||||
@ -3897,34 +3883,6 @@ js::InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, H
|
||||
return InitGetterSetterOperation(cx, pc, obj, id, val);
|
||||
}
|
||||
|
||||
bool
|
||||
js::SpreadOperation(JSContext *cx, HandleObject arr, HandleValue countVal,
|
||||
HandleValue iterator, MutableHandleValue resultCountVal)
|
||||
{
|
||||
int32_t count = countVal.toInt32();
|
||||
ForOfIterator iter(cx);
|
||||
RootedValue iterVal(cx, iterator);
|
||||
if (!iter.initWithIterator(iterVal))
|
||||
return false;
|
||||
while (true) {
|
||||
bool done;
|
||||
if (!iter.next(&iterVal, &done))
|
||||
return false;
|
||||
if (done)
|
||||
break;
|
||||
if (count == INT32_MAX) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
|
||||
JSMSG_SPREAD_TOO_LARGE);
|
||||
return false;
|
||||
}
|
||||
if (!JSObject::defineElement(cx, arr, count++, iterVal, nullptr, nullptr,
|
||||
JSPROP_ENUMERATE))
|
||||
return false;
|
||||
}
|
||||
resultCountVal.setInt32(count);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::SpreadCallOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue thisv,
|
||||
HandleValue callee, HandleValue arr, MutableHandleValue res)
|
||||
|
@ -462,10 +462,6 @@ bool
|
||||
InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandleValue idval,
|
||||
HandleObject val);
|
||||
|
||||
bool
|
||||
SpreadOperation(JSContext *cx, HandleObject arr, HandleValue countVal,
|
||||
HandleValue iterable, MutableHandleValue resultCountVal);
|
||||
|
||||
bool
|
||||
SpreadCallOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue thisv,
|
||||
HandleValue callee, HandleValue arr, MutableHandleValue res);
|
||||
|
@ -690,20 +690,8 @@
|
||||
* nuses: (argc+2)
|
||||
*/ \
|
||||
macro(JSOP_NEW, 82, js_new_str, NULL, 3, -1, 1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET) \
|
||||
/*
|
||||
* Pops the top three values on the stack as 'iterator', 'index' and 'obj',
|
||||
* iterates over 'iterator' and stores the iteration values as 'index + i'
|
||||
* elements of 'obj', pushes 'obj' and 'index + iteration count' onto the
|
||||
* stack.
|
||||
*
|
||||
* This opcode is used in Array literals with spread and spreadcall
|
||||
* arguments as well as in destructing assignment with rest element.
|
||||
* Category: Literals
|
||||
* Type: Array
|
||||
* Operands:
|
||||
* Stack: obj, index, iterator => obj, (index + iteration count)
|
||||
*/ \
|
||||
macro(JSOP_SPREAD, 83, "spread", NULL, 1, 3, 2, JOF_BYTE|JOF_ELEM|JOF_SET) \
|
||||
\
|
||||
macro(JSOP_UNUSED83, 83, "unused83", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
\
|
||||
/*
|
||||
* Fast get op for function arguments and local variables.
|
||||
|
@ -28,7 +28,7 @@ namespace js {
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
|
||||
*/
|
||||
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 175);
|
||||
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 176);
|
||||
|
||||
class XDRBuffer {
|
||||
public:
|
||||
|
Loading…
Reference in New Issue
Block a user