Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(388)

Side by Side Diff: runtime/vm/ast_transformer.cc

Issue 447003003: Introduce await (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: rebase + bring up to date Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 #include "vm/ast_transformer.h"
6
7 #include "vm/parser.h"
8
9 namespace dart {
10
11 // Quick access to the locally defined isolate() method.
12 #define I (isolate())
13
14 // Nodes that are unreachable from already parsed expressions.
15 #define FOR_EACH_UNREACHABLE_NODE(V) \
16 V(Case) \
17 V(CatchClause) \
18 V(CloneContext) \
19 V(ClosureCall) \
20 V(DoWhile) \
21 V(If) \
22 V(InlinedFinally) \
23 V(For) \
24 V(Jump) \
25 V(LoadInstanceField) \
26 V(NativeBody) \
27 V(Primary) \
28 V(Return) \
29 V(Sequence) \
30 V(StoreInstanceField) \
31 V(Switch) \
32 V(TryCatch) \
33 V(While)
34
35 #define DEFINE_UNREACHABLE(BaseName) \
36 void AwaitTransformer::Visit##BaseName##Node(BaseName##Node* node) { \
37 UNREACHABLE(); \
38 }
39
40 FOR_EACH_UNREACHABLE_NODE(DEFINE_UNREACHABLE)
41 #undef DEFINE_UNREACHABLE
42
43
44 void AwaitTransformer::Transform(AstNode* expr) {
45 expr->Visit(this);
46 }
47
48
49 LocalVariable* AwaitTransformer::EnsureCurrentTempVar() {
50 const char* await_temp_prefix = ":await_temp_var_";
51 const String& cnt_str = String::Handle(
srdjan 2014/08/13 18:41:05 I,
Michael Lippautz (Google) 2014/08/13 20:32:23 Done.
52 String::NewFormatted(
53 "%s%" Pd "", await_temp_prefix, temp_cnt_));
54 const String& symbol = String::ZoneHandle(I, Symbols::New(cnt_str));
55 ASSERT(!symbol.IsNull());
56 LocalVariable* await_tmp =
57 parsed_function_->await_temps_scope()->LookupVariable(symbol, false);
58 if (await_tmp == NULL) {
59 await_tmp = new(I) LocalVariable(
60 Scanner::kNoSourcePos,
61 symbol,
62 Type::ZoneHandle(I, Type::DynamicType()));
63 parsed_function_->await_temps_scope()->AddVariable(await_tmp);
64 }
65 return await_tmp;
66 }
67
68
69 LocalVariable* AwaitTransformer::AddToPreambleNewTempVar(AstNode* node) {
70 LocalVariable* tmp_var = EnsureCurrentTempVar();
71 preamble_->Add(new(I) StoreLocalNode(Scanner::kNoSourcePos, tmp_var, node));
72 NextTempVar();
73 return tmp_var;
74 }
75
76
77 void AwaitTransformer::VisitLiteralNode(LiteralNode* node) {
78 result_ = node;
79 }
80
81
82 void AwaitTransformer::VisitTypeNode(TypeNode* node) {
83 result_ = new(I) TypeNode(node->token_pos(), node->type());
84 }
85
86
87
88 void AwaitTransformer::VisitAwaitNode(AwaitNode* node) {
89 // Await transformation:
90 //
91 // :await_temp_var_X = <expr>;
92 // :result_param = :await_temp_var_X;
93 // if (:result_param is Future) {
94 // // :result_param.then(:async_op);
95 // }
96 // :await_temp_var_(X+1) = :result_param;
97
98 LocalVariable* async_op = preamble_->scope()->LookupVariable(
99 Symbols::AsyncOperation(), false);
100 ASSERT(async_op != NULL);
101 LocalVariable* result_param = preamble_->scope()->LookupVariable(
102 Symbols::AsyncOperationParam(), false);
103 ASSERT(result_param != NULL);
104
105 node->expr()->Visit(this);
106 preamble_->Add(new(I) StoreLocalNode(Scanner::kNoSourcePos,
107 result_param,
108 result_));
109 LoadLocalNode* load_result_param = new(I) LoadLocalNode(
110 Scanner::kNoSourcePos, result_param);
111 SequenceNode* is_future_branch = new(I) SequenceNode(
112 Scanner::kNoSourcePos, preamble_->scope());
113 ArgumentListNode* args = new(I) ArgumentListNode(Scanner::kNoSourcePos);
114 args->Add(new(I) LoadLocalNode(Scanner::kNoSourcePos, async_op));
115 // TODO(mlippautz): Once continuations are supported, just call .then().
116 // is_future_branch->Add(new(I) InstanceCallNode(
117 // Scanner::kNoSourcePos, load_result_param, Symbols::FutureThen(), args));
118 //
119 // For now, throw an exception.
120 const String& exception = String::ZoneHandle(
121 I, String::New("awaitable futures not yet supported", Heap::kOld));
122 is_future_branch->Add(new(I) ThrowNode(
123 Scanner::kNoSourcePos,
124 new(I) LiteralNode(
125 Scanner::kNoSourcePos,
126 String::ZoneHandle(I, Symbols::New(exception))),
127 NULL));
128 const Class& cls = Class::Handle(library_.LookupClass(Symbols::Future()));
srdjan 2014/08/13 18:41:06 I,
Michael Lippautz (Google) 2014/08/13 20:32:23 Done.
129 const AbstractType& future_type = AbstractType::ZoneHandle(I,
130 cls.RareType());
131 ASSERT(!future_type.IsNull());
132 TypeNode* future_type_node = new(I) TypeNode(
133 Scanner::kNoSourcePos, future_type);
134 IfNode* is_future_if = new(I) IfNode(
135 Scanner::kNoSourcePos,
136 new(I) ComparisonNode(Scanner::kNoSourcePos,
137 Token::kIS,
138 load_result_param,
139 future_type_node),
140 is_future_branch,
141 NULL);
142 preamble_->Add(is_future_if);
143
144 // TODO(mlippautz): Join for await needs to happen here.
145
146 LocalVariable* result = AddToPreambleNewTempVar(new(I) LoadLocalNode(
147 Scanner::kNoSourcePos, result_param));
148 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
149 }
150
151
152 // Transforms boolean expressions into a sequence of evaluatons that only lazily
153 // evaluate subexpressions.
154 //
155 // Example:
156 //
157 // (a || b) only evaluates b if a is true
158 //
159 // Transformation (roughly):
160 //
161 // t_1 = a;
162 // if (t_1) {
163 // t_2 = b;
164 // }
165 // t_3 = t_1 || t_2; // Compiler takes care that lazy evaluation takes place
166 // on this level.
167 AstNode* AwaitTransformer::LazyTransform(const Token::Kind logical_op,
168 AstNode* new_left,
169 AstNode* right) {
170 ASSERT(logical_op == Token::kAND || logical_op == Token::kOR);
171 AstNode* result = NULL;
172 const Token::Kind compare_logical_op = (logical_op == Token::kAND) ?
173 Token::kEQ : Token::kNE;
174 SequenceNode* eval = new SequenceNode(
srdjan 2014/08/13 18:41:06 new (I)
Michael Lippautz (Google) 2014/08/13 20:32:23 Done.
175 Scanner::kNoSourcePos, preamble_->scope());
176 SequenceNode* saved_preamble = preamble_;
177 preamble_ = eval;
178 right->Visit(this);
179 result = result_;
180 preamble_ = saved_preamble;
181 IfNode* right_body = new(I) IfNode(
182 Scanner::kNoSourcePos,
183 new(I) ComparisonNode(
184 Scanner::kNoSourcePos,
185 compare_logical_op,
186 new_left,
187 new(I) LiteralNode(Scanner::kNoSourcePos, Bool::True())),
188 eval,
189 NULL);
190 preamble_->Add(right_body);
191 return result;
192 }
193
194
195 void AwaitTransformer::VisitBinaryOpNode(BinaryOpNode* node) {
196 node->left()->Visit(this);
197 AstNode* new_left = result_;
198 AstNode* new_right = NULL;
199 // Preserve lazy evaluaton.
200 if (node->kind() == Token::kAND || node->kind() == Token::kOR) {
srdjan 2014/08/13 18:41:05 Use more parentheses.
Michael Lippautz (Google) 2014/08/13 20:32:23 Done.
201 new_right = LazyTransform(node->kind(), new_left, node->right());
202 } else {
203 node->right()->Visit(this);
204 new_right = result_;
205 }
206 LocalVariable* result = AddToPreambleNewTempVar(
207 new(I) BinaryOpNode(node->token_pos(),
208 node->kind(),
209 new_left,
210 new_right));
211 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
212 }
213
214
215 void AwaitTransformer::VisitBinaryOpWithMask32Node(
216 BinaryOpWithMask32Node* node) {
217 node->left()->Visit(this);
218 AstNode* new_left = result_;
219 AstNode* new_right = NULL;
220 // Preserve lazy evaluaton.
221 if (node->kind() == Token::kAND || node->kind() == Token::kOR) {
srdjan 2014/08/13 18:41:05 Use more parentheses
Michael Lippautz (Google) 2014/08/13 20:32:23 Done.
222 new_right = LazyTransform(node->kind(), new_left, node->right());
223 } else {
224 node->right()->Visit(this);
225 new_right = result_;
226 }
227 LocalVariable* result = AddToPreambleNewTempVar(
228 new(I) BinaryOpWithMask32Node(node->token_pos(),
229 node->kind(),
230 new_left,
231 new_right,
232 node->mask32()));
233 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
234 }
235
236
237 void AwaitTransformer::VisitComparisonNode(ComparisonNode* node) {
238 node->left()->Visit(this);
239 AstNode* new_left = result_;
240 node->right()->Visit(this);
241 AstNode* new_right = result_;
242 LocalVariable* result = AddToPreambleNewTempVar(
243 new(I) ComparisonNode(node->token_pos(),
244 node->kind(),
245 new_left,
246 new_right));
247 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
248 }
249
250
251 void AwaitTransformer::VisitUnaryOpNode(UnaryOpNode* node) {
252 node->operand()->Visit(this);
253 AstNode* new_operand = result_;
254
255 LocalVariable* result = AddToPreambleNewTempVar(
256 new(I) UnaryOpNode(node->token_pos(),
257 node->kind(),
258 new_operand));
259 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
260 }
261
srdjan 2014/08/13 18:41:05 two empty lines
Michael Lippautz (Google) 2014/08/13 20:32:23 Done.
262 // ::= (<condition>) ? <true-branch> : <false-branch>
263 //
264 void AwaitTransformer::VisitConditionalExprNode(ConditionalExprNode* node) {
265 // TODO(mlippautz): Optimize variable assingments and branching.
srdjan 2014/08/13 18:41:06 s/assingments/assignments/
Michael Lippautz (Google) 2014/08/13 20:32:23 Got rid of the comment as it doesn't make too much
266 node->condition()->Visit(this);
267 AstNode* new_condition = result_;
268 SequenceNode* new_true = new(I) SequenceNode(
269 Scanner::kNoSourcePos, preamble_->scope());
270 SequenceNode* saved_preamble = preamble_;
271 preamble_ = new_true;
272 node->true_expr()->Visit(this);
273 AstNode* new_true_result = result_;
274 SequenceNode* new_false = new(I) SequenceNode(
275 Scanner::kNoSourcePos, preamble_->scope());
276 preamble_ = new_false;
277 node->false_expr()->Visit(this);
278 AstNode* new_false_result = result_;
279 preamble_ = saved_preamble;
280 IfNode* new_if = new(I) IfNode(Scanner::kNoSourcePos,
281 new_condition,
282 new_true,
283 new_false);
284 preamble_->Add(new_if);
285 LocalVariable* result = AddToPreambleNewTempVar(
286 new(I) ConditionalExprNode(Scanner::kNoSourcePos,
287 new_condition,
288 new_true_result,
289 new_false_result));
290 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
291 }
292
293
294 void AwaitTransformer::VisitArgumentListNode(ArgumentListNode* node) {
295 ArgumentListNode* new_args = new(I) ArgumentListNode(node->token_pos());
296 for (intptr_t i = 0; i < node->length(); i++) {
297 node->NodeAt(i)->Visit(this);
298 new_args->Add(result_);
299 }
300 result_ = new_args;
301 }
302
303
304 void AwaitTransformer::VisitArrayNode(ArrayNode* node) {
305 GrowableArray<AstNode*> new_elements;
306 for (intptr_t i = 0; i < node->length(); i++) {
307 node->ElementAt(i)->Visit(this);
308 new_elements.Add(result_);
309 }
310 result_ = new(I) ArrayNode(node->token_pos(), node->type(), new_elements);
311 }
312
313
314 void AwaitTransformer::VisitStringInterpolateNode(StringInterpolateNode* node) {
315 node->value()->Visit(this);
316 ArrayNode* new_value = result_->AsArrayNode();
317 LocalVariable* result = AddToPreambleNewTempVar(
318 new(I) StringInterpolateNode(node->token_pos(),
319 new_value));
320 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
321 }
322
323
324 void AwaitTransformer::VisitClosureNode(ClosureNode* node) {
325 AstNode* new_receiver = node->receiver();
326 if (new_receiver != NULL) {
327 new_receiver->Visit(this);
328 new_receiver = result_;
329 }
330 LocalVariable* result = AddToPreambleNewTempVar(
331 new(I) ClosureNode(node->token_pos(),
332 node->function(),
333 new_receiver,
334 node->scope()));
335 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
336 }
337
338
339 void AwaitTransformer::VisitInstanceCallNode(InstanceCallNode* node) {
340 node->receiver()->Visit(this);
341 AstNode* new_receiver = result_;
342 node->arguments()->Visit(this);
343 ArgumentListNode* new_args = result_->AsArgumentListNode();
344
345 LocalVariable* result = AddToPreambleNewTempVar(
346 new(I) InstanceCallNode(node->token_pos(),
347 new_receiver,
348 node->function_name(),
349 new_args));
350 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
351 }
352
353
354 void AwaitTransformer::VisitStaticCallNode(StaticCallNode* node) {
355 node->arguments()->Visit(this);
356 ArgumentListNode* new_args = result_->AsArgumentListNode();
357
358 LocalVariable* result = AddToPreambleNewTempVar(
359 new(I) StaticCallNode(node->token_pos(),
360 node->function(),
361 new_args));
362 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
363 }
364
365
366 void AwaitTransformer::VisitConstructorCallNode(ConstructorCallNode* node) {
367 node->arguments()->Visit(this);
368 ArgumentListNode* new_args = result_->AsArgumentListNode();
369
370 LocalVariable* result = AddToPreambleNewTempVar(
371 new(I) ConstructorCallNode(node->token_pos(),
372 node->type_arguments(),
373 node->constructor(),
374 new_args));
375 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
376 }
377
378
379 void AwaitTransformer::VisitInstanceGetterNode(InstanceGetterNode* node) {
380 node->receiver()->Visit(this);
381 AstNode* new_receiver = result_;
382
383 LocalVariable* result = AddToPreambleNewTempVar(
384 new(I) InstanceGetterNode(node->token_pos(),
385 new_receiver,
386 node->field_name()));
387 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
388 }
389
390
391 void AwaitTransformer::VisitInstanceSetterNode(InstanceSetterNode* node) {
392 AstNode* new_receiver = node->receiver();
393 if (new_receiver != NULL) {
394 new_receiver->Visit(this);
395 new_receiver = result_;
396 }
397
398 node->value()->Visit(this);
399 AstNode* new_value = result_;
400
401 LocalVariable* result = AddToPreambleNewTempVar(
402 new(I) InstanceSetterNode(node->token_pos(),
403 new_receiver,
404 node->field_name(),
405 new_value));
406 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
407 }
408
409
410 void AwaitTransformer::VisitStaticGetterNode(StaticGetterNode* node) {
411 AstNode* new_receiver = node->receiver();
412 if (new_receiver != NULL) {
413 new_receiver->Visit(this);
414 new_receiver = result_;
415 }
416
417 LocalVariable* result = AddToPreambleNewTempVar(
418 new(I) StaticGetterNode(node->token_pos(),
419 new_receiver,
420 node->is_super_getter(),
421 node->cls(),
422 node->field_name()));
423 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
424 }
425
426
427 void AwaitTransformer::VisitStaticSetterNode(StaticSetterNode* node) {
428 AstNode* new_receiver = node->receiver();
429 if (new_receiver != NULL) {
430 new_receiver->Visit(this);
431 new_receiver = result_;
432 }
433 node->value()->Visit(this);
434 AstNode* new_value = result_;
435
436 LocalVariable* result = AddToPreambleNewTempVar(
437 new(I) StaticSetterNode(node->token_pos(),
438 new_receiver,
439 node->cls(),
440 node->field_name(),
441 new_value));
442 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
443 }
444
445
446 void AwaitTransformer::VisitLoadLocalNode(LoadLocalNode* node) {
447 LocalVariable* result = AddToPreambleNewTempVar(
448 new(I) LoadLocalNode(node->token_pos(), &node->local()));
449 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
450 }
451
452
453 void AwaitTransformer::VisitStoreLocalNode(StoreLocalNode* node) {
454 node->value()->Visit(this);
455 AstNode* new_value = result_;
456 LocalVariable* result = AddToPreambleNewTempVar(
457 new(I) StoreLocalNode(node->token_pos(),
458 &node->local(),
459 new_value));
460 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
461 }
462
463
464 void AwaitTransformer::VisitLoadStaticFieldNode(LoadStaticFieldNode* node) {
465 LocalVariable* result = AddToPreambleNewTempVar(
466 new(I) LoadStaticFieldNode(node->token_pos(),
467 node->field()));
468 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
469 }
470
471
472 void AwaitTransformer::VisitStoreStaticFieldNode(StoreStaticFieldNode* node) {
473 node->value()->Visit(this);
474 AstNode* new_value = result_;
475 LocalVariable* result = AddToPreambleNewTempVar(
476 new(I) StoreStaticFieldNode(node->token_pos(),
477 node->field(),
478 new_value));
479 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
480 }
481
482
483 void AwaitTransformer::VisitLoadIndexedNode(LoadIndexedNode* node) {
484 node->array()->Visit(this);
485 AstNode* new_array = result_;
486 node->index_expr()->Visit(this);
487 AstNode* new_index = result_;
488 LocalVariable* result = AddToPreambleNewTempVar(
489 new(I) LoadIndexedNode(node->token_pos(),
490 new_array,
491 new_index,
492 node->super_class()));
493 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
494 }
495
496
497 void AwaitTransformer::VisitStoreIndexedNode(StoreIndexedNode* node) {
498 node->array()->Visit(this);
499 AstNode* new_array = result_;
500 node->index_expr()->Visit(this);
501 AstNode* new_index = result_;
502 node->value()->Visit(this);
503 AstNode* new_value = result_;
504 LocalVariable* result = AddToPreambleNewTempVar(
505 new(I) StoreIndexedNode(node->token_pos(),
506 new_array,
507 new_index,
508 new_value,
509 node->super_class()));
510 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
511 }
512
513
514 void AwaitTransformer::VisitAssignableNode(AssignableNode* node) {
515 node->expr()->Visit(this);
516 AstNode* new_expr = result_;
517 LocalVariable* result = AddToPreambleNewTempVar(
518 new(I) AssignableNode(node->token_pos(),
519 new_expr,
520 node->type(),
521 node->dst_name()));
522 result_ = new(I) LoadLocalNode(Scanner::kNoSourcePos, result);
523 }
524
525
526 void AwaitTransformer::VisitLetNode(LetNode* node) {
527 // TODO(mlippautz): Check initializers and their temps.
528 LetNode* result = new(I) LetNode(node->token_pos());
529 for (intptr_t i = 0; i < node->nodes().length(); i++) {
530 node->nodes()[i]->Visit(this);
531 result->AddNode(result_);
532 }
533 result_ = result;
534 }
535
536
537 void AwaitTransformer::VisitThrowNode(ThrowNode* node) {
538 // TODO(mlippautz): Check if relevant.
539 node->exception()->Visit(this);
540 AstNode* new_exception = result_;
541 node->stacktrace()->Visit(this);
542 AstNode* new_stacktrace = result_;
543 result_ = new(I) ThrowNode(node->token_pos(),
544 new_exception,
545 new_stacktrace);
546 }
547
548 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698