mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-07 00:08:39 +09:00
Bug 1322314 - Do not emit ParseNode twice in BytecodeEmitter::emitDestructuringOpsArray
Issue #73 [Depends on] Bug 1147371: Implement IteratorClose
This commit is contained in:
parent
4d3e61136f
commit
078b9f3edc
3 changed files with 144 additions and 139 deletions
|
|
@ -4462,13 +4462,6 @@ BytecodeEmitter::emitDestructuringLHS(ParseNode* target, DestructuringFlavor fla
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitDestructuringLHSInBranch(ParseNode* target, DestructuringFlavor flav)
|
||||
{
|
||||
TDZCheckCache tdzCache(this);
|
||||
return emitDestructuringLHS(target, flav);
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitIteratorNext(ParseNode* pn, bool allowSelfHosted)
|
||||
{
|
||||
|
|
@ -4739,7 +4732,7 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav
|
|||
//
|
||||
// let x, y;
|
||||
// let a, b, c, d;
|
||||
// let tmp, done, iter, result; // stack values
|
||||
// let iter, result, done, value; // stack values
|
||||
//
|
||||
// iter = x[Symbol.iterator]();
|
||||
//
|
||||
|
|
@ -4747,115 +4740,113 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav
|
|||
// result = iter.next();
|
||||
// done = result.done;
|
||||
//
|
||||
// if (done) {
|
||||
// a = undefined;
|
||||
// if (done)
|
||||
// value = undefined;
|
||||
// else
|
||||
// value = result.value;
|
||||
//
|
||||
// result = undefined;
|
||||
// done = true;
|
||||
// } else {
|
||||
// a = result.value;
|
||||
//
|
||||
// // Do next element's .next() and .done access here
|
||||
// result = iter.next();
|
||||
// done = result.done;
|
||||
// }
|
||||
// a = value;
|
||||
//
|
||||
// // ==== emitted by loop for b ====
|
||||
// if (done) {
|
||||
// b = undefined;
|
||||
//
|
||||
// result = undefined;
|
||||
// done = true;
|
||||
// value = undefined;
|
||||
// } else {
|
||||
// b = result.value;
|
||||
//
|
||||
// result = iter.next();
|
||||
// done = result.done;
|
||||
// if (done)
|
||||
// value = undefined;
|
||||
// else
|
||||
// value = result.value;
|
||||
// }
|
||||
//
|
||||
// b = value;
|
||||
//
|
||||
// // ==== emitted by loop for elision ====
|
||||
// if (done) {
|
||||
// result = undefined
|
||||
// done = true
|
||||
// value = undefined;
|
||||
// } else {
|
||||
// result.value;
|
||||
//
|
||||
// result = iter.next();
|
||||
// done = result.done;
|
||||
// if (done)
|
||||
// value = undefined;
|
||||
// else
|
||||
// value = result.value;
|
||||
// }
|
||||
//
|
||||
// // ==== emitted by loop for c ====
|
||||
// if (done) {
|
||||
// c = y;
|
||||
// value = undefined;
|
||||
// } 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.
|
||||
// result = iter.next();
|
||||
// done = result.done;
|
||||
// if (done)
|
||||
// value = undefined;
|
||||
// else
|
||||
// value = result.value;
|
||||
// }
|
||||
//
|
||||
// if (value === undefined)
|
||||
// value = y;
|
||||
//
|
||||
// c = value;
|
||||
//
|
||||
// // ==== emitted by loop for d ====
|
||||
// if (done) {
|
||||
// // Assing empty array when completed
|
||||
// d = [];
|
||||
// } else {
|
||||
// d = [...iter];
|
||||
// }
|
||||
// if (done)
|
||||
// value = [];
|
||||
// else
|
||||
// value = [...iter];
|
||||
//
|
||||
// d = value;
|
||||
|
||||
/*
|
||||
* Use an iterator to destructure the RHS, instead of index lookup. We
|
||||
* must leave the *original* value on the stack.
|
||||
*/
|
||||
// Use an iterator to destructure the RHS, instead of index lookup. We
|
||||
// must leave the *original* value on the stack.
|
||||
if (!emit1(JSOP_DUP)) // ... OBJ OBJ
|
||||
return false;
|
||||
if (!emitIterator()) // ... OBJ? ITER
|
||||
if (!emitIterator()) // ... OBJ ITER
|
||||
return false;
|
||||
bool needToPopIterator = true;
|
||||
|
||||
for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) {
|
||||
bool isHead = member == pattern->pn_head;
|
||||
bool hasNext = !!member->pn_next;
|
||||
|
||||
if (member->isKind(PNK_SPREAD)) {
|
||||
IfThenElseEmitter ifThenElse(this);
|
||||
if (!isHead) {
|
||||
// If spread is not the first element of the pattern,
|
||||
// iterator can already be completed.
|
||||
if (!ifThenElse.emitIfElse()) // ... OBJ? ITER
|
||||
// ... OBJ ITER DONE
|
||||
if (!ifThenElse.emitIfElse()) // ... OBJ ITER
|
||||
return false;
|
||||
|
||||
if (!emit1(JSOP_POP)) // ... OBJ?
|
||||
if (!emitUint32Operand(JSOP_NEWARRAY, 0)) // ... OBJ ITER ARRAY
|
||||
return false;
|
||||
if (!emitUint32Operand(JSOP_NEWARRAY, 0)) // ... OBJ? ARRAY
|
||||
return false;
|
||||
if (!emitDestructuringLHSInBranch(member, flav)) // ... OBJ?
|
||||
return false;
|
||||
|
||||
if (!ifThenElse.emitElse()) // ... OBJ? ITER
|
||||
if (!ifThenElse.emitElse()) // ... OBJ ITER
|
||||
return false;
|
||||
}
|
||||
|
||||
// If iterator is not completed, create a new array with the rest
|
||||
// of the iterator.
|
||||
if (!emitUint32Operand(JSOP_NEWARRAY, 0)) // ... OBJ? ITER ARRAY
|
||||
if (!emit1(JSOP_DUP)) // ... OBJ ITER
|
||||
return false;
|
||||
if (!emitNumberOp(0)) // ... OBJ? ITER ARRAY INDEX
|
||||
if (!emitUint32Operand(JSOP_NEWARRAY, 0)) // ... OBJ ITER ITER ARRAY
|
||||
return false;
|
||||
if (!emitSpread()) // ... OBJ? ARRAY INDEX
|
||||
if (!emitNumberOp(0)) // ... OBJ ITER ITER ARRAY INDEX
|
||||
return false;
|
||||
if (!emit1(JSOP_POP)) // ... OBJ? ARRAY
|
||||
if (!emitSpread()) // ... OBJ ITER ARRAY INDEX
|
||||
return false;
|
||||
if (!emitDestructuringLHSInBranch(member, flav)) // ... OBJ?
|
||||
if (!emit1(JSOP_POP)) // ... OBJ ITER ARRAY
|
||||
return false;
|
||||
|
||||
if (!isHead) {
|
||||
if (!ifThenElse.emitEnd())
|
||||
return false;
|
||||
MOZ_ASSERT(ifThenElse.popped() == 1);
|
||||
MOZ_ASSERT(ifThenElse.pushed() == 1);
|
||||
}
|
||||
needToPopIterator = false;
|
||||
MOZ_ASSERT(!member->pn_next);
|
||||
|
||||
if (!emitDestructuringLHS(member, flav)) // ... OBJ ITER
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(!hasNext);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -4867,110 +4858,100 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
IfThenElseEmitter ifThenElse(this);
|
||||
if (!ifThenElse.emitIfElse()) // ... OBJ? ITER RESULT
|
||||
return false;
|
||||
|
||||
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 (!emitInitializerInBranch(pndefault, subpattern)) // ... OBJ? ITER VALUE
|
||||
return false;
|
||||
} else {
|
||||
if (!isElision) {
|
||||
if (!emit1(JSOP_UNDEFINED)) // ... OBJ? ITER UNDEFINED
|
||||
IfThenElseEmitter ifAlreadyDone(this);
|
||||
if (!isHead) {
|
||||
// If this element is not the first element of the pattern,
|
||||
// iterator can already be completed.
|
||||
// ... OBJ ITER DONE
|
||||
if (hasNext) {
|
||||
if (!emit1(JSOP_DUP)) // ... OBJ ITER DONE DONE
|
||||
return false;
|
||||
if (!emit1(JSOP_NOP_DESTRUCTURING))
|
||||
}
|
||||
if (!ifAlreadyDone.emitIfElse()) // ... OBJ ITER ?DONE
|
||||
return false;
|
||||
|
||||
if (!emit1(JSOP_UNDEFINED)) // ... OBJ ITER ?DONE UNDEF
|
||||
return false;
|
||||
if (!emit1(JSOP_NOP_DESTRUCTURING)) // ... OBJ ITER ?DONE UNDEF
|
||||
return false;
|
||||
|
||||
if (!ifAlreadyDone.emitElse()) // ... OBJ ITER ?DONE
|
||||
return false;
|
||||
|
||||
if (hasNext) {
|
||||
if (!emit1(JSOP_POP)) // ... OBJ ITER
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!isElision) {
|
||||
if (!emitDestructuringLHSInBranch(subpattern, flav)) // ... OBJ? ITER
|
||||
return false;
|
||||
} else if (pndefault) {
|
||||
if (!emit1(JSOP_POP)) // ... OBJ? ITER
|
||||
|
||||
if (!emit1(JSOP_DUP)) // ... OBJ ITER ITER
|
||||
return false;
|
||||
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;
|
||||
|
||||
if (hasNext) {
|
||||
if (!emit1(JSOP_DUP)) // ... OBJ ITER RESULT DONE DONE
|
||||
return false;
|
||||
}
|
||||
|
||||
// Setup next element's result when the iterator is done.
|
||||
if (hasNextNonSpread) {
|
||||
if (!emit1(JSOP_UNDEFINED)) // ... OBJ? ITER RESULT
|
||||
return false;
|
||||
if (!emit1(JSOP_NOP_DESTRUCTURING))
|
||||
return false;
|
||||
if (!emit1(JSOP_TRUE)) // ... OBJ? ITER RESULT DONE?
|
||||
return false;
|
||||
} else if (hasNextSpread) {
|
||||
if (!emit1(JSOP_TRUE)) // ... OBJ? ITER DONE?
|
||||
IfThenElseEmitter ifDone(this);
|
||||
if (!ifDone.emitIfElse()) // ... OBJ ITER RESULT ?DONE
|
||||
return false;
|
||||
|
||||
if (hasNext) {
|
||||
if (!emit1(JSOP_SWAP)) // ... OBJ ITER ?DONE RESULT
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ifThenElse.emitElse()) // ... OBJ? ITER RESULT
|
||||
if (!emit1(JSOP_POP)) // ... OBJ ITER ?DONE
|
||||
return false;
|
||||
if (!emit1(JSOP_UNDEFINED)) // ... OBJ ITER ?DONE UNDEF
|
||||
return false;
|
||||
if (!emit1(JSOP_NOP_DESTRUCTURING)) // ... OBJ ITER ?DONE UNDEF
|
||||
return false;
|
||||
|
||||
if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // ... OBJ? ITER VALUE
|
||||
if (!ifDone.emitElse()) // ... OBJ ITER RESULT ?DONE
|
||||
return false;
|
||||
|
||||
if (hasNext) {
|
||||
if (!emit1(JSOP_SWAP)) // ... OBJ ITER ?DONE RESULT
|
||||
return false;
|
||||
}
|
||||
if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // ... OBJ ITER ?DONE VALUE
|
||||
return false;
|
||||
|
||||
if (!ifDone.emitEnd())
|
||||
return false;
|
||||
MOZ_ASSERT(ifDone.pushed() == 0);
|
||||
|
||||
if (!isHead) {
|
||||
if (!ifAlreadyDone.emitEnd())
|
||||
return false;
|
||||
MOZ_ASSERT(ifAlreadyDone.pushed() == 1);
|
||||
}
|
||||
|
||||
if (pndefault) {
|
||||
if (!emitDefault(pndefault, subpattern)) // ... OBJ? ITER VALUE
|
||||
if (!emitDefault(pndefault, subpattern)) // ... OBJ ITER ?DONE VALUE
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isElision) {
|
||||
if (!emitDestructuringLHSInBranch(subpattern, flav)) // ... OBJ? ITER
|
||||
if (!emitDestructuringLHS(subpattern, flav)) // ... OBJ ITER ?DONE
|
||||
return false;
|
||||
} else {
|
||||
if (!emit1(JSOP_POP)) // ... OBJ? ITER
|
||||
if (!emit1(JSOP_POP)) // ... OBJ ITER ?DONE
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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 (!ifThenElse.emitEnd())
|
||||
return false;
|
||||
if (hasNextNonSpread)
|
||||
MOZ_ASSERT(ifThenElse.pushed() == 1);
|
||||
else if (hasNextSpread)
|
||||
MOZ_ASSERT(ifThenElse.pushed() == 0);
|
||||
else
|
||||
MOZ_ASSERT(ifThenElse.popped() == 1);
|
||||
}
|
||||
|
||||
if (needToPopIterator) {
|
||||
if (!emit1(JSOP_POP)) // ... OBJ?
|
||||
return false;
|
||||
}
|
||||
if (!emit1(JSOP_POP)) // ... OBJ
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -6118,7 +6099,7 @@ BytecodeEmitter::emitSpread(bool allowSelfHosted)
|
|||
return false;
|
||||
if (!emit1(JSOP_DUP)) // ITER ARR I RESULT RESULT
|
||||
return false;
|
||||
if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // ITER ARR I RESULT DONE?
|
||||
if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // ITER ARR I RESULT DONE
|
||||
return false;
|
||||
|
||||
if (!emitBackwardJump(JSOP_IFEQ, top, &beq, &breakTarget)) // ITER ARR I RESULT
|
||||
|
|
@ -6307,7 +6288,7 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
|
|||
return false;
|
||||
if (!emit1(JSOP_DUP)) // ITER RESULT RESULT
|
||||
return false;
|
||||
if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // ITER RESULT DONE?
|
||||
if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // ITER RESULT DONE
|
||||
return false;
|
||||
|
||||
if (!emitBackwardJump(JSOP_IFEQ, top, &beq, &breakTarget))
|
||||
|
|
@ -6803,7 +6784,7 @@ BytecodeEmitter::emitComprehensionForOf(ParseNode* pn)
|
|||
return false;
|
||||
if (!emit1(JSOP_DUP)) // ITER RESULT RESULT
|
||||
return false;
|
||||
if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // ITER RESULT DONE?
|
||||
if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // ITER RESULT DONE
|
||||
return false;
|
||||
|
||||
JumpList beq;
|
||||
|
|
|
|||
|
|
@ -646,7 +646,6 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
// the stack and emits code to destructure a single lhs expression (either a
|
||||
// name or a compound []/{} expression).
|
||||
MOZ_MUST_USE bool emitDestructuringLHS(ParseNode* target, DestructuringFlavor flav);
|
||||
MOZ_MUST_USE bool emitDestructuringLHSInBranch(ParseNode* target, DestructuringFlavor flav);
|
||||
|
||||
// emitDestructuringOps assumes the to-be-destructured value has been
|
||||
// pushed on the stack and emits code to destructure each part of a [] or
|
||||
|
|
|
|||
25
js/src/tests/ecma_6/Destructuring/array-default-class.js
Normal file
25
js/src/tests/ecma_6/Destructuring/array-default-class.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
var BUGNUMBER = 1322314;
|
||||
var summary = "Function in computed property in class expression in array destructuring default";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
function* g([
|
||||
a = class E {
|
||||
[ (function() { return "foo"; })() ]() {
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
]) {
|
||||
yield a;
|
||||
}
|
||||
|
||||
let C = [...g([])][0];
|
||||
let x = new C();
|
||||
assertEq(x.foo(), 10);
|
||||
|
||||
C = [...g([undefined])][0];
|
||||
x = new C();
|
||||
assertEq(x.foo(), 10);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(0, 0);
|
||||
Loading…
Add table
Add a link
Reference in a new issue