Index: runtime/vm/ast_transformer.cc |
diff --git a/runtime/vm/ast_transformer.cc b/runtime/vm/ast_transformer.cc |
index e4637e5427829ebe023c438fb493c7879df0881d..6ef865f0e246a4e88846d46a2240b562078efbf2 100644 |
--- a/runtime/vm/ast_transformer.cc |
+++ b/runtime/vm/ast_transformer.cc |
@@ -13,6 +13,7 @@ namespace dart { |
// Nodes that are unreachable from already parsed expressions. |
#define FOR_EACH_UNREACHABLE_NODE(V) \ |
+ V(AwaitMarker) \ |
V(Case) \ |
V(CatchClause) \ |
V(CloneContext) \ |
@@ -85,15 +86,18 @@ void AwaitTransformer::VisitTypeNode(TypeNode* node) { |
} |
- |
void AwaitTransformer::VisitAwaitNode(AwaitNode* node) { |
// Await transformation: |
// |
// :await_temp_var_X = <expr>; |
// :result_param = :await_temp_var_X; |
// if (:result_param is Future) { |
- // // :result_param.then(:async_op); |
+ // AwaitMarker(kNewContinuationState); |
+ // :result_param.then(:async_op); |
+ // return; // (return_type() == kContinuation) |
// } |
+ // AwaitMarker(kTargetForContinuation); // Join happens here. |
+ // :saved_try_ctx_var = :await_saved_try_ctx_var_y; |
// :await_temp_var_(X+1) = :result_param; |
LocalVariable* async_op = preamble_->scope()->LookupVariable( |
@@ -104,46 +108,48 @@ void AwaitTransformer::VisitAwaitNode(AwaitNode* node) { |
ASSERT(result_param != NULL); |
node->expr()->Visit(this); |
- preamble_->Add(new(I) StoreLocalNode(Scanner::kNoSourcePos, |
- result_param, |
- result_)); |
+ preamble_->Add(new(I) StoreLocalNode( |
+ Scanner::kNoSourcePos, result_param, result_)); |
LoadLocalNode* load_result_param = new(I) LoadLocalNode( |
Scanner::kNoSourcePos, result_param); |
SequenceNode* is_future_branch = new(I) SequenceNode( |
Scanner::kNoSourcePos, preamble_->scope()); |
+ AwaitMarkerNode* await_marker = |
+ new(I) AwaitMarkerNode(AwaitMarkerNode::kNewContinuationState); |
+ await_marker->set_scope(preamble_->scope()); |
+ is_future_branch->Add(await_marker); |
ArgumentListNode* args = new(I) ArgumentListNode(Scanner::kNoSourcePos); |
args->Add(new(I) LoadLocalNode(Scanner::kNoSourcePos, async_op)); |
- // TODO(mlippautz): Once continuations are supported, just call .then(). |
- // is_future_branch->Add(new(I) InstanceCallNode( |
- // Scanner::kNoSourcePos, load_result_param, Symbols::FutureThen(), args)); |
- // |
- // For now, throw an exception. |
- const String& exception = String::ZoneHandle( |
- I, String::New("awaitable futures not yet supported", Heap::kOld)); |
- is_future_branch->Add(new(I) ThrowNode( |
- Scanner::kNoSourcePos, |
- new(I) LiteralNode( |
- Scanner::kNoSourcePos, |
- String::ZoneHandle(I, Symbols::New(exception))), |
- NULL)); |
+ is_future_branch->Add(new(I) InstanceCallNode( |
+ Scanner::kNoSourcePos, load_result_param, Symbols::FutureThen(), args)); |
+ ReturnNode* continuation_return = new(I) ReturnNode(Scanner::kNoSourcePos); |
+ continuation_return->set_return_type(ReturnNode::kContinuation); |
+ is_future_branch->Add(continuation_return); |
+ |
const Class& cls = Class::ZoneHandle( |
I, library_.LookupClass(Symbols::Future())); |
- const AbstractType& future_type = AbstractType::ZoneHandle(I, |
- cls.RareType()); |
+ const AbstractType& future_type = AbstractType::ZoneHandle(I, cls.RareType()); |
ASSERT(!future_type.IsNull()); |
- TypeNode* future_type_node = new(I) TypeNode( |
- Scanner::kNoSourcePos, future_type); |
- IfNode* is_future_if = new(I) IfNode( |
+ preamble_->Add(new(I) IfNode( |
Scanner::kNoSourcePos, |
- new(I) ComparisonNode(Scanner::kNoSourcePos, |
- Token::kIS, |
- load_result_param, |
- future_type_node), |
+ new (I) ComparisonNode( |
+ Scanner::kNoSourcePos, |
+ Token::kIS, |
+ load_result_param, |
+ new (I) TypeNode(Scanner::kNoSourcePos, future_type)), |
is_future_branch, |
- NULL); |
- preamble_->Add(is_future_if); |
- |
- // TODO(mlippautz): Join for await needs to happen here. |
+ NULL)); |
+ preamble_->Add(new (I) AwaitMarkerNode( |
+ AwaitMarkerNode::kTargetForContinuation)); |
+ // If this expression is part of a try block, also append the code for |
+ // restoring the saved try context that lives on the stack. |
+ if (parsed_function_->saved_try_ctx() != NULL) { |
+ preamble_->Add(new (I) StoreLocalNode( |
+ Scanner::kNoSourcePos, |
+ parsed_function_->saved_try_ctx(), |
+ new (I) LoadLocalNode( |
+ Scanner::kNoSourcePos, parsed_function_->async_saved_try_ctx()))); |
+ } |
LocalVariable* result = AddToPreambleNewTempVar(new(I) LoadLocalNode( |
Scanner::kNoSourcePos, result_param)); |