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 |