Index: src/parsing/parser.cc |
diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc |
index 9060868a3ff0e08ec3746221078ae87ad75924d5..5967c74cd3a79f7b77f0ee978142624181086417 100644 |
--- a/src/parsing/parser.cc |
+++ b/src/parsing/parser.cc |
@@ -2463,7 +2463,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) { |
if (is_generator()) { |
return_value = BuildIteratorResult(return_value, true); |
} else if (is_async_function()) { |
- return_value = BuildPromiseResolve(return_value, return_value->position()); |
+ return_value = BuildResolvePromise(return_value, return_value->position()); |
} |
result = factory()->NewReturnStatement(return_value, loc.beg_pos); |
@@ -3792,12 +3792,11 @@ void Parser::DesugarAsyncFunctionBody(const AstRawString* function_name, |
FunctionBodyType body_type, |
bool accept_IN, int pos, bool* ok) { |
// function async_function() { |
- // try { |
- // .generator_object = %CreateGeneratorObject(); |
+ // .generator_object = %CreateGeneratorObject(); |
+ // BuildRejectPromiseOnException({ |
// ... function body ... |
- // } catch (e) { |
- // return Promise.reject(e); |
- // } |
+ // return %ResolvePromise(.promise, expr), .promise; |
+ // }) |
// } |
scope->ForceContextAllocation(); |
Variable* temp = |
@@ -3811,13 +3810,11 @@ void Parser::DesugarAsyncFunctionBody(const AstRawString* function_name, |
kNoSourcePosition), |
zone()); |
- Block* try_block = factory()->NewBlock(NULL, 8, true, kNoSourcePosition); |
- |
- ZoneList<Statement*>* inner_body = try_block->statements(); |
+ Block* block = factory()->NewBlock(NULL, 8, true, kNoSourcePosition); |
Expression* return_value = nullptr; |
if (body_type == FunctionBodyType::kNormal) { |
- ParseStatementList(inner_body, Token::RBRACE, CHECK_OK_VOID); |
+ ParseStatementList(block->statements(), Token::RBRACE, CHECK_OK_VOID); |
return_value = factory()->NewUndefinedLiteral(kNoSourcePosition); |
} else { |
return_value = |
@@ -3825,11 +3822,12 @@ void Parser::DesugarAsyncFunctionBody(const AstRawString* function_name, |
RewriteNonPattern(classifier, CHECK_OK_VOID); |
} |
- return_value = BuildPromiseResolve(return_value, return_value->position()); |
- inner_body->Add( |
+ return_value = BuildResolvePromise(return_value, return_value->position()); |
+ block->statements()->Add( |
factory()->NewReturnStatement(return_value, return_value->position()), |
zone()); |
- body->Add(BuildRejectPromiseOnException(try_block), zone()); |
+ block = BuildRejectPromiseOnException(block, CHECK_OK_VOID); |
+ body->Add(block, zone()); |
scope->set_end_position(scanner()->location().end_pos); |
} |
@@ -4387,9 +4385,67 @@ Block* Parser::BuildParameterInitializationBlock( |
return init_block; |
} |
-Block* Parser::BuildRejectPromiseOnException(Block* block) { |
- // try { <block> } catch (error) { return Promise.reject(error); } |
- Block* try_block = block; |
+Block* Parser::BuildRejectPromiseOnException(Block* inner_block, bool* ok) { |
+ // var .promise = %CreatePromise(); |
+ // var .debug_is_active = %_DebugIsActive(); |
+ // if (.debug_is_active) %DebugPushPromise(.promise); |
+ // try { |
+ // <inner_block> |
+ // } catch (.catch) { |
+ // %RejectPromise(.promise, .catch); |
+ // return .promise; |
+ // } finally { |
+ // if (.debug_is_active) %DebugPopPromise(); |
+ // } |
+ Block* result = factory()->NewBlock(nullptr, 4, true, kNoSourcePosition); |
+ |
+ // var .promise = %CreatePromise(); |
+ Statement* set_promise; |
+ { |
+ DeclareVariable(ast_value_factory()->dot_promise_string(), VAR, |
+ kNoSourcePosition, CHECK_OK); |
+ Expression* create_promise = factory()->NewCallRuntime( |
+ Context::PROMISE_CREATE_INDEX, |
+ new (zone()) ZoneList<Expression*>(0, zone()), kNoSourcePosition); |
+ Assignment* assign_promise = factory()->NewAssignment( |
+ Token::INIT, BuildDotPromise(), create_promise, kNoSourcePosition); |
+ set_promise = |
+ factory()->NewExpressionStatement(assign_promise, kNoSourcePosition); |
+ } |
+ result->statements()->Add(set_promise, zone()); |
+ |
+ // var .debug_is_active = %_DebugIsActive(); |
+ Statement* set_debug_is_active; |
+ { |
+ DeclareVariable(ast_value_factory()->dot_debug_is_active_string(), VAR, |
+ kNoSourcePosition, CHECK_OK); |
+ Expression* debug_is_active = factory()->NewCallRuntime( |
+ Runtime::kInlineDebugIsActive, |
+ new (zone()) ZoneList<Expression*>(0, zone()), kNoSourcePosition); |
+ Assignment* assign_debug_is_active = |
+ factory()->NewAssignment(Token::INIT, BuildDotDebugIsActive(), |
+ debug_is_active, kNoSourcePosition); |
+ set_debug_is_active = factory()->NewExpressionStatement( |
+ assign_debug_is_active, kNoSourcePosition); |
+ } |
+ result->statements()->Add(set_debug_is_active, zone()); |
+ |
+ // if (.debug_is_active) %DebugPushPromise(.promise); |
+ Statement* conditionally_debug_push_promise; |
+ { |
+ ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone()); |
+ args->Add(BuildDotPromise(), zone()); |
+ Expression* call_push_promise = factory()->NewCallRuntime( |
+ Runtime::kDebugPushPromise, args, kNoSourcePosition); |
+ Statement* debug_push_promise = |
+ factory()->NewExpressionStatement(call_push_promise, kNoSourcePosition); |
+ conditionally_debug_push_promise = factory()->NewIfStatement( |
+ BuildDotDebugIsActive(), debug_push_promise, |
+ factory()->NewEmptyStatement(kNoSourcePosition), kNoSourcePosition); |
+ } |
+ result->statements()->Add(conditionally_debug_push_promise, zone()); |
+ |
+ // catch (.catch) { return %RejectPromise(.promise, .catch), .promise } |
Scope* catch_scope = NewScope(CATCH_SCOPE); |
catch_scope->set_is_hidden(); |
Variable* catch_variable = |
@@ -4397,18 +4453,40 @@ Block* Parser::BuildRejectPromiseOnException(Block* block) { |
kCreatedInitialized, Variable::NORMAL); |
Block* catch_block = factory()->NewBlock(nullptr, 1, true, kNoSourcePosition); |
- Expression* promise_reject = BuildPromiseReject( |
+ 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()); |
+ |
TryStatement* try_catch_statement = factory()->NewTryCatchStatement( |
- try_block, catch_scope, catch_variable, catch_block, kNoSourcePosition); |
+ 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 { if (.debug_is_active) %DebugPopPromise(); } |
+ Block* finally_block = |
+ factory()->NewBlock(nullptr, 1, true, kNoSourcePosition); |
+ { |
+ ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(0, zone()); |
+ Expression* call_pop_promise = factory()->NewCallRuntime( |
+ Runtime::kDebugPopPromise, args, kNoSourcePosition); |
+ Statement* debug_pop_promise = |
+ factory()->NewExpressionStatement(call_pop_promise, kNoSourcePosition); |
+ Statement* conditionally_debug_pop_promise = factory()->NewIfStatement( |
+ BuildDotDebugIsActive(), debug_pop_promise, |
+ factory()->NewEmptyStatement(kNoSourcePosition), kNoSourcePosition); |
+ finally_block->statements()->Add(conditionally_debug_pop_promise, zone()); |
+ } |
+ |
+ Statement* try_finally_statement = factory()->NewTryFinallyStatement( |
+ outer_try_block, finally_block, kNoSourcePosition); |
- block = factory()->NewBlock(nullptr, 1, true, kNoSourcePosition); |
- block->statements()->Add(try_catch_statement, zone()); |
- return block; |
+ result->statements()->Add(try_finally_statement, zone()); |
+ return result; |
} |
Expression* Parser::BuildCreateJSGeneratorObject(int pos, FunctionKind kind) { |
@@ -4422,18 +4500,37 @@ Expression* Parser::BuildCreateJSGeneratorObject(int pos, FunctionKind kind) { |
pos); |
} |
-Expression* Parser::BuildPromiseResolve(Expression* value, int pos) { |
- ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone()); |
+Expression* Parser::BuildResolvePromise(Expression* value, int pos) { |
+ // %ResolvePromise(.promise, value), .promise |
+ ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone()); |
+ args->Add(BuildDotPromise(), zone()); |
args->Add(value, zone()); |
- return factory()->NewCallRuntime(Context::PROMISE_CREATE_RESOLVED_INDEX, args, |
- pos); |
+ Expression* call_runtime = |
+ factory()->NewCallRuntime(Context::PROMISE_RESOLVE_INDEX, args, pos); |
+ return factory()->NewBinaryOperation(Token::COMMA, call_runtime, |
+ BuildDotPromise(), pos); |
} |
-Expression* Parser::BuildPromiseReject(Expression* value, int pos) { |
- ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone()); |
+Expression* Parser::BuildRejectPromise(Expression* value, int pos) { |
+ // %RejectPromiseNoDebugEvent(.promise, value, true), .promise |
+ // The NoDebugEvent variant 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*>(2, zone()); |
+ args->Add(BuildDotPromise(), zone()); |
args->Add(value, zone()); |
- return factory()->NewCallRuntime(Context::PROMISE_CREATE_REJECTED_INDEX, args, |
- pos); |
+ Expression* call_runtime = factory()->NewCallRuntime( |
+ Context::REJECT_PROMISE_NO_DEBUG_EVENT_INDEX, args, pos); |
+ return factory()->NewBinaryOperation(Token::COMMA, call_runtime, |
+ BuildDotPromise(), pos); |
+} |
+ |
+VariableProxy* Parser::BuildDotPromise() { |
+ return NewUnresolved(ast_value_factory()->dot_promise_string(), VAR); |
+} |
+ |
+VariableProxy* Parser::BuildDotDebugIsActive() { |
+ return NewUnresolved(ast_value_factory()->dot_debug_is_active_string(), VAR); |
} |
ZoneList<Statement*>* Parser::ParseEagerFunctionBody( |
@@ -4559,8 +4656,9 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody( |
CHECK_OK); |
} |
+ // TODO(littledan): Merge the two rejection blocks into one |
if (IsAsyncFunction(kind)) { |
- init_block = BuildRejectPromiseOnException(init_block); |
+ init_block = BuildRejectPromiseOnException(init_block, CHECK_OK); |
} |
DCHECK_NOT_NULL(init_block); |