Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(125)

Unified Diff: src/parsing/parser.cc

Issue 1895603002: [esnext] prototype runtime implementation for async functions (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@AsyncFunction
Patch Set: majorly improve stack traces, get rid of self-spawning behaviour, create inner generator function Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/parsing/parser.h ('k') | src/parsing/parser-base.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 {
« no previous file with comments | « src/parsing/parser.h ('k') | src/parsing/parser-base.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698