Backed out changeset 9716bcfed35d (bug 1184922)

This commit is contained in:
Tooru Fujisawa 2016-10-09 13:18:51 +09:00
Родитель 4a9787ac6a
Коммит 9c1a8a5b6a
1 изменённых файлов: 54 добавлений и 209 удалений

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

@ -4513,76 +4513,6 @@ BytecodeEmitter::emitDestructuringOpsArrayHelper(ParseNode* pattern, Destructuri
MOZ_ASSERT(pattern->isArity(PN_LIST));
MOZ_ASSERT(this->stackDepth != 0);
// Here's pseudo code for |let [a, b, , c=y, ...d] = x;|
//
// let x, y;
// let a, b, c, d;
// let tmp, done, iter, result; // stack values
//
// iter = x[Symbol.iterator]();
//
// // ==== emitted by loop for a ====
// result = iter.next();
// done = result.done;
//
// if (done) {
// a = undefined;
//
// result = undefined;
// done = true;
// } else {
// a = result.value;
//
// // Do next element's .next() and .done access here
// result = iter.next();
// done = result.done;
// }
//
// // ==== emitted by loop for b ====
// if (done) {
// b = undefined;
//
// result = undefined;
// done = true;
// } else {
// b = result.value;
//
// result = iter.next();
// done = result.done;
// }
//
// // ==== emitted by loop for elision ====
// if (done) {
// result = undefined
// done = true
// } else {
// result.value;
//
// result = iter.next();
// done = result.done;
// }
//
// // ==== emitted by loop for c ====
// if (done) {
// c = y;
// } else {
// tmp = result.value;
// if (tmp === undefined)
// tmp = y;
// c = tmp;
//
// // Don't do next element's .next() and .done access if
// // this is the last non-spread element.
// }
//
// // ==== emitted by loop for d ====
// if (done) {
// // Assing empty array when completed
// d = [];
// } else {
// d = [...iter];
// }
/*
* Use an iterator to destructure the RHS, instead of index lookup. We
* must leave the *original* value on the stack.
@ -4594,37 +4524,20 @@ BytecodeEmitter::emitDestructuringOpsArrayHelper(ParseNode* pattern, Destructuri
bool needToPopIterator = true;
for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) {
bool isHead = member == pattern->pn_head;
if (member->isKind(PNK_SPREAD)) {
JumpList beq;
JumpList end;
unsigned noteIndex = -1;
if (!isHead) {
// If spread is not the first element of the pattern,
// iterator can already be completed.
if (!newSrcNote(SRC_IF_ELSE, &noteIndex))
return false;
if (!emitJump(JSOP_IFEQ, &beq)) // ... OBJ? ITER
return false;
/*
* Now push the property name currently being matched, which is the
* current property name "label" on the left of a colon in the object
* initializer.
*/
ParseNode* pndefault = nullptr;
ParseNode* elem = member;
if (elem->isKind(PNK_ASSIGN)) {
pndefault = elem->pn_right;
elem = elem->pn_left;
}
int32_t depth = stackDepth;
if (!emit1(JSOP_POP)) // ... OBJ?
return false;
if (!emitUint32Operand(JSOP_NEWARRAY, 0)) // ... OBJ? ARRAY
return false;
if (!emitDestructuringLHS(member, flav)) // ... OBJ?
return false;
if (!emitJump(JSOP_GOTO, &end))
return false;
if (!emitJumpTargetAndPatch(beq))
return false;
stackDepth = depth;
}
// If iterator is not completed, create a new array with the rest
// of the iterator.
if (elem->isKind(PNK_SPREAD)) {
/* Create a new array with the rest of the iterator */
if (!emitUint32Operand(JSOP_NEWARRAY, 0)) // ... OBJ? ITER ARRAY
return false;
if (!emitNumberOp(0)) // ... OBJ? ITER ARRAY INDEX
@ -4633,136 +4546,68 @@ BytecodeEmitter::emitDestructuringOpsArrayHelper(ParseNode* pattern, Destructuri
return false;
if (!emit1(JSOP_POP)) // ... OBJ? ARRAY
return false;
if (!emitDestructuringLHS(member, flav)) // ... OBJ?
return false;
if (!isHead) {
if (!emitJumpTargetAndPatch(end))
return false;
if (!setSrcNoteOffset(noteIndex, 0, end.offset - beq.offset))
return false;
}
needToPopIterator = false;
MOZ_ASSERT(!member->pn_next);
break;
}
ParseNode* pndefault = nullptr;
ParseNode* subpattern = member;
if (subpattern->isKind(PNK_ASSIGN)) {
pndefault = subpattern->pn_right;
subpattern = subpattern->pn_left;
}
bool isElision = subpattern->isKind(PNK_ELISION);
bool hasNextNonSpread = member->pn_next && !member->pn_next->isKind(PNK_SPREAD);
bool hasNextSpread = member->pn_next && member->pn_next->isKind(PNK_SPREAD);
MOZ_ASSERT(!subpattern->isKind(PNK_SPREAD));
auto emitNext = [pattern](ExclusiveContext* cx, BytecodeEmitter* bce) {
if (!bce->emit1(JSOP_DUP)) // ... OBJ? ITER ITER
return false;
if (!bce->emitIteratorNext(pattern)) // ... OBJ? ITER RESULT
return false;
if (!bce->emit1(JSOP_DUP)) // ... OBJ? ITER RESULT RESULT
return false;
if (!bce->emitAtomOp(cx->names().done, JSOP_GETPROP)) // ... OBJ? ITER RESULT DONE?
return false;
return true;
};
if (isHead) {
if (!emitNext(cx, this)) // ... OBJ? ITER RESULT DONE?
return false;
}
unsigned noteIndex;
if (!newSrcNote(SRC_IF_ELSE, &noteIndex))
return false;
JumpList beq;
if (!emitJump(JSOP_IFEQ, &beq)) // ... OBJ? ITER RESULT
return false;
int32_t depth = stackDepth;
if (!emit1(JSOP_POP)) // ... OBJ? ITER
return false;
if (pndefault) {
// Emit only pndefault tree here, as undefined check in emitDefault
// should always be true.
if (!emitConditionallyExecutedTree(pndefault)) // ... OBJ? ITER VALUE
return false;
} else {
if (!isElision) {
if (!emit1(JSOP_UNDEFINED)) // ... OBJ? ITER UNDEFINED
return false;
if (!emit1(JSOP_NOP_DESTRUCTURING))
return false;
}
}
if (!isElision) {
if (!emitDestructuringLHS(subpattern, flav)) // ... OBJ? ITER
if (!emit1(JSOP_DUP)) // ... OBJ? ITER ITER
return false;
} else if (pndefault) {
if (!emitIteratorNext(pattern)) // ... OBJ? ITER RESULT
return false;
if (!emit1(JSOP_DUP)) // ... OBJ? ITER RESULT RESULT
return false;
if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // ... OBJ? ITER RESULT DONE?
return false;
// Emit (result.done ? undefined : result.value)
// This is mostly copied from emitConditionalExpression, except that this code
// does not push new values onto the stack.
unsigned noteIndex;
if (!newSrcNote(SRC_COND, &noteIndex))
return false;
JumpList beq;
if (!emitJump(JSOP_IFEQ, &beq))
return false;
if (!emit1(JSOP_POP)) // ... OBJ? ITER
return false;
}
// Setup next element's result when the iterator is done.
if (hasNextNonSpread) {
if (!emit1(JSOP_UNDEFINED)) // ... OBJ? ITER RESULT
if (!emit1(JSOP_UNDEFINED)) // ... OBJ? ITER UNDEFINED
return false;
if (!emit1(JSOP_NOP_DESTRUCTURING))
return false;
if (!emit1(JSOP_TRUE)) // ... OBJ? ITER RESULT DONE?
/* Jump around else, fixup the branch, emit else, fixup jump. */
JumpList jmp;
if (!emitJump(JSOP_GOTO, &jmp))
return false;
} else if (hasNextSpread) {
if (!emit1(JSOP_TRUE)) // ... OBJ? ITER DONE?
if (!emitJumpTargetAndPatch(beq))
return false;
if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // ... OBJ? ITER VALUE
return false;
if (!emitJumpTargetAndPatch(jmp))
return false;
if (!setSrcNoteOffset(noteIndex, 0, jmp.offset - beq.offset))
return false;
}
JumpList end;
if (!emitJump(JSOP_GOTO, &end))
return false;
if (!emitJumpTargetAndPatch(beq))
if (pndefault && !emitDefault(pndefault))
return false;
stackDepth = depth;
if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // ... OBJ? ITER VALUE
return false;
if (pndefault) {
if (!emitDefault(pndefault)) // ... OBJ? ITER VALUE
return false;
}
if (!isElision) {
if (!emitDestructuringLHS(subpattern, flav)) // ... OBJ? ITER
return false;
} else {
// Destructure into the pattern the element contains.
ParseNode* subpattern = elem;
if (subpattern->isKind(PNK_ELISION)) {
// The value destructuring into an elision just gets ignored.
if (!emit1(JSOP_POP)) // ... OBJ? ITER
return false;
continue;
}
// Setup next element's result when the iterator is not done.
if (hasNextNonSpread) {
if (!emitNext(cx, this)) // ... OBJ? ITER RESULT DONE?
return false;
} else if (hasNextSpread) {
if (!emit1(JSOP_FALSE)) // ... OBJ? ITER DONE?
return false;
}
if (!emitJumpTargetAndPatch(end))
return false;
if (!setSrcNoteOffset(noteIndex, 0, end.offset - beq.offset))
if (!emitDestructuringLHS(subpattern, flav))
return false;
}
if (needToPopIterator) {
if (!emit1(JSOP_POP)) // ... OBJ?
return false;
}
if (needToPopIterator && !emit1(JSOP_POP))
return false;
return true;
}