Commit 3062af70 authored by neis's avatar neis Committed by Commit bot

Implement iterator finalization in array destructuring.

We must close the iterator whenever the destructuring didn't exhaust it, unless an iterator operation (eg. next) threw.  We do this by wrapping the iterator use in a try-catch-finally similar to the desugaring of for-of.

This is behind --harmony-iterator-close.

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

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

Cr-Commit-Position: refs/heads/master@{#34654}
parent 9bf7730d
This diff is collapsed.
......@@ -456,6 +456,9 @@ class ParserTraits {
MessageTemplate::Template message,
const AstRawString* arg, int pos);
void FinalizeIteratorUse(Variable* completion, Expression* condition,
Variable* iter, Block* iterator_use, Block* result);
Statement* FinalizeForOfStatement(ForOfStatement* loop, int pos);
// Reporting errors.
......@@ -696,6 +699,13 @@ class Parser : public ParserBase<ParserTraits> {
private:
friend class ParserTraits;
// Runtime encoding of different completion modes.
enum CompletionKind {
kNormalCompletion,
kThrowCompletion,
kAbruptCompletion
};
// Limit the allowed number of local variables in a function. The hard limit
// is that offsets computed by FullCodeGenerator::StackOperand and similar
// functions are ints, and they should not overflow. In addition, accessing
......
......@@ -409,16 +409,27 @@ void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* node) {
void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
Variable** temp_var) {
auto temp = *temp_var = CreateTempVar(current_value_);
block_->statements()->Add(parser_->BuildAssertIsCoercible(temp), zone());
DCHECK(block_->ignore_completion_value());
auto temp = *temp_var = CreateTempVar(current_value_);
auto iterator = CreateTempVar(parser_->GetIterator(
factory()->NewVariableProxy(temp), factory(), RelocInfo::kNoPosition));
auto done = CreateTempVar(
factory()->NewBooleanLiteral(false, RelocInfo::kNoPosition));
auto result = CreateTempVar();
auto v = CreateTempVar();
auto completion = CreateTempVar();
auto nopos = RelocInfo::kNoPosition;
// For the purpose of iterator finalization, we temporarily set block_ to a
// new block. In the main body of this function, we write to block_ (both
// explicitly and implicitly via recursion). At the end of the function, we
// wrap this new block in a try-finally statement, restore block_ to its
// original value, and add the try-finally statement to block_.
auto target = block_;
if (FLAG_harmony_iterator_close) {
block_ = factory()->NewBlock(nullptr, 8, true, nopos);
}
Spread* spread = nullptr;
for (Expression* value : *node->values()) {
......@@ -428,60 +439,101 @@ void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
}
PatternContext context = SetInitializerContextIfNeeded(value);
// if (!done) {
// done = true; // If .next, .done or .value throws, don't close.
// result = IteratorNext(iterator);
// v = (done = result.done) ? undefined : result.value;
// }
auto next_block =
factory()->NewBlock(nullptr, 2, true, RelocInfo::kNoPosition);
next_block->statements()->Add(factory()->NewExpressionStatement(
parser_->BuildIteratorNextResult(
factory()->NewVariableProxy(iterator),
result, RelocInfo::kNoPosition),
RelocInfo::kNoPosition),
zone());
auto assign_to_done = factory()->NewAssignment(
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());
Statement* if_statement;
{
auto next_block =
factory()->NewBlock(nullptr, 3, true, RelocInfo::kNoPosition);
next_block->statements()->Add(
factory()->NewExpressionStatement(
factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(done),
factory()->NewBooleanLiteral(true, nopos), nopos),
nopos),
zone());
auto if_statement = factory()->NewIfStatement(
factory()->NewUnaryOperation(Token::NOT,
factory()->NewVariableProxy(done),
RelocInfo::kNoPosition),
next_block, factory()->NewEmptyStatement(RelocInfo::kNoPosition),
RelocInfo::kNoPosition);
next_block->statements()->Add(
factory()->NewExpressionStatement(
parser_->BuildIteratorNextResult(
factory()->NewVariableProxy(iterator), result,
RelocInfo::kNoPosition),
RelocInfo::kNoPosition),
zone());
auto assign_to_done = factory()->NewAssignment(
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()->NewVariableProxy(done),
RelocInfo::kNoPosition),
next_block, factory()->NewEmptyStatement(RelocInfo::kNoPosition),
RelocInfo::kNoPosition);
}
block_->statements()->Add(if_statement, zone());
if (!(value->IsLiteral() && value->AsLiteral()->raw_value()->IsTheHole())) {
if (FLAG_harmony_iterator_close) {
// completion = kAbruptCompletion;
Expression* proxy = factory()->NewVariableProxy(completion);
Expression* assignment = factory()->NewAssignment(
Token::ASSIGN, proxy,
factory()->NewSmiLiteral(kAbruptCompletion, nopos), nopos);
block_->statements()->Add(
factory()->NewExpressionStatement(assignment, nopos), zone());
}
RecurseIntoSubpattern(value, factory()->NewVariableProxy(v));
if (FLAG_harmony_iterator_close) {
// completion = kNormalCompletion;
Expression* proxy = factory()->NewVariableProxy(completion);
Expression* assignment = factory()->NewAssignment(
Token::ASSIGN, proxy,
factory()->NewSmiLiteral(kNormalCompletion, nopos), nopos);
block_->statements()->Add(
factory()->NewExpressionStatement(assignment, nopos), zone());
}
}
set_context(context);
}
if (spread != nullptr) {
// array = [];
// A spread can only occur as the last component. It is not handled by
// RecurseIntoSubpattern above.
// let array = [];
// if (!done) %concat_iterable_to_array(array, iterator);
// done = true;
auto empty_exprs = new (zone()) ZoneList<Expression*>(0, zone());
auto array = CreateTempVar(factory()->NewArrayLiteral(
empty_exprs,
......@@ -506,9 +558,23 @@ void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
RelocInfo::kNoPosition);
block_->statements()->Add(if_statement, zone());
auto set_done = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(done),
factory()->NewBooleanLiteral(true, nopos), nopos);
block_->statements()->Add(
factory()->NewExpressionStatement(set_done, nopos), zone());
RecurseIntoSubpattern(spread->expression(),
factory()->NewVariableProxy(array));
}
if (FLAG_harmony_iterator_close) {
Expression* closing_condition = factory()->NewUnaryOperation(
Token::NOT, factory()->NewVariableProxy(done), nopos);
parser_->FinalizeIteratorUse(completion, closing_condition, iterator,
block_, target);
block_ = target;
}
}
......
......@@ -13,13 +13,13 @@ snippet: "
"
frame size: 16
parameter count: 1
bytecode array length: 345
bytecode array length: 344
bytecodes: [
B(StackCheck),
B(LdaZero),
B(Star), R(3),
B(LdaUndefined),
B(Star), R(4),
B(LdaZero),
B(Star), R(3),
B(Mov), R(context), R(11),
B(Mov), R(context), R(12),
B(CreateArrayLiteral), U8(0), U8(0), U8(3),
......@@ -46,7 +46,7 @@ bytecodes: [
B(Star), R(13),
B(LoadIC), R(13), U8(3), U8(9),
B(JumpIfToBooleanTrue), U8(28),
B(LdaSmi8), U8(1),
B(LdaSmi8), U8(2),
B(Star), R(3),
B(Ldar), R(2),
B(Star), R(13),
......@@ -72,10 +72,10 @@ bytecodes: [
B(PushContext), R(8),
B(Ldar), R(3),
B(Star), R(13),
B(LdaSmi8), U8(1),
B(LdaSmi8), U8(2),
B(TestEqualStrict), R(13),
B(JumpIfFalse), U8(6),
B(LdaSmi8), U8(2),
B(LdaSmi8), U8(1),
B(Star), R(3),
B(LdaContextSlot), R(context), U8(4),
B(Throw),
......@@ -96,8 +96,8 @@ bytecodes: [
B(Star), R(12),
B(LdaUndefined),
B(TestEqualStrict), R(12),
B(JumpIfToBooleanFalse), U8(4),
B(JumpConstant), U8(10),
B(LogicalNot),
B(JumpIfFalseConstant), U8(10),
B(Ldar), R(1),
B(Star), R(12),
B(LoadIC), R(12), U8(6), U8(13),
......@@ -109,7 +109,7 @@ bytecodes: [
B(Jump), U8(122),
B(Ldar), R(3),
B(Star), R(12),
B(LdaSmi8), U8(2),
B(LdaSmi8), U8(1),
B(TestEqualStrict), R(12),
B(JumpIfFalse), U8(77),
B(Ldar), R(5),
......@@ -183,7 +183,7 @@ constant pool: [
handlers: [
[10, 151, 157],
[13, 105, 107],
[248, 261, 263],
[247, 260, 262],
]
---
......@@ -193,15 +193,15 @@ snippet: "
"
frame size: 17
parameter count: 1
bytecode array length: 361
bytecode array length: 360
bytecodes: [
B(StackCheck),
B(LdaConstant), U8(0),
B(Star), R(7),
B(LdaZero),
B(Star), R(3),
B(LdaUndefined),
B(Star), R(4),
B(LdaZero),
B(Star), R(3),
B(Mov), R(context), R(12),
B(Mov), R(context), R(13),
B(Ldar), R(7),
......@@ -228,7 +228,7 @@ bytecodes: [
B(Star), R(14),
B(LoadIC), R(14), U8(3), U8(9),
B(JumpIfToBooleanTrue), U8(32),
B(LdaSmi8), U8(1),
B(LdaSmi8), U8(2),
B(Star), R(3),
B(Ldar), R(2),
B(Star), R(14),
......@@ -256,10 +256,10 @@ bytecodes: [
B(PushContext), R(9),
B(Ldar), R(3),
B(Star), R(14),
B(LdaSmi8), U8(1),
B(LdaSmi8), U8(2),
B(TestEqualStrict), R(14),
B(JumpIfFalse), U8(6),
B(LdaSmi8), U8(2),
B(LdaSmi8), U8(1),
B(Star), R(3),
B(LdaContextSlot), R(context), U8(4),
B(Throw),
......@@ -280,8 +280,8 @@ bytecodes: [
B(Star), R(13),
B(LdaUndefined),
B(TestEqualStrict), R(13),
B(JumpIfToBooleanFalse), U8(4),
B(JumpConstant), U8(10),
B(LogicalNot),
B(JumpIfFalseConstant), U8(10),
B(Ldar), R(1),
B(Star), R(13),
B(LoadIC), R(13), U8(6), U8(13),
......@@ -293,7 +293,7 @@ bytecodes: [
B(Jump), U8(122),
B(Ldar), R(3),
B(Star), R(13),
B(LdaSmi8), U8(2),
B(LdaSmi8), U8(1),
B(TestEqualStrict), R(13),
B(JumpIfFalse), U8(77),
B(Ldar), R(5),
......@@ -372,7 +372,7 @@ constant pool: [
handlers: [
[14, 157, 163],
[17, 111, 113],
[255, 268, 270],
[254, 267, 269],
]
---
......@@ -384,13 +384,13 @@ snippet: "
"
frame size: 16
parameter count: 1
bytecode array length: 367
bytecode array length: 366
bytecodes: [
B(StackCheck),
B(LdaZero),
B(Star), R(3),
B(LdaUndefined),
B(Star), R(4),
B(LdaZero),
B(Star), R(3),
B(Mov), R(context), R(11),
B(Mov), R(context), R(12),
B(CreateArrayLiteral), U8(0), U8(0), U8(3),
......@@ -417,7 +417,7 @@ bytecodes: [
B(Star), R(13),
B(LoadIC), R(13), U8(3), U8(9),
B(JumpIfToBooleanTrue), U8(50),
B(LdaSmi8), U8(1),
B(LdaSmi8), U8(2),
B(Star), R(3),
B(Ldar), R(2),
B(Star), R(13),
......@@ -454,10 +454,10 @@ bytecodes: [
B(PushContext), R(8),
B(Ldar), R(3),
B(Star), R(13),
B(LdaSmi8), U8(1),
B(LdaSmi8), U8(2),
B(TestEqualStrict), R(13),
B(JumpIfFalse), U8(6),
B(LdaSmi8), U8(2),
B(LdaSmi8), U8(1),
B(Star), R(3),
B(LdaContextSlot), R(context), U8(4),
B(Throw),
......@@ -478,8 +478,8 @@ bytecodes: [
B(Star), R(12),
B(LdaUndefined),
B(TestEqualStrict), R(12),
B(JumpIfToBooleanFalse), U8(4),
B(JumpConstant), U8(10),
B(LogicalNot),
B(JumpIfFalseConstant), U8(10),
B(Ldar), R(1),
B(Star), R(12),
B(LoadIC), R(12), U8(6), U8(13),
......@@ -491,7 +491,7 @@ bytecodes: [
B(Jump), U8(122),
B(Ldar), R(3),
B(Star), R(12),
B(LdaSmi8), U8(2),
B(LdaSmi8), U8(1),
B(TestEqualStrict), R(12),
B(JumpIfFalse), U8(77),
B(Ldar), R(5),
......@@ -565,7 +565,7 @@ constant pool: [
handlers: [
[10, 173, 179],
[13, 127, 129],
[270, 283, 285],
[269, 282, 284],
]
---
......@@ -575,16 +575,16 @@ snippet: "
"
frame size: 15
parameter count: 1
bytecode array length: 377
bytecode array length: 376
bytecodes: [
B(StackCheck),
B(CreateObjectLiteral), U8(0), U8(0), U8(5),
B(Star), R(8),
B(Star), R(6),
B(LdaZero),
B(Star), R(2),
B(LdaUndefined),
B(Star), R(3),
B(LdaZero),
B(Star), R(2),
B(Mov), R(context), R(10),
B(Mov), R(context), R(11),
B(CreateArrayLiteral), U8(1), U8(1), U8(3),
......@@ -611,7 +611,7 @@ bytecodes: [
B(Star), R(12),
B(LoadIC), R(12), U8(4), U8(9),
B(JumpIfToBooleanTrue), U8(42),
B(LdaSmi8), U8(1),
B(LdaSmi8), U8(2),
B(Star), R(2),
B(Ldar), R(6),
B(Star), R(12),
......@@ -642,10 +642,10 @@ bytecodes: [
B(PushContext), R(7),
B(Ldar), R(2),
B(Star), R(12),
B(LdaSmi8), U8(1),
B(LdaSmi8), U8(2),
B(TestEqualStrict), R(12),
B(JumpIfFalse), U8(6),
B(LdaSmi8), U8(2),
B(LdaSmi8), U8(1),
B(Star), R(2),
B(LdaContextSlot), R(context), U8(4),
B(Throw),
......@@ -666,8 +666,8 @@ bytecodes: [
B(Star), R(11),
B(LdaUndefined),
B(TestEqualStrict), R(11),
B(JumpIfToBooleanFalse), U8(4),
B(JumpConstant), U8(12),
B(LogicalNot),
B(JumpIfFalseConstant), U8(12),
B(Ldar), R(0),
B(Star), R(11),
B(LoadIC), R(11), U8(8), U8(17),
......@@ -679,7 +679,7 @@ bytecodes: [
B(Jump), U8(122),
B(Ldar), R(2),
B(Star), R(11),
B(LdaSmi8), U8(2),
B(LdaSmi8), U8(1),
B(TestEqualStrict), R(11),
B(JumpIfFalse), U8(77),
B(Ldar), R(4),
......@@ -760,6 +760,6 @@ constant pool: [
handlers: [
[18, 173, 179],
[21, 127, 129],
[271, 284, 286],
[270, 283, 285],
]
This diff is collapsed.
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