Commit cd6a5a45 authored by neis's avatar neis Committed by Commit bot

Fix corner case in iterator finalization for array destructuring.

The comment was correct but the code didn't match :(
Must not close when .value throws.

R=adamk@chromium.org
BUG=v8:3566
LOG=n

Review URL: https://codereview.chromium.org/1778333002

Cr-Commit-Position: refs/heads/master@{#34691}
parent 57a1897c
...@@ -443,13 +443,54 @@ void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node, ...@@ -443,13 +443,54 @@ void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
// if (!done) { // if (!done) {
// done = true; // If .next, .done or .value throws, don't close. // done = true; // If .next, .done or .value throws, don't close.
// result = IteratorNext(iterator); // result = IteratorNext(iterator);
// v = (done = result.done) ? undefined : result.value; // if (result.done) {
// v = undefined;
// } else {
// v = result.value;
// done = false;
// }
// } // }
Statement* if_statement; Statement* if_not_done;
{ {
auto result_done = factory()->NewProperty(
factory()->NewVariableProxy(result),
factory()->NewStringLiteral(ast_value_factory()->done_string(),
RelocInfo::kNoPosition),
RelocInfo::kNoPosition);
auto assign_undefined = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(v),
factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
RelocInfo::kNoPosition);
auto assign_value = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(v),
factory()->NewProperty(
factory()->NewVariableProxy(result),
factory()->NewStringLiteral(ast_value_factory()->value_string(),
RelocInfo::kNoPosition),
RelocInfo::kNoPosition),
RelocInfo::kNoPosition);
auto unset_done = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(done),
factory()->NewBooleanLiteral(false, RelocInfo::kNoPosition),
RelocInfo::kNoPosition);
auto inner_else =
factory()->NewBlock(nullptr, 2, true, RelocInfo::kNoPosition);
inner_else->statements()->Add(
factory()->NewExpressionStatement(assign_value, nopos), zone());
inner_else->statements()->Add(
factory()->NewExpressionStatement(unset_done, nopos), zone());
auto inner_if = factory()->NewIfStatement(
result_done,
factory()->NewExpressionStatement(assign_undefined, nopos),
inner_else, nopos);
auto next_block = auto next_block =
factory()->NewBlock(nullptr, 3, true, RelocInfo::kNoPosition); factory()->NewBlock(nullptr, 3, true, RelocInfo::kNoPosition);
next_block->statements()->Add( next_block->statements()->Add(
factory()->NewExpressionStatement( factory()->NewExpressionStatement(
factory()->NewAssignment( factory()->NewAssignment(
...@@ -457,7 +498,6 @@ void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node, ...@@ -457,7 +498,6 @@ void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
factory()->NewBooleanLiteral(true, nopos), nopos), factory()->NewBooleanLiteral(true, nopos), nopos),
nopos), nopos),
zone()); zone());
next_block->statements()->Add( next_block->statements()->Add(
factory()->NewExpressionStatement( factory()->NewExpressionStatement(
parser_->BuildIteratorNextResult( parser_->BuildIteratorNextResult(
...@@ -465,40 +505,16 @@ void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node, ...@@ -465,40 +505,16 @@ void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
RelocInfo::kNoPosition), RelocInfo::kNoPosition),
RelocInfo::kNoPosition), RelocInfo::kNoPosition),
zone()); zone());
next_block->statements()->Add(inner_if, zone());
auto assign_to_done = factory()->NewAssignment( if_not_done = factory()->NewIfStatement(
Token::ASSIGN, factory()->NewVariableProxy(done),
factory()->NewProperty(
factory()->NewVariableProxy(result),
factory()->NewStringLiteral(ast_value_factory()->done_string(),
RelocInfo::kNoPosition),
RelocInfo::kNoPosition),
RelocInfo::kNoPosition);
auto next_value = factory()->NewConditional(
assign_to_done,
factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
factory()->NewProperty(
factory()->NewVariableProxy(result),
factory()->NewStringLiteral(ast_value_factory()->value_string(),
RelocInfo::kNoPosition),
RelocInfo::kNoPosition),
RelocInfo::kNoPosition);
next_block->statements()->Add(
factory()->NewExpressionStatement(
factory()->NewAssignment(Token::ASSIGN,
factory()->NewVariableProxy(v),
next_value, RelocInfo::kNoPosition),
RelocInfo::kNoPosition),
zone());
if_statement = factory()->NewIfStatement(
factory()->NewUnaryOperation(Token::NOT, factory()->NewUnaryOperation(Token::NOT,
factory()->NewVariableProxy(done), factory()->NewVariableProxy(done),
RelocInfo::kNoPosition), RelocInfo::kNoPosition),
next_block, factory()->NewEmptyStatement(RelocInfo::kNoPosition), next_block, factory()->NewEmptyStatement(RelocInfo::kNoPosition),
RelocInfo::kNoPosition); RelocInfo::kNoPosition);
} }
block_->statements()->Add(if_statement, zone()); block_->statements()->Add(if_not_done, zone());
if (!(value->IsLiteral() && value->AsLiteral()->raw_value()->IsTheHole())) { if (!(value->IsLiteral() && value->AsLiteral()->raw_value()->IsTheHole())) {
if (FLAG_harmony_iterator_close) { if (FLAG_harmony_iterator_close) {
......
...@@ -1010,6 +1010,94 @@ function* g() { yield 42; return 88 }; ...@@ -1010,6 +1010,94 @@ function* g() { yield 42; return 88 };
} }
// Value throws.
{
g.prototype.next = () => ({get value() {throw 666}});
g.prototype.return = () => { assertUnreachable() };
assertThrowsEquals(() => {
for (var x of g()) {}
}, 666);
assertThrowsEquals(() => {
for (let x of g()) {}
}, 666);
assertThrowsEquals(() => {
for (const x of g()) {}
}, 666);
assertThrowsEquals(() => {
for (x of g()) {}
}, 666);
assertThrowsEquals(() => {
var [x] = g();
}, 666);
assertThrowsEquals(() => {
let [x] = g();
}, 666);
assertThrowsEquals(() => {
const [x] = g();
}, 666);
assertThrowsEquals(() => {
[x] = g();
}, 666);
assertThrowsEquals(() => {
(([x]) => x)(g());
}, 666);
}
// Done throws.
{
g.prototype.next = () => ({get done() {throw 666}});
g.prototype.return = () => { assertUnreachable() };
assertThrowsEquals(() => {
for (var x of g()) {}
}, 666);
assertThrowsEquals(() => {
for (let x of g()) {}
}, 666);
assertThrowsEquals(() => {
for (const x of g()) {}
}, 666);
assertThrowsEquals(() => {
for (x of g()) {}
}, 666);
assertThrowsEquals(() => {
var [x] = g();
}, 666);
assertThrowsEquals(() => {
let [x] = g();
}, 666);
assertThrowsEquals(() => {
const [x] = g();
}, 666);
assertThrowsEquals(() => {
[x] = g();
}, 666);
assertThrowsEquals(() => {
(([x]) => x)(g());
}, 666);
}
// Nested loops. // Nested loops.
{ {
function* g1() { yield 1; yield 2; throw 3; } function* g1() { yield 1; yield 2; throw 3; }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment