Chromium Code Reviews| Index: src/parsing/parser.cc |
| diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc |
| index dcb973da78ebc39f91b7f157621f37be41c66fad..8d9e4c72005eb856db68fc8ab70e2cca7f2f6145 100644 |
| --- a/src/parsing/parser.cc |
| +++ b/src/parsing/parser.cc |
| @@ -553,6 +553,7 @@ Parser::Parser(ParseInfo* info) |
| set_allow_harmony_trailing_commas(FLAG_harmony_trailing_commas); |
| set_allow_harmony_class_fields(FLAG_harmony_class_fields); |
| set_allow_harmony_object_rest_spread(FLAG_harmony_object_rest_spread); |
| + set_allow_harmony_async_iteration(FLAG_harmony_async_iteration); |
| for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; |
| ++feature) { |
| use_counts_[feature] = 0; |
| @@ -1757,7 +1758,8 @@ Statement* Parser::RewriteTryStatement(Block* try_block, Block* catch_block, |
| // !%_IsJSReceiver(result = iterator.next()) && |
| // %ThrowIteratorResultNotAnObject(result) |
|
neis
2017/01/20 14:38:15
Comment needs an update.
|
| Expression* Parser::BuildIteratorNextResult(Expression* iterator, |
| - Variable* result, int pos) { |
| + Variable* result, IteratorType type, |
| + int pos) { |
| Expression* next_literal = factory()->NewStringLiteral( |
| ast_value_factory()->next_string(), kNoSourcePosition); |
| Expression* next_property = |
| @@ -1766,6 +1768,9 @@ Expression* Parser::BuildIteratorNextResult(Expression* iterator, |
| new (zone()) ZoneList<Expression*>(0, zone()); |
| Expression* next_call = |
| factory()->NewCall(next_property, next_arguments, pos); |
| + if (type == IteratorType::kAsync) { |
| + next_call = RewriteAwaitExpression(next_call, pos); |
| + } |
| Expression* result_proxy = factory()->NewVariableProxy(result); |
| Expression* left = |
| factory()->NewAssignment(Token::ASSIGN, result_proxy, next_call, pos); |
| @@ -1977,7 +1982,8 @@ Statement* Parser::InitializeForOfStatement(ForOfStatement* for_of, |
| { |
| assign_iterator = factory()->NewAssignment( |
| Token::ASSIGN, factory()->NewVariableProxy(iterator), |
| - factory()->NewGetIterator(iterable, iterable->position()), |
| + factory()->NewGetIterator(iterable, GetIterator::kNormal, |
| + iterable->position()), |
| iterable->position()); |
| } |
| @@ -1986,8 +1992,8 @@ Statement* Parser::InitializeForOfStatement(ForOfStatement* for_of, |
| Expression* next_result; |
| { |
| Expression* iterator_proxy = factory()->NewVariableProxy(iterator); |
| - next_result = |
| - BuildIteratorNextResult(iterator_proxy, result, next_result_pos); |
| + next_result = BuildIteratorNextResult( |
| + iterator_proxy, result, IteratorType::kNormal, next_result_pos); |
| } |
| // result.done |
| @@ -2075,7 +2081,139 @@ Statement* Parser::InitializeForOfStatement(ForOfStatement* for_of, |
| for_of->Initialize(body, iterator, assign_iterator, next_result, result_done, |
| assign_each); |
| - return finalize ? FinalizeForOfStatement(for_of, completion, nopos) : for_of; |
| + return finalize ? FinalizeForOfStatement(for_of, completion, |
| + IteratorType::kNormal, nopos) |
| + : for_of; |
| +} |
| + |
| +Statement* Parser::InitializeForAwaitOfStatement(ForEachStatement* for_each, |
|
neis
2017/01/20 14:38:15
Can't you just parameterize the existing Initializ
caitp
2017/01/20 17:05:34
It's doable, but harder to read IMO
. Whatever peo
caitp
2017/01/20 20:17:19
Eh, it actually gets pretty ugly to try to do it t
|
| + Expression* each, |
| + Expression* iterable, |
| + Statement* body, bool finalize, |
| + int next_result_pos) { |
| + // Create the auxiliary expressions needed for iterating over the iterable, |
| + // and initialize the given ForOfStatement with them. |
| + // If finalize is true, also instrument the loop with code that performs the |
| + // proper ES6 iterator finalization. In that case, the result is not |
| + // immediately a ForOfStatement. |
| + |
| + ForOfStatement* for_of = for_each->AsForOfStatement(); |
| + DCHECK_NOT_NULL(for_of); |
| + |
| + const int nopos = kNoSourcePosition; |
| + auto avfactory = ast_value_factory(); |
| + |
| + Variable* iterator = NewTemporary(avfactory->dot_iterator_string()); |
| + Variable* result = NewTemporary(avfactory->dot_result_string()); |
| + Variable* completion = NewTemporary(avfactory->empty_string()); |
| + |
| + // iterator = GetIterator(iterable) |
|
neis
2017/01/20 14:38:16
Comment needs an update.
|
| + Expression* assign_iterator; |
| + { |
| + assign_iterator = factory()->NewAssignment( |
| + Token::ASSIGN, factory()->NewVariableProxy(iterator), |
| + factory()->NewGetIterator(iterable, GetIterator::kAsync, |
| + iterable->position()), |
| + iterable->position()); |
| + } |
| + |
| + // !%_IsJSReceiver(result = iterator.next()) && |
| + // %ThrowIteratorResultNotAnObject(result) |
|
neis
2017/01/20 14:38:15
Comment needs an update.
|
| + Expression* next_result; |
| + { |
| + Expression* iterator_proxy = factory()->NewVariableProxy(iterator); |
| + next_result = BuildIteratorNextResult( |
| + iterator_proxy, result, IteratorType::kAsync, next_result_pos); |
| + } |
| + |
| + // result.done |
| + Expression* result_done; |
| + { |
| + Expression* done_literal = factory()->NewStringLiteral( |
| + ast_value_factory()->done_string(), kNoSourcePosition); |
| + Expression* result_proxy = factory()->NewVariableProxy(result); |
| + result_done = |
| + factory()->NewProperty(result_proxy, done_literal, kNoSourcePosition); |
| + } |
| + |
| + // result.value |
| + Expression* result_value; |
| + { |
| + Expression* value_literal = |
| + factory()->NewStringLiteral(avfactory->value_string(), nopos); |
| + Expression* result_proxy = factory()->NewVariableProxy(result); |
| + result_value = factory()->NewProperty(result_proxy, value_literal, nopos); |
| + } |
| + |
| + // {{completion = kAbruptCompletion;}} |
| + Statement* set_completion_abrupt; |
| + if (finalize) { |
| + Expression* proxy = factory()->NewVariableProxy(completion); |
| + Expression* assignment = factory()->NewAssignment( |
| + Token::ASSIGN, proxy, |
| + factory()->NewSmiLiteral(Parser::kAbruptCompletion, nopos), nopos); |
| + |
| + Block* block = factory()->NewBlock(nullptr, 1, true, nopos); |
| + block->statements()->Add( |
| + factory()->NewExpressionStatement(assignment, nopos), zone()); |
| + set_completion_abrupt = block; |
| + } |
| + |
| + // do { let tmp = #result_value; #set_completion_abrupt; tmp } |
| + // Expression* result_value (gets overwritten) |
| + if (finalize) { |
| + Variable* var_tmp = NewTemporary(avfactory->empty_string()); |
| + Expression* tmp = factory()->NewVariableProxy(var_tmp); |
| + Expression* assignment = |
| + factory()->NewAssignment(Token::ASSIGN, tmp, result_value, nopos); |
| + |
| + Block* block = factory()->NewBlock(nullptr, 2, false, nopos); |
| + block->statements()->Add( |
| + factory()->NewExpressionStatement(assignment, nopos), zone()); |
| + block->statements()->Add(set_completion_abrupt, zone()); |
| + |
| + result_value = factory()->NewDoExpression(block, var_tmp, nopos); |
| + } |
| + |
| + // each = #result_value; |
| + Expression* assign_each; |
| + { |
| + assign_each = |
| + factory()->NewAssignment(Token::ASSIGN, each, result_value, nopos); |
| + if (each->IsArrayLiteral() || each->IsObjectLiteral()) { |
| + assign_each = PatternRewriter::RewriteDestructuringAssignment( |
| + this, assign_each->AsAssignment(), scope()); |
| + } |
| + } |
| + |
| + // {{completion = kNormalCompletion;}} |
| + Statement* set_completion_normal; |
| + if (finalize) { |
| + Expression* proxy = factory()->NewVariableProxy(completion); |
| + Expression* assignment = factory()->NewAssignment( |
| + Token::ASSIGN, proxy, |
| + factory()->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos); |
| + |
| + Block* block = factory()->NewBlock(nullptr, 1, true, nopos); |
| + block->statements()->Add( |
| + factory()->NewExpressionStatement(assignment, nopos), zone()); |
| + set_completion_normal = block; |
| + } |
| + |
| + // { #loop-body; #set_completion_normal } |
| + // Statement* body (gets overwritten) |
| + if (finalize) { |
| + Block* block = factory()->NewBlock(nullptr, 2, false, nopos); |
| + block->statements()->Add(body, zone()); |
| + block->statements()->Add(set_completion_normal, zone()); |
| + body = block; |
| + } |
| + |
| + for_of->Initialize(body, iterator, assign_iterator, next_result, result_done, |
| + assign_each); |
| + return finalize ? FinalizeForOfStatement(for_of, completion, |
| + IteratorType::kAsync, nopos) |
| + : for_of; |
| } |
| Statement* Parser::DesugarLexicalBindingsInForStatement( |
| @@ -2740,6 +2878,7 @@ Parser::LazyParsingResult Parser::SkipFunction( |
| SET_ALLOW(harmony_trailing_commas); |
| SET_ALLOW(harmony_class_fields); |
| SET_ALLOW(harmony_object_rest_spread); |
| + SET_ALLOW(harmony_async_iteration); |
| #undef SET_ALLOW |
| } |
| // Aborting inner function preparsing would leave scopes in an inconsistent |
| @@ -4345,7 +4484,8 @@ Expression* Parser::RewriteYieldStar(Expression* generator, |
| Variable* var_iterator = NewTemporary(ast_value_factory()->empty_string()); |
| Statement* get_iterator; |
| { |
| - Expression* iterator = factory()->NewGetIterator(iterable, nopos); |
| + Expression* iterator = |
| + factory()->NewGetIterator(iterable, GetIterator::kNormal, nopos); |
| Expression* iterator_proxy = factory()->NewVariableProxy(var_iterator); |
| Expression* assignment = factory()->NewAssignment( |
| Token::ASSIGN, iterator_proxy, iterator, nopos); |
| @@ -4427,7 +4567,8 @@ Expression* Parser::RewriteYieldStar(Expression* generator, |
| Block* then = factory()->NewBlock(nullptr, 4 + 1, false, nopos); |
| BuildIteratorCloseForCompletion( |
| scope(), then->statements(), var_iterator, |
| - factory()->NewSmiLiteral(Parser::kNormalCompletion, nopos)); |
| + factory()->NewSmiLiteral(Parser::kNormalCompletion, nopos), |
| + IteratorType::kNormal); |
| then->statements()->Add(throw_call, zone()); |
| check_throw = factory()->NewIfStatement( |
| condition, then, factory()->NewEmptyStatement(nopos), nopos); |
| @@ -4613,7 +4754,8 @@ Expression* Parser::RewriteYieldStar(Expression* generator, |
| case_next->Add(factory()->NewBreakStatement(switch_mode, nopos), zone()); |
| auto case_return = new (zone()) ZoneList<Statement*>(5, zone()); |
| - BuildIteratorClose(case_return, var_iterator, var_input, var_output); |
| + BuildIteratorClose(case_return, var_iterator, var_input, var_output, |
| + IteratorType::kNormal); |
| case_return->Add(factory()->NewBreakStatement(switch_mode, nopos), zone()); |
| auto case_throw = new (zone()) ZoneList<Statement*>(5, zone()); |
| @@ -4697,7 +4839,7 @@ Statement* Parser::CheckCallable(Variable* var, Expression* error, int pos) { |
| void Parser::BuildIteratorClose(ZoneList<Statement*>* statements, |
| Variable* iterator, Variable* input, |
| - Variable* var_output) { |
| + Variable* var_output, IteratorType type) { |
| // |
|
neis
2017/01/20 14:38:15
This function is only used in RewriteYieldStar and
caitp
2017/01/20 17:05:34
That may be a bug then. You're supposed to Iterato
|
| // This function adds four statements to [statements], corresponding to the |
| // following code: |
| @@ -4706,7 +4848,13 @@ void Parser::BuildIteratorClose(ZoneList<Statement*>* statements, |
| // if (IS_NULL_OR_UNDEFINED(iteratorReturn) { |
| // return {value: input, done: true}; |
| // } |
| - // output = %_Call(iteratorReturn, iterator, input); |
| + // |
| + // [if (IteratorType == kAsync)] |
| + // output = Await(%_Call(iteratorReturn, iterator, input)); |
| + // [else] |
| + // output = %_Call(iteratorReturn, iterator, input); |
| + // [endif] |
| + // |
| // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output); |
| // |
| @@ -4755,6 +4903,10 @@ void Parser::BuildIteratorClose(ZoneList<Statement*>* statements, |
| Expression* call = |
| factory()->NewCallRuntime(Runtime::kInlineCall, args, nopos); |
| + if (type == IteratorType::kAsync) { |
| + call = RewriteAwaitExpression(call, nopos); |
| + } |
| + |
| Expression* output_proxy = factory()->NewVariableProxy(var_output); |
| Expression* assignment = |
| factory()->NewAssignment(Token::ASSIGN, output_proxy, call, nopos); |
| @@ -4794,7 +4946,8 @@ void Parser::BuildIteratorClose(ZoneList<Statement*>* statements, |
| void Parser::FinalizeIteratorUse(Scope* use_scope, Variable* completion, |
| Expression* condition, Variable* iter, |
| - Block* iterator_use, Block* target) { |
| + Block* iterator_use, Block* target, |
| + IteratorType type) { |
| // |
| // This function adds two statements to [target], corresponding to the |
| // following code: |
| @@ -4850,8 +5003,8 @@ void Parser::FinalizeIteratorUse(Scope* use_scope, Variable* completion, |
| { |
| Block* block = factory()->NewBlock(nullptr, 2, true, nopos); |
| Expression* proxy = factory()->NewVariableProxy(completion); |
| - BuildIteratorCloseForCompletion(use_scope, block->statements(), iter, |
| - proxy); |
| + BuildIteratorCloseForCompletion(use_scope, block->statements(), iter, proxy, |
| + type); |
| DCHECK(block->statements()->length() == 2); |
| maybe_close = factory()->NewBlock(nullptr, 1, true, nopos); |
| @@ -4910,7 +5063,8 @@ void Parser::FinalizeIteratorUse(Scope* use_scope, Variable* completion, |
| void Parser::BuildIteratorCloseForCompletion(Scope* scope, |
| ZoneList<Statement*>* statements, |
| Variable* iterator, |
| - Expression* completion) { |
| + Expression* completion, |
| + IteratorType type) { |
| // |
| // This function adds two statements to [statements], corresponding to the |
| // following code: |
| @@ -4968,6 +5122,10 @@ void Parser::BuildIteratorCloseForCompletion(Scope* scope, |
| Expression* call = |
| factory()->NewCallRuntime(Runtime::kInlineCall, args, nopos); |
| + if (type == IteratorType::kAsync) { |
| + call = RewriteAwaitExpression(call, nopos); |
| + } |
| + |
| Block* try_block = factory()->NewBlock(nullptr, 1, false, nopos); |
| try_block->statements()->Add(factory()->NewExpressionStatement(call, nopos), |
| zone()); |
| @@ -5067,7 +5225,8 @@ void Parser::BuildIteratorCloseForCompletion(Scope* scope, |
| } |
| Statement* Parser::FinalizeForOfStatement(ForOfStatement* loop, |
| - Variable* var_completion, int pos) { |
| + Variable* var_completion, |
| + IteratorType type, int pos) { |
| // |
| // This function replaces the loop with the following wrapping: |
| // |
| @@ -5111,7 +5270,7 @@ Statement* Parser::FinalizeForOfStatement(ForOfStatement* loop, |
| DCHECK_EQ(scope()->scope_type(), BLOCK_SCOPE); |
| FinalizeIteratorUse(loop_scope, var_completion, closing_condition, |
| - loop->iterator(), try_block, final_loop); |
| + loop->iterator(), try_block, final_loop, type); |
| } |
| return final_loop; |