| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/ast_transformer.h" | 5 #include "vm/ast_transformer.h" |
| 6 | 6 |
| 7 #include "vm/parser.h" | 7 #include "vm/parser.h" |
| 8 | 8 |
| 9 namespace dart { | 9 namespace dart { |
| 10 | 10 |
| 11 // Quick access to the locally defined isolate() method. | 11 // Quick access to the locally defined isolate() method. |
| 12 #define I (isolate()) | 12 #define I (isolate()) |
| 13 | 13 |
| 14 // Nodes that are unreachable from already parsed expressions. | 14 // Nodes that are unreachable from already parsed expressions. |
| 15 #define FOR_EACH_UNREACHABLE_NODE(V) \ | 15 #define FOR_EACH_UNREACHABLE_NODE(V) \ |
| 16 V(AwaitMarker) \ |
| 16 V(Case) \ | 17 V(Case) \ |
| 17 V(CatchClause) \ | 18 V(CatchClause) \ |
| 18 V(CloneContext) \ | 19 V(CloneContext) \ |
| 19 V(ClosureCall) \ | 20 V(ClosureCall) \ |
| 20 V(DoWhile) \ | 21 V(DoWhile) \ |
| 21 V(If) \ | 22 V(If) \ |
| 22 V(InitStaticField) \ | 23 V(InitStaticField) \ |
| 23 V(InlinedFinally) \ | 24 V(InlinedFinally) \ |
| 24 V(For) \ | 25 V(For) \ |
| 25 V(Jump) \ | 26 V(Jump) \ |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 void AwaitTransformer::VisitLiteralNode(LiteralNode* node) { | 79 void AwaitTransformer::VisitLiteralNode(LiteralNode* node) { |
| 79 result_ = node; | 80 result_ = node; |
| 80 } | 81 } |
| 81 | 82 |
| 82 | 83 |
| 83 void AwaitTransformer::VisitTypeNode(TypeNode* node) { | 84 void AwaitTransformer::VisitTypeNode(TypeNode* node) { |
| 84 result_ = new(I) TypeNode(node->token_pos(), node->type()); | 85 result_ = new(I) TypeNode(node->token_pos(), node->type()); |
| 85 } | 86 } |
| 86 | 87 |
| 87 | 88 |
| 88 | |
| 89 void AwaitTransformer::VisitAwaitNode(AwaitNode* node) { | 89 void AwaitTransformer::VisitAwaitNode(AwaitNode* node) { |
| 90 // Await transformation: | 90 // Await transformation: |
| 91 // | 91 // |
| 92 // :await_temp_var_X = <expr>; | 92 // :await_temp_var_X = <expr>; |
| 93 // :result_param = :await_temp_var_X; | 93 // :result_param = :await_temp_var_X; |
| 94 // if (:result_param is Future) { | 94 // if (:result_param is Future) { |
| 95 // // :result_param.then(:async_op); | 95 // AwaitMarker(kNewContinuationState); |
| 96 // :result_param.then(:async_op); |
| 97 // return; // (return_type() == kContinuation) |
| 96 // } | 98 // } |
| 99 // AwaitMarker(kTargetForContinuation); // Join happens here. |
| 100 // :saved_try_ctx_var = :await_saved_try_ctx_var_y; |
| 97 // :await_temp_var_(X+1) = :result_param; | 101 // :await_temp_var_(X+1) = :result_param; |
| 98 | 102 |
| 99 LocalVariable* async_op = preamble_->scope()->LookupVariable( | 103 LocalVariable* async_op = preamble_->scope()->LookupVariable( |
| 100 Symbols::AsyncOperation(), false); | 104 Symbols::AsyncOperation(), false); |
| 101 ASSERT(async_op != NULL); | 105 ASSERT(async_op != NULL); |
| 102 LocalVariable* result_param = preamble_->scope()->LookupVariable( | 106 LocalVariable* result_param = preamble_->scope()->LookupVariable( |
| 103 Symbols::AsyncOperationParam(), false); | 107 Symbols::AsyncOperationParam(), false); |
| 104 ASSERT(result_param != NULL); | 108 ASSERT(result_param != NULL); |
| 105 | 109 |
| 106 node->expr()->Visit(this); | 110 node->expr()->Visit(this); |
| 107 preamble_->Add(new(I) StoreLocalNode(Scanner::kNoSourcePos, | 111 preamble_->Add(new(I) StoreLocalNode( |
| 108 result_param, | 112 Scanner::kNoSourcePos, result_param, result_)); |
| 109 result_)); | |
| 110 LoadLocalNode* load_result_param = new(I) LoadLocalNode( | 113 LoadLocalNode* load_result_param = new(I) LoadLocalNode( |
| 111 Scanner::kNoSourcePos, result_param); | 114 Scanner::kNoSourcePos, result_param); |
| 112 SequenceNode* is_future_branch = new(I) SequenceNode( | 115 SequenceNode* is_future_branch = new(I) SequenceNode( |
| 113 Scanner::kNoSourcePos, preamble_->scope()); | 116 Scanner::kNoSourcePos, preamble_->scope()); |
| 117 AwaitMarkerNode* await_marker = |
| 118 new(I) AwaitMarkerNode(AwaitMarkerNode::kNewContinuationState); |
| 119 await_marker->set_scope(preamble_->scope()); |
| 120 is_future_branch->Add(await_marker); |
| 114 ArgumentListNode* args = new(I) ArgumentListNode(Scanner::kNoSourcePos); | 121 ArgumentListNode* args = new(I) ArgumentListNode(Scanner::kNoSourcePos); |
| 115 args->Add(new(I) LoadLocalNode(Scanner::kNoSourcePos, async_op)); | 122 args->Add(new(I) LoadLocalNode(Scanner::kNoSourcePos, async_op)); |
| 116 // TODO(mlippautz): Once continuations are supported, just call .then(). | 123 is_future_branch->Add(new(I) InstanceCallNode( |
| 117 // is_future_branch->Add(new(I) InstanceCallNode( | 124 Scanner::kNoSourcePos, load_result_param, Symbols::FutureThen(), args)); |
| 118 // Scanner::kNoSourcePos, load_result_param, Symbols::FutureThen(), args)); | 125 ReturnNode* continuation_return = new(I) ReturnNode(Scanner::kNoSourcePos); |
| 119 // | 126 continuation_return->set_return_type(ReturnNode::kContinuation); |
| 120 // For now, throw an exception. | 127 is_future_branch->Add(continuation_return); |
| 121 const String& exception = String::ZoneHandle( | 128 |
| 122 I, String::New("awaitable futures not yet supported", Heap::kOld)); | |
| 123 is_future_branch->Add(new(I) ThrowNode( | |
| 124 Scanner::kNoSourcePos, | |
| 125 new(I) LiteralNode( | |
| 126 Scanner::kNoSourcePos, | |
| 127 String::ZoneHandle(I, Symbols::New(exception))), | |
| 128 NULL)); | |
| 129 const Class& cls = Class::ZoneHandle( | 129 const Class& cls = Class::ZoneHandle( |
| 130 I, library_.LookupClass(Symbols::Future())); | 130 I, library_.LookupClass(Symbols::Future())); |
| 131 const AbstractType& future_type = AbstractType::ZoneHandle(I, | 131 const AbstractType& future_type = AbstractType::ZoneHandle(I, cls.RareType()); |
| 132 cls.RareType()); | |
| 133 ASSERT(!future_type.IsNull()); | 132 ASSERT(!future_type.IsNull()); |
| 134 TypeNode* future_type_node = new(I) TypeNode( | 133 preamble_->Add(new(I) IfNode( |
| 135 Scanner::kNoSourcePos, future_type); | |
| 136 IfNode* is_future_if = new(I) IfNode( | |
| 137 Scanner::kNoSourcePos, | 134 Scanner::kNoSourcePos, |
| 138 new(I) ComparisonNode(Scanner::kNoSourcePos, | 135 new (I) ComparisonNode( |
| 139 Token::kIS, | 136 Scanner::kNoSourcePos, |
| 140 load_result_param, | 137 Token::kIS, |
| 141 future_type_node), | 138 load_result_param, |
| 139 new (I) TypeNode(Scanner::kNoSourcePos, future_type)), |
| 142 is_future_branch, | 140 is_future_branch, |
| 143 NULL); | 141 NULL)); |
| 144 preamble_->Add(is_future_if); | 142 preamble_->Add(new (I) AwaitMarkerNode( |
| 145 | 143 AwaitMarkerNode::kTargetForContinuation)); |
| 146 // TODO(mlippautz): Join for await needs to happen here. | 144 // If this expression is part of a try block, also append the code for |
| 145 // restoring the saved try context that lives on the stack. |
| 146 if (parsed_function_->saved_try_ctx() != NULL) { |
| 147 preamble_->Add(new (I) StoreLocalNode( |
| 148 Scanner::kNoSourcePos, |
| 149 parsed_function_->saved_try_ctx(), |
| 150 new (I) LoadLocalNode( |
| 151 Scanner::kNoSourcePos, parsed_function_->async_saved_try_ctx()))); |
| 152 } |
| 147 | 153 |
| 148 LocalVariable* result = AddToPreambleNewTempVar(new(I) LoadLocalNode( | 154 LocalVariable* result = AddToPreambleNewTempVar(new(I) LoadLocalNode( |
| 149 Scanner::kNoSourcePos, result_param)); | 155 Scanner::kNoSourcePos, result_param)); |
| 150 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); | 156 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 151 } | 157 } |
| 152 | 158 |
| 153 | 159 |
| 154 // Transforms boolean expressions into a sequence of evaluatons that only lazily | 160 // Transforms boolean expressions into a sequence of evaluatons that only lazily |
| 155 // evaluate subexpressions. | 161 // evaluate subexpressions. |
| 156 // | 162 // |
| (...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 499 void AwaitTransformer::VisitThrowNode(ThrowNode* node) { | 505 void AwaitTransformer::VisitThrowNode(ThrowNode* node) { |
| 500 // TODO(mlippautz): Check if relevant. | 506 // TODO(mlippautz): Check if relevant. |
| 501 AstNode* new_exception = Transform(node->exception()); | 507 AstNode* new_exception = Transform(node->exception()); |
| 502 AstNode* new_stacktrace = Transform(node->stacktrace()); | 508 AstNode* new_stacktrace = Transform(node->stacktrace()); |
| 503 result_ = new(I) ThrowNode(node->token_pos(), | 509 result_ = new(I) ThrowNode(node->token_pos(), |
| 504 new_exception, | 510 new_exception, |
| 505 new_stacktrace); | 511 new_stacktrace); |
| 506 } | 512 } |
| 507 | 513 |
| 508 } // namespace dart | 514 } // namespace dart |
| OLD | NEW |