Index: src/parsing/parser.cc |
diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc |
index 805b6ef066bfe5ea0cd4669cf2ad2a387b022873..50ce215b3f3704f07c3151a7b0e2905c8a6b3435 100644 |
--- a/src/parsing/parser.cc |
+++ b/src/parsing/parser.cc |
@@ -1613,10 +1613,17 @@ Expression* Parser::RewriteReturn(Expression* return_value, int pos) { |
return_value = factory()->NewConditional(is_undefined, ThisExpression(pos), |
is_object_conditional, pos); |
} |
+ |
if (is_generator()) { |
return_value = BuildIteratorResult(return_value, true); |
} else if (is_async_function()) { |
- return_value = BuildResolvePromise(return_value, return_value->position()); |
+ // In an async function, |
+ // return expr; |
+ // is rewritten as |
+ // return .async_return_value = expr; |
+ return_value = factory()->NewAssignment( |
+ Token::ASSIGN, factory()->NewVariableProxy(AsyncReturnVariable()), |
+ return_value, kNoSourcePosition); |
} |
return return_value; |
} |
@@ -2977,59 +2984,157 @@ Block* Parser::BuildParameterInitializationBlock( |
return init_block; |
} |
+Block* Parser::BuildRejectPromiseOnExceptionForParameters(Block* inner_block) { |
+ // .promise = %AsyncFunctionPromiseCreate(); |
+ // try { |
+ // <inner_block> |
+ // } catch (.catch) { |
+ // return %RejectPromise(.promise, .catch), .promise; |
+ // } |
+ Block* result = factory()->NewBlock(nullptr, 2, true, kNoSourcePosition); |
+ |
+ { |
+ // .promise = %AsyncFunctionPromiseCreate(); |
+ Expression* create_promise = factory()->NewCallRuntime( |
+ Context::ASYNC_FUNCTION_PROMISE_CREATE_INDEX, |
+ new (zone()) ZoneList<Expression*>(0, zone()), kNoSourcePosition); |
+ Assignment* assign_promise = factory()->NewAssignment( |
+ Token::INIT, factory()->NewVariableProxy(PromiseVariable()), |
+ create_promise, kNoSourcePosition); |
+ Statement* set_promise = |
+ factory()->NewExpressionStatement(assign_promise, kNoSourcePosition); |
+ result->statements()->Add(set_promise, zone()); |
+ } |
+ |
+ // catch (.catch) { |
+ // return %RejectPromise(.promise, .catch), .promise; |
+ // } |
+ Scope* catch_scope = NewScope(CATCH_SCOPE); |
+ catch_scope->set_is_hidden(); |
+ Variable* catch_variable = |
+ catch_scope->DeclareLocal(ast_value_factory()->dot_catch_string(), VAR); |
+ Block* catch_block = factory()->NewBlock(nullptr, 1, true, kNoSourcePosition); |
+ { |
+ // return %RejectPromise(.promise, .catch), .promise; |
+ Expression* reject_return_promise = factory()->NewBinaryOperation( |
+ Token::COMMA, BuildRejectPromise(catch_variable), |
+ factory()->NewVariableProxy(PromiseVariable(), kNoSourcePosition), |
+ kNoSourcePosition); |
+ |
+ catch_block->statements()->Add( |
+ factory()->NewReturnStatement(reject_return_promise, kNoSourcePosition), |
+ zone()); |
+ } |
+ |
+ TryStatement* try_catch_statement = |
+ factory()->NewTryCatchStatementForAsyncAwait(inner_block, catch_scope, |
+ catch_variable, catch_block, |
+ kNoSourcePosition); |
+ result->statements()->Add(try_catch_statement, zone()); |
+ return result; |
+} |
+ |
Block* Parser::BuildRejectPromiseOnException(Block* inner_block) { |
+ // .is_rejection = false; |
// .promise = %AsyncFunctionPromiseCreate(); |
// try { |
// <inner_block> |
// } catch (.catch) { |
- // %RejectPromise(.promise, .catch); |
- // return .promise; |
+ // .is_rejection = true; |
+ // .async_return_value = .catch; |
// } finally { |
+ // .is_rejection |
+ // ? %RejectPromise(.promise, .async_return_value) |
+ // : %ResolvePromise(.promise, .async_return_value); |
// %AsyncFunctionPromiseRelease(.promise); |
+ // return .promise; |
// } |
- Block* result = factory()->NewBlock(nullptr, 2, true, kNoSourcePosition); |
+ Block* result = factory()->NewBlock(nullptr, 3, true, kNoSourcePosition); |
- // .promise = %AsyncFunctionPromiseCreate(); |
- Statement* set_promise; |
+ Variable* is_rejection_var = |
+ scope()->NewTemporary(ast_value_factory()->empty_string()); |
{ |
+ // .is_rejection = false; |
+ Assignment* set_is_rejection = factory()->NewAssignment( |
+ Token::INIT, factory()->NewVariableProxy(is_rejection_var), |
+ factory()->NewBooleanLiteral(false, kNoSourcePosition), |
+ kNoSourcePosition); |
+ result->statements()->Add( |
+ factory()->NewExpressionStatement(set_is_rejection, kNoSourcePosition), |
+ zone()); |
+ |
+ // .promise = %AsyncFunctionPromiseCreate(); |
Expression* create_promise = factory()->NewCallRuntime( |
Context::ASYNC_FUNCTION_PROMISE_CREATE_INDEX, |
new (zone()) ZoneList<Expression*>(0, zone()), kNoSourcePosition); |
Assignment* assign_promise = factory()->NewAssignment( |
Token::INIT, factory()->NewVariableProxy(PromiseVariable()), |
create_promise, kNoSourcePosition); |
- set_promise = |
+ Statement* set_promise = |
factory()->NewExpressionStatement(assign_promise, kNoSourcePosition); |
+ result->statements()->Add(set_promise, zone()); |
} |
- result->statements()->Add(set_promise, zone()); |
- // catch (.catch) { return %RejectPromise(.promise, .catch), .promise } |
+ // catch (.catch) { |
+ // .is_rejection = true; |
+ // .async_return_value = .catch; |
+ // } |
Scope* catch_scope = NewScope(CATCH_SCOPE); |
catch_scope->set_is_hidden(); |
Variable* catch_variable = |
catch_scope->DeclareLocal(ast_value_factory()->dot_catch_string(), VAR); |
Block* catch_block = factory()->NewBlock(nullptr, 1, true, kNoSourcePosition); |
+ { |
+ // .is_rejection = true; |
+ DCHECK_NOT_NULL(is_rejection_var); |
+ Assignment* set_is_rejection = factory()->NewAssignment( |
+ Token::ASSIGN, factory()->NewVariableProxy(is_rejection_var), |
+ factory()->NewBooleanLiteral(true, kNoSourcePosition), |
+ kNoSourcePosition); |
+ catch_block->statements()->Add( |
+ factory()->NewExpressionStatement(set_is_rejection, kNoSourcePosition), |
+ zone()); |
+ // .async_return_value = .catch; |
+ Assignment* set_async_return_var = factory()->NewAssignment( |
+ Token::ASSIGN, factory()->NewVariableProxy(AsyncReturnVariable()), |
+ factory()->NewVariableProxy(catch_variable), kNoSourcePosition); |
- Expression* promise_reject = BuildRejectPromise( |
- factory()->NewVariableProxy(catch_variable), kNoSourcePosition); |
- ReturnStatement* return_promise_reject = |
- factory()->NewReturnStatement(promise_reject, kNoSourcePosition); |
- catch_block->statements()->Add(return_promise_reject, zone()); |
+ catch_block->statements()->Add(factory()->NewExpressionStatement( |
+ set_async_return_var, kNoSourcePosition), |
+ zone()); |
+ } |
TryStatement* try_catch_statement = |
factory()->NewTryCatchStatementForAsyncAwait(inner_block, catch_scope, |
catch_variable, catch_block, |
kNoSourcePosition); |
- |
- // There is no TryCatchFinally node, so wrap it in an outer try/finally |
Block* outer_try_block = |
factory()->NewBlock(nullptr, 1, true, kNoSourcePosition); |
outer_try_block->statements()->Add(try_catch_statement, zone()); |
- // finally { %AsyncFunctionPromiseRelease(.promise) } |
+ // finally { |
+ // .is_rejection |
+ // ? %RejectPromise(.promise, .async_return_value) |
+ // : %ResolvePromise(.promise, .async_return_value); |
+ // %AsyncFunctionPromiseRelease(.promise); |
+ // return .promise; |
+ // } |
Block* finally_block = |
factory()->NewBlock(nullptr, 1, true, kNoSourcePosition); |
{ |
+ // .is_rejection |
+ // ? %RejectPromise(.promise, .async_return_value) |
+ // : %ResolvePromise(.promise, .async_return_value); |
+ Expression* resolve_or_reject_promise = |
+ factory()->NewConditional(factory()->NewVariableProxy(is_rejection_var), |
+ BuildRejectPromise(AsyncReturnVariable()), |
+ BuildResolvePromise(), kNoSourcePosition); |
+ finally_block->statements()->Add( |
+ factory()->NewExpressionStatement(resolve_or_reject_promise, |
+ kNoSourcePosition), |
+ zone()); |
+ |
+ // %AsyncFunctionPromiseRelease(.promise); |
ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone()); |
args->Add(factory()->NewVariableProxy(PromiseVariable()), zone()); |
Expression* call_promise_release = factory()->NewCallRuntime( |
@@ -3037,11 +3142,15 @@ Block* Parser::BuildRejectPromiseOnException(Block* inner_block) { |
Statement* promise_release = factory()->NewExpressionStatement( |
call_promise_release, kNoSourcePosition); |
finally_block->statements()->Add(promise_release, zone()); |
+ |
+ // return .promise; |
+ Statement* return_promise = factory()->NewReturnStatement( |
+ factory()->NewVariableProxy(PromiseVariable()), kNoSourcePosition); |
+ finally_block->statements()->Add(return_promise, zone()); |
} |
Statement* try_finally_statement = factory()->NewTryFinallyStatement( |
outer_try_block, finally_block, kNoSourcePosition); |
- |
result->statements()->Add(try_finally_statement, zone()); |
return result; |
} |
@@ -3062,31 +3171,25 @@ Assignment* Parser::BuildCreateJSGeneratorObject(int pos, FunctionKind kind) { |
kNoSourcePosition); |
} |
-Expression* Parser::BuildResolvePromise(Expression* value, int pos) { |
- // %ResolvePromise(.promise, value), .promise |
+Expression* Parser::BuildResolvePromise() { |
+ // %ResolvePromise(.promise, .async_return_variable), .promise |
ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone()); |
args->Add(factory()->NewVariableProxy(PromiseVariable()), zone()); |
- args->Add(value, zone()); |
- Expression* call_runtime = |
- factory()->NewCallRuntime(Context::PROMISE_RESOLVE_INDEX, args, pos); |
- return factory()->NewBinaryOperation( |
- Token::COMMA, call_runtime, |
- factory()->NewVariableProxy(PromiseVariable()), pos); |
+ args->Add(factory()->NewVariableProxy(AsyncReturnVariable()), zone()); |
+ return factory()->NewCallRuntime(Context::PROMISE_RESOLVE_INDEX, args, |
+ kNoSourcePosition); |
} |
-Expression* Parser::BuildRejectPromise(Expression* value, int pos) { |
- // %promise_internal_reject(.promise, value, false), .promise |
+Expression* Parser::BuildRejectPromise(Variable* value) { |
+ // %promise_internal_reject(.promise, .value, false) |
// Disables the additional debug event for the rejection since a debug event |
// already happened for the exception that got us here. |
ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(3, zone()); |
args->Add(factory()->NewVariableProxy(PromiseVariable()), zone()); |
- args->Add(value, zone()); |
- args->Add(factory()->NewBooleanLiteral(false, pos), zone()); |
- Expression* call_runtime = factory()->NewCallRuntime( |
- Context::PROMISE_INTERNAL_REJECT_INDEX, args, pos); |
- return factory()->NewBinaryOperation( |
- Token::COMMA, call_runtime, |
- factory()->NewVariableProxy(PromiseVariable()), pos); |
+ args->Add(factory()->NewVariableProxy(value), zone()); |
+ args->Add(factory()->NewBooleanLiteral(false, kNoSourcePosition), zone()); |
+ return factory()->NewCallRuntime(Context::PROMISE_INTERNAL_REJECT_INDEX, args, |
+ kNoSourcePosition); |
} |
Variable* Parser::PromiseVariable() { |
@@ -3101,6 +3204,19 @@ Variable* Parser::PromiseVariable() { |
return promise; |
} |
+Variable* Parser::AsyncReturnVariable() { |
+ // Based on the various compilation paths, there are many different |
+ // code paths which may be the first to access the return value |
+ // temporary. Whichever comes first should create it and stash it in |
+ // the FunctionState. |
+ Variable* async_return = function_state_->async_return_variable(); |
+ if (async_return == nullptr) { |
+ async_return = scope()->NewTemporary(ast_value_factory()->empty_string()); |
+ function_state_->set_async_return_variable(async_return); |
+ } |
+ return async_return; |
+} |
+ |
Expression* Parser::BuildInitialYield(int pos, FunctionKind kind) { |
Assignment* assignment = BuildCreateJSGeneratorObject(pos, kind); |
VariableProxy* generator = |
@@ -3782,14 +3898,16 @@ void Parser::RewriteAsyncFunctionBody(ZoneList<Statement*>* body, Block* block, |
// .generator_object = %CreateJSGeneratorObject(); |
// BuildRejectPromiseOnException({ |
// ... block ... |
- // return %ResolvePromise(.promise, expr), .promise; |
+ // .async_return_var = expr; |
// }) |
// } |
- return_value = BuildResolvePromise(return_value, return_value->position()); |
- block->statements()->Add( |
- factory()->NewReturnStatement(return_value, return_value->position()), |
- zone()); |
+ Assignment* set_async_return_var = factory()->NewAssignment( |
+ Token::ASSIGN, factory()->NewVariableProxy(AsyncReturnVariable()), |
+ return_value, kNoSourcePosition); |
+ block->statements()->Add(factory()->NewExpressionStatement( |
+ set_async_return_var, kNoSourcePosition), |
+ zone()); |
block = BuildRejectPromiseOnException(block); |
body->Add(block, zone()); |
} |