Chromium Code Reviews| Index: src/parsing/parser.cc |
| diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc |
| index ed63b543b46cae98d24debebc9334fcfa1f6f6ec..ec57f487dfffa77e0e1e8306606e03c01753d873 100644 |
| --- a/src/parsing/parser.cc |
| +++ b/src/parsing/parser.cc |
| @@ -2681,7 +2681,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) { |
| } |
| ExpectSemicolon(CHECK_OK); |
| - if (is_generator()) { |
| + if (is_generator() || is_async_function()) { |
| return_value = BuildIteratorResult(return_value, true); |
| } |
| @@ -4026,6 +4026,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
| ? peek_position() : function_token_pos; |
| bool is_generator = IsGeneratorFunction(kind); |
| + bool is_async = IsAsyncFunction(kind); |
| // Anonymous functions were passed either the empty symbol or a null |
| // handle as the function name. Remember if we were passed a non-empty |
| @@ -4057,7 +4058,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
| scope_->SetScopeName(function_name); |
| ExpressionClassifier formals_classifier(this, &duplicate_finder); |
| - if (is_generator) { |
| + if (is_generator || is_async) { |
| // For generators, allocating variables in contexts is currently a win |
| // because it minimizes the work needed to suspend and resume an |
| // activation. The machine code produced for generators (by full-codegen) |
| @@ -4067,9 +4068,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
| // Calling a generator returns a generator object. That object is stored |
| // in a temporary variable, a definition that is used by "yield" |
| // expressions. This also marks the FunctionState as a generator. |
| - Variable* temp = scope_->NewTemporary( |
| - ast_value_factory()->dot_generator_object_string()); |
| - function_state.set_generator_object_variable(temp); |
| + if (is_generator) { |
| + Variable* temp = scope_->NewTemporary( |
| + ast_value_factory()->dot_generator_object_string()); |
| + function_state.set_generator_object_variable(temp); |
| + } |
| } |
| Expect(Token::LPAREN, CHECK_OK); |
| @@ -4489,6 +4492,24 @@ Block* Parser::BuildParameterInitializationBlock( |
| return init_block; |
| } |
| +Expression* Parser::EmitCreateJSGeneratorObject(int pos) { |
| + DCHECK_NOT_NULL(function_state_->generator_object_variable()); |
|
caitp (gmail)
2016/04/26 22:01:30
these don't really add much, but since they're use
|
| + ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone()); |
| + args->Add(factory()->NewThisFunction(pos), zone()); |
| + args->Add(ThisExpression(scope_, factory(), RelocInfo::kNoPosition), zone()); |
| + return factory()->NewCallRuntime(Runtime::kCreateJSGeneratorObject, args, |
| + pos); |
| +} |
| + |
| +Expression* Parser::EmitYieldJSGeneratorObject(Expression* allocation) { |
| + VariableProxy* init_proxy = |
| + factory()->NewVariableProxy(function_state_->generator_object_variable()); |
| + Assignment* assignment = factory()->NewAssignment( |
| + Token::INIT, init_proxy, allocation, RelocInfo::kNoPosition); |
| + VariableProxy* get_proxy = |
| + factory()->NewVariableProxy(function_state_->generator_object_variable()); |
| + return factory()->NewYield(get_proxy, assignment, RelocInfo::kNoPosition); |
| +} |
| ZoneList<Statement*>* Parser::ParseEagerFunctionBody( |
| const AstRawString* function_name, int pos, |
| @@ -4542,22 +4563,9 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody( |
| factory()->NewBlock(nullptr, 3, false, RelocInfo::kNoPosition); |
| { |
| - ZoneList<Expression*>* arguments = |
| - new (zone()) ZoneList<Expression*>(2, zone()); |
| - arguments->Add(factory()->NewThisFunction(pos), zone()); |
| - arguments->Add( |
| - ThisExpression(scope_, factory(), RelocInfo::kNoPosition), zone()); |
| - CallRuntime* allocation = factory()->NewCallRuntime( |
| - Runtime::kCreateJSGeneratorObject, arguments, pos); |
| - |
| - VariableProxy* init_proxy = factory()->NewVariableProxy( |
| - function_state_->generator_object_variable()); |
| - Assignment* assignment = factory()->NewAssignment( |
| - Token::INIT, init_proxy, allocation, RelocInfo::kNoPosition); |
| - VariableProxy* get_proxy = factory()->NewVariableProxy( |
| - function_state_->generator_object_variable()); |
| - Yield* yield = |
| - factory()->NewYield(get_proxy, assignment, RelocInfo::kNoPosition); |
| + Expression* allocation = EmitCreateJSGeneratorObject(pos); |
| + Expression* yield = EmitYieldJSGeneratorObject(allocation); |
| + |
| try_block->statements()->Add( |
| factory()->NewExpressionStatement(yield, RelocInfo::kNoPosition), |
| zone()); |
| @@ -4585,6 +4593,77 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody( |
| body->Add(factory()->NewTryFinallyStatement(try_block, finally_block, |
| RelocInfo::kNoPosition), |
| zone()); |
| + } else if (IsAsyncFunction(kind)) { |
| + Expression* inner_generator = nullptr; |
| + { |
| + Scope* generator_scope = |
| + NewScope(inner_scope, FUNCTION_SCOPE, kAsyncFunction); |
| + |
| + // For generators, allocating variables in contexts is currently a win |
| + // because it minimizes the work needed to suspend and resume an |
| + // activation. The machine code produced for generators (by |
| + // full-codegen) |
| + // relies on this forced context allocation, but not in an essential |
| + // way. |
| + generator_scope->ForceContextAllocation(); |
| + |
| + FunctionState generator_state_(&function_state_, &scope_, |
| + generator_scope, kAsyncFunction, |
| + factory()); |
| + generator_scope->set_start_position(pos); |
| + ZoneList<Statement*>* generator_body = |
| + new (zone()) ZoneList<Statement*>(8, zone()); |
| + |
| + // Calling a generator returns a generator object. That object is |
| + // stored |
| + // in a temporary variable, a definition that is used by "yield" |
| + // expressions. This also marks the FunctionState as a generator. |
| + Variable* temp = scope_->NewTemporary( |
| + ast_value_factory()->dot_generator_object_string()); |
| + generator_state_.set_generator_object_variable(temp); |
| + |
| + Expression* allocation = EmitCreateJSGeneratorObject(pos); |
| + Expression* yield = EmitYieldJSGeneratorObject(allocation); |
| + |
| + generator_body->Add( |
| + factory()->NewExpressionStatement(yield, RelocInfo::kNoPosition), |
| + zone()); |
| + |
| + ParseStatementList(generator_body, Token::RBRACE, CHECK_OK); |
| + |
| + Statement* final_return = factory()->NewReturnStatement( |
| + BuildIteratorResult(nullptr, true), RelocInfo::kNoPosition); |
| + generator_body->Add(final_return, zone()); |
| + generator_scope->set_end_position(scanner()->location().end_pos); |
| + |
| + inner_generator = factory()->NewFunctionLiteral( |
| + function_name, generator_scope, generator_body, |
| + generator_state_.materialized_literal_count(), |
| + generator_state_.expected_property_count(), 0, |
| + FunctionLiteral::kNoDuplicateParameters, |
| + FunctionLiteral::kAnonymousExpression, |
| + FunctionLiteral::kShouldEagerCompile, kGeneratorFunction, |
| + RelocInfo::kNoPosition); |
| + } |
| + |
| + ZoneList<Expression*>* call_generator_args = |
| + new (zone()) ZoneList<Expression*>(2, zone()); |
| + call_generator_args->Add(inner_generator, zone()); |
| + call_generator_args->Add( |
| + ThisExpression(inner_scope, factory(), RelocInfo::kNoPosition), |
| + zone()); |
| + Expression* call_generator = factory()->NewCallRuntime( |
| + Runtime::kInlineCall, call_generator_args, RelocInfo::kNoPosition); |
| + |
| + ZoneList<Expression*>* async_function_start_args = |
| + new (zone()) ZoneList<Expression*>(1, zone()); |
| + async_function_start_args->Add(call_generator, zone()); |
| + Expression* async_function_start = factory()->NewCallRuntime( |
| + Context::ASYNC_FUNCTION_START_INDEX, async_function_start_args, |
| + RelocInfo::kNoPosition); |
| + body->Add(factory()->NewReturnStatement(async_function_start, |
| + RelocInfo::kNoPosition), |
| + zone()); |
| } else { |
| ParseStatementList(body, Token::RBRACE, CHECK_OK); |
| } |
| @@ -4606,6 +4685,39 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody( |
| DCHECK_EQ(body, inner_block->statements()); |
| SetLanguageMode(scope_, inner_scope->language_mode()); |
| Block* init_block = BuildParameterInitializationBlock(parameters, CHECK_OK); |
| + |
| + if (IsAsyncFunction(kind)) { |
| + // If an exception occurs during parameter initialization, return a |
| + // rejected promise. |
| + // |
| + // try { <init_block> } catch (error) { return Promise.reject(error); } |
| + Block* try_block = init_block; |
| + Scope* catch_scope = NewScope(scope_, CATCH_SCOPE); |
| + Variable* catch_variable = |
| + catch_scope->DeclareLocal(ast_value_factory()->dot_catch_string(), |
| + VAR, kCreatedInitialized, Variable::NORMAL); |
| + Block* catch_block = |
| + factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition); |
| + |
| + ZoneList<Expression*>* promise_reject_arguments = |
| + new (zone()) ZoneList<Expression*>(1, zone()); |
| + promise_reject_arguments->Add(factory()->NewVariableProxy(catch_variable), |
| + zone()); |
| + CallRuntime* promise_reject = factory()->NewCallRuntime( |
| + Context::PROMISE_CREATE_REJECTED_INDEX, promise_reject_arguments, |
| + RelocInfo::kNoPosition); |
| + ReturnStatement* return_promise_reject = |
| + factory()->NewReturnStatement(promise_reject, RelocInfo::kNoPosition); |
| + catch_block->statements()->Add(return_promise_reject, zone()); |
| + TryStatement* try_catch_statement = factory()->NewTryCatchStatement( |
| + try_block, catch_scope, catch_variable, catch_block, |
| + RelocInfo::kNoPosition); |
| + |
| + init_block = |
| + factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition); |
| + init_block->statements()->Add(try_catch_statement, zone()); |
| + } |
| + |
| DCHECK_NOT_NULL(init_block); |
| inner_scope->set_end_position(scanner()->location().end_pos); |
| @@ -5396,7 +5508,10 @@ void ParserTraits::RewriteNonPattern(Type::ExpressionClassifier* classifier, |
| Expression* ParserTraits::RewriteAwaitExpression(Expression* value, int pos) { |
| // TODO(caitp): Implement AsyncFunctionAwait() |
| // per tc39.github.io/ecmascript-asyncawait/#abstract-ops-async-function-await |
| - return value; |
| + Expression* generator_object = parser_->factory()->NewVariableProxy( |
| + parser_->function_state_->generator_object_variable()); |
| + value = BuildIteratorResult(value, false); |
| + return parser_->factory()->NewYield(generator_object, value, pos); |
| } |
| Zone* ParserTraits::zone() const { |