| 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 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 35 V(While) | 35 V(While) |
| 36 | 36 |
| 37 #define DEFINE_UNREACHABLE(BaseName) \ | 37 #define DEFINE_UNREACHABLE(BaseName) \ |
| 38 void AwaitTransformer::Visit##BaseName##Node(BaseName##Node* node) { \ | 38 void AwaitTransformer::Visit##BaseName##Node(BaseName##Node* node) { \ |
| 39 UNREACHABLE(); \ | 39 UNREACHABLE(); \ |
| 40 } | 40 } |
| 41 | 41 |
| 42 FOR_EACH_UNREACHABLE_NODE(DEFINE_UNREACHABLE) | 42 FOR_EACH_UNREACHABLE_NODE(DEFINE_UNREACHABLE) |
| 43 #undef DEFINE_UNREACHABLE | 43 #undef DEFINE_UNREACHABLE |
| 44 | 44 |
| 45 AwaitTransformer::AwaitTransformer(SequenceNode* preamble, |
| 46 const Library& library, |
| 47 ParsedFunction* const parsed_function, |
| 48 LocalScope* function_top) |
| 49 : preamble_(preamble), |
| 50 temp_cnt_(0), |
| 51 library_(library), |
| 52 parsed_function_(parsed_function), |
| 53 function_top_(function_top), |
| 54 isolate_(Isolate::Current()) { |
| 55 ASSERT(function_top_ != NULL); |
| 56 } |
| 57 |
| 45 | 58 |
| 46 AstNode* AwaitTransformer::Transform(AstNode* expr) { | 59 AstNode* AwaitTransformer::Transform(AstNode* expr) { |
| 47 expr->Visit(this); | 60 expr->Visit(this); |
| 48 return result_; | 61 return result_; |
| 49 } | 62 } |
| 50 | 63 |
| 51 | 64 |
| 52 LocalVariable* AwaitTransformer::EnsureCurrentTempVar() { | 65 LocalVariable* AwaitTransformer::EnsureCurrentTempVar() { |
| 53 const char* await_temp_prefix = ":await_temp_var_"; | 66 const char* await_temp_prefix = ":await_temp_var_"; |
| 54 const String& cnt_str = String::ZoneHandle( | 67 const String& cnt_str = String::ZoneHandle( |
| 55 I, String::NewFormatted("%s%d", await_temp_prefix, temp_cnt_)); | 68 I, String::NewFormatted("%s%d", await_temp_prefix, temp_cnt_)); |
| 56 const String& symbol = String::ZoneHandle(I, Symbols::New(cnt_str)); | 69 const String& symbol = String::ZoneHandle(I, Symbols::New(cnt_str)); |
| 57 ASSERT(!symbol.IsNull()); | 70 ASSERT(!symbol.IsNull()); |
| 58 LocalVariable* await_tmp = | 71 // Look up the variable through the preamble scope. |
| 59 parsed_function_->await_temps_scope()->LookupVariable(symbol, false); | 72 LocalVariable* await_tmp = preamble_->scope()->LookupVariable(symbol, false); |
| 60 if (await_tmp == NULL) { | 73 if (await_tmp == NULL) { |
| 61 await_tmp = new(I) LocalVariable( | 74 // If we need a new temp variable, we add it to the function's top scope. |
| 62 Scanner::kNoSourcePos, | 75 await_tmp = new (I) LocalVariable( |
| 63 symbol, | 76 Scanner::kNoSourcePos, symbol, Type::ZoneHandle(Type::DynamicType())); |
| 64 Type::ZoneHandle(I, Type::DynamicType())); | 77 function_top_->AddVariable(await_tmp); |
| 65 parsed_function_->await_temps_scope()->AddVariable(await_tmp); | 78 // After adding it to the top scope, we can look it up from the preamble. |
| 79 // The following call includes an ASSERT check. |
| 80 await_tmp = GetVariableInScope(preamble_->scope(), symbol); |
| 66 } | 81 } |
| 67 return await_tmp; | 82 return await_tmp; |
| 68 } | 83 } |
| 69 | 84 |
| 70 | 85 |
| 86 LocalVariable* AwaitTransformer::GetVariableInScope(LocalScope* scope, |
| 87 const String& symbol) { |
| 88 LocalVariable* var = scope->LookupVariable(symbol, false); |
| 89 ASSERT(var != NULL); |
| 90 return var; |
| 91 } |
| 92 |
| 93 |
| 71 LocalVariable* AwaitTransformer::AddToPreambleNewTempVar(AstNode* node) { | 94 LocalVariable* AwaitTransformer::AddToPreambleNewTempVar(AstNode* node) { |
| 72 LocalVariable* tmp_var = EnsureCurrentTempVar(); | 95 LocalVariable* tmp_var = EnsureCurrentTempVar(); |
| 73 preamble_->Add(new(I) StoreLocalNode(Scanner::kNoSourcePos, tmp_var, node)); | 96 preamble_->Add(new(I) StoreLocalNode(Scanner::kNoSourcePos, tmp_var, node)); |
| 74 NextTempVar(); | 97 NextTempVar(); |
| 75 return tmp_var; | 98 return tmp_var; |
| 76 } | 99 } |
| 77 | 100 |
| 78 | 101 |
| 79 void AwaitTransformer::VisitLiteralNode(LiteralNode* node) { | 102 void AwaitTransformer::VisitLiteralNode(LiteralNode* node) { |
| 80 result_ = node; | 103 result_ = node; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 93 // :result_param = :await_temp_var_X; | 116 // :result_param = :await_temp_var_X; |
| 94 // if (:result_param is Future) { | 117 // if (:result_param is Future) { |
| 95 // AwaitMarker(kNewContinuationState); | 118 // AwaitMarker(kNewContinuationState); |
| 96 // :result_param.then(:async_op); | 119 // :result_param.then(:async_op); |
| 97 // return; // (return_type() == kContinuation) | 120 // return; // (return_type() == kContinuation) |
| 98 // } | 121 // } |
| 99 // AwaitMarker(kTargetForContinuation); // Join happens here. | 122 // AwaitMarker(kTargetForContinuation); // Join happens here. |
| 100 // :saved_try_ctx_var = :await_saved_try_ctx_var_y; | 123 // :saved_try_ctx_var = :await_saved_try_ctx_var_y; |
| 101 // :await_temp_var_(X+1) = :result_param; | 124 // :await_temp_var_(X+1) = :result_param; |
| 102 | 125 |
| 103 LocalVariable* async_op = preamble_->scope()->LookupVariable( | 126 LocalVariable* async_op = GetVariableInScope( |
| 104 Symbols::AsyncOperation(), false); | 127 preamble_->scope(), Symbols::AsyncOperation()); |
| 105 ASSERT(async_op != NULL); | 128 LocalVariable* result_param = GetVariableInScope( |
| 106 LocalVariable* result_param = preamble_->scope()->LookupVariable( | 129 preamble_->scope(), Symbols::AsyncOperationParam()); |
| 107 Symbols::AsyncOperationParam(), false); | |
| 108 ASSERT(result_param != NULL); | |
| 109 | 130 |
| 110 node->expr()->Visit(this); | 131 node->expr()->Visit(this); |
| 111 preamble_->Add(new(I) StoreLocalNode( | 132 preamble_->Add(new(I) StoreLocalNode( |
| 112 Scanner::kNoSourcePos, result_param, result_)); | 133 Scanner::kNoSourcePos, result_param, result_)); |
| 113 LoadLocalNode* load_result_param = new(I) LoadLocalNode( | 134 LoadLocalNode* load_result_param = new(I) LoadLocalNode( |
| 114 Scanner::kNoSourcePos, result_param); | 135 Scanner::kNoSourcePos, result_param); |
| 115 SequenceNode* is_future_branch = new(I) SequenceNode( | 136 LocalScope* is_future_scope = ChainNewScope(preamble_->scope()); |
| 116 Scanner::kNoSourcePos, preamble_->scope()); | 137 SequenceNode* is_future_branch = new (I) SequenceNode( |
| 117 AwaitMarkerNode* await_marker = | 138 Scanner::kNoSourcePos, is_future_scope); |
| 118 new(I) AwaitMarkerNode(AwaitMarkerNode::kNewContinuationState); | 139 AwaitMarkerNode* await_marker = new (I) AwaitMarkerNode( |
| 119 await_marker->set_scope(preamble_->scope()); | 140 AwaitMarkerNode::kNewContinuationState); |
| 141 await_marker->set_scope(is_future_scope); |
| 142 GetVariableInScope(is_future_scope, Symbols::AwaitJumpVar()); |
| 143 GetVariableInScope(is_future_scope, Symbols::AwaitContextVar()); |
| 120 is_future_branch->Add(await_marker); | 144 is_future_branch->Add(await_marker); |
| 121 ArgumentListNode* args = new(I) ArgumentListNode(Scanner::kNoSourcePos); | 145 ArgumentListNode* args = new(I) ArgumentListNode(Scanner::kNoSourcePos); |
| 122 args->Add(new(I) LoadLocalNode(Scanner::kNoSourcePos, async_op)); | 146 args->Add(new(I) LoadLocalNode(Scanner::kNoSourcePos, async_op)); |
| 123 is_future_branch->Add(new(I) InstanceCallNode( | 147 is_future_branch->Add(new(I) InstanceCallNode( |
| 124 Scanner::kNoSourcePos, load_result_param, Symbols::FutureThen(), args)); | 148 Scanner::kNoSourcePos, load_result_param, Symbols::FutureThen(), args)); |
| 125 ReturnNode* continuation_return = new(I) ReturnNode(Scanner::kNoSourcePos); | 149 ReturnNode* continuation_return = new(I) ReturnNode(Scanner::kNoSourcePos); |
| 126 continuation_return->set_return_type(ReturnNode::kContinuation); | 150 continuation_return->set_return_type(ReturnNode::kContinuation); |
| 127 is_future_branch->Add(continuation_return); | 151 is_future_branch->Add(continuation_return); |
| 128 | 152 |
| 129 const Class& cls = Class::ZoneHandle( | 153 const Class& cls = Class::ZoneHandle( |
| 130 I, library_.LookupClass(Symbols::Future())); | 154 I, library_.LookupClass(Symbols::Future())); |
| 131 const AbstractType& future_type = AbstractType::ZoneHandle(I, cls.RareType()); | 155 const AbstractType& future_type = AbstractType::ZoneHandle(I, cls.RareType()); |
| 132 ASSERT(!future_type.IsNull()); | 156 ASSERT(!future_type.IsNull()); |
| 133 preamble_->Add(new(I) IfNode( | 157 preamble_->Add(new(I) IfNode( |
| 134 Scanner::kNoSourcePos, | 158 Scanner::kNoSourcePos, |
| 135 new (I) ComparisonNode( | 159 new (I) ComparisonNode( |
| 136 Scanner::kNoSourcePos, | 160 Scanner::kNoSourcePos, |
| 137 Token::kIS, | 161 Token::kIS, |
| 138 load_result_param, | 162 load_result_param, |
| 139 new (I) TypeNode(Scanner::kNoSourcePos, future_type)), | 163 new (I) TypeNode(Scanner::kNoSourcePos, future_type)), |
| 140 is_future_branch, | 164 is_future_branch, |
| 141 NULL)); | 165 NULL)); |
| 142 preamble_->Add(new (I) AwaitMarkerNode( | 166 preamble_->Add(new (I) AwaitMarkerNode( |
| 143 AwaitMarkerNode::kTargetForContinuation)); | 167 AwaitMarkerNode::kTargetForContinuation)); |
| 168 |
| 144 // If this expression is part of a try block, also append the code for | 169 // 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. | 170 // restoring the saved try context that lives on the stack. |
| 146 if (parsed_function_->saved_try_ctx() != NULL) { | 171 const String& async_saved_try_ctx_name = |
| 172 String::Handle(I, parsed_function_->async_saved_try_ctx_name()); |
| 173 if (!async_saved_try_ctx_name.IsNull()) { |
| 174 LocalVariable* async_saved_try_ctx = |
| 175 GetVariableInScope(preamble_->scope(), async_saved_try_ctx_name); |
| 147 preamble_->Add(new (I) StoreLocalNode( | 176 preamble_->Add(new (I) StoreLocalNode( |
| 148 Scanner::kNoSourcePos, | 177 Scanner::kNoSourcePos, |
| 149 parsed_function_->saved_try_ctx(), | 178 parsed_function_->saved_try_ctx(), |
| 150 new (I) LoadLocalNode( | 179 new (I) LoadLocalNode(Scanner::kNoSourcePos, async_saved_try_ctx))); |
| 151 Scanner::kNoSourcePos, parsed_function_->async_saved_try_ctx()))); | |
| 152 } | 180 } |
| 153 | 181 |
| 154 LocalVariable* result = AddToPreambleNewTempVar(new(I) LoadLocalNode( | 182 LocalVariable* result = AddToPreambleNewTempVar(new(I) LoadLocalNode( |
| 155 Scanner::kNoSourcePos, result_param)); | 183 Scanner::kNoSourcePos, result_param)); |
| 156 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); | 184 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 157 } | 185 } |
| 158 | 186 |
| 159 | 187 |
| 160 // Transforms boolean expressions into a sequence of evaluatons that only lazily | 188 // Transforms boolean expressions into a sequence of evaluatons that only lazily |
| 161 // evaluate subexpressions. | 189 // evaluate subexpressions. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 172 // } | 200 // } |
| 173 // t_3 = t_1 || t_2; // Compiler takes care that lazy evaluation takes place | 201 // t_3 = t_1 || t_2; // Compiler takes care that lazy evaluation takes place |
| 174 // on this level. | 202 // on this level. |
| 175 AstNode* AwaitTransformer::LazyTransform(const Token::Kind logical_op, | 203 AstNode* AwaitTransformer::LazyTransform(const Token::Kind logical_op, |
| 176 AstNode* new_left, | 204 AstNode* new_left, |
| 177 AstNode* right) { | 205 AstNode* right) { |
| 178 ASSERT(logical_op == Token::kAND || logical_op == Token::kOR); | 206 ASSERT(logical_op == Token::kAND || logical_op == Token::kOR); |
| 179 AstNode* result = NULL; | 207 AstNode* result = NULL; |
| 180 const Token::Kind compare_logical_op = (logical_op == Token::kAND) ? | 208 const Token::Kind compare_logical_op = (logical_op == Token::kAND) ? |
| 181 Token::kEQ : Token::kNE; | 209 Token::kEQ : Token::kNE; |
| 182 SequenceNode* eval = new(I) SequenceNode( | 210 SequenceNode* eval = new (I) SequenceNode( |
| 183 Scanner::kNoSourcePos, preamble_->scope()); | 211 Scanner::kNoSourcePos, ChainNewScope(preamble_->scope())); |
| 184 SequenceNode* saved_preamble = preamble_; | 212 SequenceNode* saved_preamble = preamble_; |
| 185 preamble_ = eval; | 213 preamble_ = eval; |
| 186 result = Transform(right); | 214 result = Transform(right); |
| 187 preamble_ = saved_preamble; | 215 preamble_ = saved_preamble; |
| 188 IfNode* right_body = new(I) IfNode( | 216 IfNode* right_body = new(I) IfNode( |
| 189 Scanner::kNoSourcePos, | 217 Scanner::kNoSourcePos, |
| 190 new(I) ComparisonNode( | 218 new(I) ComparisonNode( |
| 191 Scanner::kNoSourcePos, | 219 Scanner::kNoSourcePos, |
| 192 compare_logical_op, | 220 compare_logical_op, |
| 193 new_left, | 221 new_left, |
| 194 new(I) LiteralNode(Scanner::kNoSourcePos, Bool::True())), | 222 new(I) LiteralNode(Scanner::kNoSourcePos, Bool::True())), |
| 195 eval, | 223 eval, |
| 196 NULL); | 224 NULL); |
| 197 preamble_->Add(right_body); | 225 preamble_->Add(right_body); |
| 198 return result; | 226 return result; |
| 199 } | 227 } |
| 200 | 228 |
| 201 | 229 |
| 230 LocalScope* AwaitTransformer::ChainNewScope(LocalScope* parent) { |
| 231 return new (I) LocalScope( |
| 232 parent, parent->function_level(), parent->loop_level()); |
| 233 } |
| 234 |
| 235 |
| 202 void AwaitTransformer::VisitBinaryOpNode(BinaryOpNode* node) { | 236 void AwaitTransformer::VisitBinaryOpNode(BinaryOpNode* node) { |
| 203 node->left()->Visit(this); | 237 node->left()->Visit(this); |
| 204 AstNode* new_left = result_; | 238 AstNode* new_left = result_; |
| 205 AstNode* new_right = NULL; | 239 AstNode* new_right = NULL; |
| 206 // Preserve lazy evaluaton. | 240 // Preserve lazy evaluaton. |
| 207 if ((node->kind() == Token::kAND) || (node->kind() == Token::kOR)) { | 241 if ((node->kind() == Token::kAND) || (node->kind() == Token::kOR)) { |
| 208 new_right = LazyTransform(node->kind(), new_left, node->right()); | 242 new_right = LazyTransform(node->kind(), new_left, node->right()); |
| 209 } else { | 243 } else { |
| 210 new_right = Transform(node->right()); | 244 new_right = Transform(node->right()); |
| 211 } | 245 } |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 256 LocalVariable* result = AddToPreambleNewTempVar( | 290 LocalVariable* result = AddToPreambleNewTempVar( |
| 257 new(I) UnaryOpNode(node->token_pos(), node->kind(), new_operand)); | 291 new(I) UnaryOpNode(node->token_pos(), node->kind(), new_operand)); |
| 258 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); | 292 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result); |
| 259 } | 293 } |
| 260 | 294 |
| 261 | 295 |
| 262 // ::= (<condition>) ? <true-branch> : <false-branch> | 296 // ::= (<condition>) ? <true-branch> : <false-branch> |
| 263 // | 297 // |
| 264 void AwaitTransformer::VisitConditionalExprNode(ConditionalExprNode* node) { | 298 void AwaitTransformer::VisitConditionalExprNode(ConditionalExprNode* node) { |
| 265 AstNode* new_condition = Transform(node->condition()); | 299 AstNode* new_condition = Transform(node->condition()); |
| 266 SequenceNode* new_true = new(I) SequenceNode( | 300 SequenceNode* new_true = new (I) SequenceNode( |
| 267 Scanner::kNoSourcePos, preamble_->scope()); | 301 Scanner::kNoSourcePos, ChainNewScope(preamble_->scope())); |
| 268 SequenceNode* saved_preamble = preamble_; | 302 SequenceNode* saved_preamble = preamble_; |
| 269 preamble_ = new_true; | 303 preamble_ = new_true; |
| 270 AstNode* new_true_result = Transform(node->true_expr()); | 304 AstNode* new_true_result = Transform(node->true_expr()); |
| 271 SequenceNode* new_false = new(I) SequenceNode( | 305 SequenceNode* new_false = new (I) SequenceNode( |
| 272 Scanner::kNoSourcePos, preamble_->scope()); | 306 Scanner::kNoSourcePos, ChainNewScope(preamble_->scope())); |
| 273 preamble_ = new_false; | 307 preamble_ = new_false; |
| 274 AstNode* new_false_result = Transform(node->false_expr()); | 308 AstNode* new_false_result = Transform(node->false_expr()); |
| 275 preamble_ = saved_preamble; | 309 preamble_ = saved_preamble; |
| 276 IfNode* new_if = new(I) IfNode(Scanner::kNoSourcePos, | 310 IfNode* new_if = new(I) IfNode(Scanner::kNoSourcePos, |
| 277 new_condition, | 311 new_condition, |
| 278 new_true, | 312 new_true, |
| 279 new_false); | 313 new_false); |
| 280 preamble_->Add(new_if); | 314 preamble_->Add(new_if); |
| 281 LocalVariable* result = AddToPreambleNewTempVar( | 315 LocalVariable* result = AddToPreambleNewTempVar( |
| 282 new(I) ConditionalExprNode(Scanner::kNoSourcePos, | 316 new(I) ConditionalExprNode(Scanner::kNoSourcePos, |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 505 void AwaitTransformer::VisitThrowNode(ThrowNode* node) { | 539 void AwaitTransformer::VisitThrowNode(ThrowNode* node) { |
| 506 // TODO(mlippautz): Check if relevant. | 540 // TODO(mlippautz): Check if relevant. |
| 507 AstNode* new_exception = Transform(node->exception()); | 541 AstNode* new_exception = Transform(node->exception()); |
| 508 AstNode* new_stacktrace = Transform(node->stacktrace()); | 542 AstNode* new_stacktrace = Transform(node->stacktrace()); |
| 509 result_ = new(I) ThrowNode(node->token_pos(), | 543 result_ = new(I) ThrowNode(node->token_pos(), |
| 510 new_exception, | 544 new_exception, |
| 511 new_stacktrace); | 545 new_stacktrace); |
| 512 } | 546 } |
| 513 | 547 |
| 514 } // namespace dart | 548 } // namespace dart |
| OLD | NEW |