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

Side by Side Diff: pkg/kernel/lib/transformations/async.dart

Issue 2561723003: Merge kernel closure conversion into the Dart SDK (Closed)
Patch Set: Remove path constraint Created 4 years 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
OLDNEW
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, 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 library kernel.transformations.async; 5 library kernel.transformations.async;
6 6
7 import '../kernel.dart'; 7 import '../kernel.dart';
8 import 'continuation.dart'; 8 import 'continuation.dart';
9 9
10 /// A transformer that introduces temporary variables for all subexpressions 10 /// A transformer that introduces temporary variables for all subexpressions
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
49 /// If an expression should be named it is named before visiting its children 49 /// If an expression should be named it is named before visiting its children
50 /// so the naming assignment appears in the list before all statements 50 /// so the naming assignment appears in the list before all statements
51 /// implementating the translation of the children. 51 /// implementating the translation of the children.
52 /// 52 ///
53 /// Children that are conditionally evaluated, such as some parts of logical 53 /// Children that are conditionally evaluated, such as some parts of logical
54 /// and conditional expressions, must be delimited so that they do not emit 54 /// and conditional expressions, must be delimited so that they do not emit
55 /// unguarded statements into [statements]. This is implemented by setting 55 /// unguarded statements into [statements]. This is implemented by setting
56 /// [statements] to a fresh empty list before transforming those children. 56 /// [statements] to a fresh empty list before transforming those children.
57 List<Statement> statements = <Statement>[]; 57 List<Statement> statements = <Statement>[];
58 58
59
60 /// The number of currently live named intermediate values. 59 /// The number of currently live named intermediate values.
61 /// 60 ///
62 /// This index is used to allocate names to temporary values. Because 61 /// This index is used to allocate names to temporary values. Because
63 /// children are visited right-to-left, names are assigned in reverse order of 62 /// children are visited right-to-left, names are assigned in reverse order of
64 /// index. 63 /// index.
65 /// 64 ///
66 /// When an assignment is emitted into [statements] to name an expression 65 /// When an assignment is emitted into [statements] to name an expression
67 /// before visiting its children, the index is not immediately reserved 66 /// before visiting its children, the index is not immediately reserved
68 /// because a child can freely use the same name as its parent. In practice, 67 /// because a child can freely use the same name as its parent. In practice,
69 /// this will be the rightmost named child. 68 /// this will be the rightmost named child.
70 /// 69 ///
71 /// After visiting the children of a named expression, [nameIndex] is set to 70 /// After visiting the children of a named expression, [nameIndex] is set to
72 /// indicate one more live value (the value of the expression) than before 71 /// indicate one more live value (the value of the expression) than before
73 /// visiting the expression. 72 /// visiting the expression.
74 /// 73 ///
75 /// After visiting the children of an expression that is not named, 74 /// After visiting the children of an expression that is not named,
76 /// [nameIndex] may still account for names of subexpressions. 75 /// [nameIndex] may still account for names of subexpressions.
77 int nameIndex = 0; 76 int nameIndex = 0;
78 77
79 final VariableDeclaration asyncResult = 78 final VariableDeclaration asyncResult = new VariableDeclaration(':result');
80 new VariableDeclaration(':result');
81 final List<VariableDeclaration> variables = <VariableDeclaration>[]; 79 final List<VariableDeclaration> variables = <VariableDeclaration>[];
82 80
83 ExpressionLifter(this.continuationRewriter); 81 ExpressionLifter(this.continuationRewriter);
84 82
85 Block blockOf(List<Statement> stmts) => new Block(stmts.reversed.toList()); 83 Block blockOf(List<Statement> stmts) => new Block(stmts.reversed.toList());
86 84
87 /// Rewrite a toplevel expression (toplevel wrt. a statement). 85 /// Rewrite a toplevel expression (toplevel wrt. a statement).
88 /// 86 ///
89 /// Rewriting an expression produces a sequence of statements and an 87 /// Rewriting an expression produces a sequence of statements and an
90 /// expression. The sequence of statements are added to the given list. Pass 88 /// expression. The sequence of statements are added to the given list. Pass
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 var shouldName = seenAwait; 167 var shouldName = seenAwait;
170 168
171 // 1. If there is an await in a sibling to the right, emit an assignment to 169 // 1. If there is an await in a sibling to the right, emit an assignment to
172 // a temporary variable before transforming the children. 170 // a temporary variable before transforming the children.
173 var result = shouldName ? name(expr) : expr; 171 var result = shouldName ? name(expr) : expr;
174 172
175 // 2. Remember the number of live temporaries before transforming the 173 // 2. Remember the number of live temporaries before transforming the
176 // children. 174 // children.
177 var index = nameIndex; 175 var index = nameIndex;
178 176
179
180 // 3. Transform the children. Initially they do not have an await in a 177 // 3. Transform the children. Initially they do not have an await in a
181 // sibling to their right. 178 // sibling to their right.
182 seenAwait = false; 179 seenAwait = false;
183 action(); 180 action();
184 181
185
186 // 4. If the expression was named then the variables used for children are 182 // 4. If the expression was named then the variables used for children are
187 // no longer live but the variable used for the expression is. 183 // no longer live but the variable used for the expression is.
188 if (shouldName) { 184 if (shouldName) {
189 nameIndex = index + 1; 185 nameIndex = index + 1;
190 seenAwait = true; 186 seenAwait = true;
191 } 187 }
192 return result; 188 return result;
193 } 189 }
194 190
195 // Unary expressions. 191 // Unary expressions.
196 Expression unary(Expression expr) { 192 Expression unary(Expression expr) {
197 return transform(expr, () { expr.transformChildren(this); }); 193 return transform(expr, () {
194 expr.transformChildren(this);
195 });
198 } 196 }
199 197
200 TreeNode visitVariableSet(VariableSet expr) => unary(expr); 198 TreeNode visitVariableSet(VariableSet expr) => unary(expr);
201 TreeNode visitPropertyGet(PropertyGet expr) => unary(expr); 199 TreeNode visitPropertyGet(PropertyGet expr) => unary(expr);
202 TreeNode visitDirectPropertyGet(DirectPropertyGet expr) => unary(expr); 200 TreeNode visitDirectPropertyGet(DirectPropertyGet expr) => unary(expr);
203 TreeNode visitSuperPropertySet(SuperPropertySet expr) => unary(expr); 201 TreeNode visitSuperPropertySet(SuperPropertySet expr) => unary(expr);
204 TreeNode visitStaticSet(StaticSet expr) => unary(expr); 202 TreeNode visitStaticSet(StaticSet expr) => unary(expr);
205 TreeNode visitNot(Not expr) => unary(expr); 203 TreeNode visitNot(Not expr) => unary(expr);
206 TreeNode visitIsExpression(IsExpression expr) => unary(expr); 204 TreeNode visitIsExpression(IsExpression expr) => unary(expr);
207 TreeNode visitAsExpression(AsExpression expr) => unary(expr); 205 TreeNode visitAsExpression(AsExpression expr) => unary(expr);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
242 } 240 }
243 241
244 TreeNode visitDirectMethodInvocation(DirectMethodInvocation expr) { 242 TreeNode visitDirectMethodInvocation(DirectMethodInvocation expr) {
245 return transform(expr, () { 243 return transform(expr, () {
246 visitArguments(expr.arguments); 244 visitArguments(expr.arguments);
247 expr.receiver = expr.receiver.accept(this)..parent = expr; 245 expr.receiver = expr.receiver.accept(this)..parent = expr;
248 }); 246 });
249 } 247 }
250 248
251 TreeNode visitSuperMethodInvocation(SuperMethodInvocation expr) { 249 TreeNode visitSuperMethodInvocation(SuperMethodInvocation expr) {
252 return transform(expr, () { visitArguments(expr.arguments); }); 250 return transform(expr, () {
251 visitArguments(expr.arguments);
252 });
253 } 253 }
254 254
255 TreeNode visitStaticInvocation(StaticInvocation expr) { 255 TreeNode visitStaticInvocation(StaticInvocation expr) {
256 return transform(expr, () { visitArguments(expr.arguments); }); 256 return transform(expr, () {
257 visitArguments(expr.arguments);
258 });
257 } 259 }
258 260
259 TreeNode visitConstructorInvocation(ConstructorInvocation expr) { 261 TreeNode visitConstructorInvocation(ConstructorInvocation expr) {
260 return transform(expr, () { visitArguments(expr.arguments); }); 262 return transform(expr, () {
263 visitArguments(expr.arguments);
264 });
261 } 265 }
262 266
263 TreeNode visitStringConcatenation(StringConcatenation expr) { 267 TreeNode visitStringConcatenation(StringConcatenation expr) {
264 return transform(expr, () { 268 return transform(expr, () {
265 var expressions = expr.expressions; 269 var expressions = expr.expressions;
266 for (var i = expressions.length - 1; i >= 0; --i) { 270 for (var i = expressions.length - 1; i >= 0; --i) {
267 expressions[i] = expressions[i].accept(this)..parent = expr; 271 expressions[i] = expressions[i].accept(this)..parent = expr;
268 } 272 }
269 }); 273 });
270 } 274 }
(...skipping 17 matching lines...) Expand all
288 } 292 }
289 293
290 // Control flow. 294 // Control flow.
291 TreeNode visitLogicalExpression(LogicalExpression expr) { 295 TreeNode visitLogicalExpression(LogicalExpression expr) {
292 var shouldName = seenAwait; 296 var shouldName = seenAwait;
293 297
294 // Right is delimited because it is conditionally evaluated. 298 // Right is delimited because it is conditionally evaluated.
295 var rightStatements = <Statement>[]; 299 var rightStatements = <Statement>[];
296 seenAwait = false; 300 seenAwait = false;
297 expr.right = delimit(() => expr.right.accept(this), rightStatements) 301 expr.right = delimit(() => expr.right.accept(this), rightStatements)
298 ..parent = expr; 302 ..parent = expr;
299 var rightAwait = seenAwait; 303 var rightAwait = seenAwait;
300 304
301 if (rightStatements.isEmpty) { 305 if (rightStatements.isEmpty) {
302 // Easy case: right did not emit any statements. 306 // Easy case: right did not emit any statements.
303 seenAwait = shouldName; 307 seenAwait = shouldName;
304 return transform(expr, () { 308 return transform(expr, () {
305 expr.left = expr.left.accept(this)..parent = expr; 309 expr.left = expr.left.accept(this)..parent = expr;
306 seenAwait = seenAwait || rightAwait; 310 seenAwait = seenAwait || rightAwait;
307 }); 311 });
308 } 312 }
309 313
310 // If right has emitted statements we will produce a temporary t and emit 314 // If right has emitted statements we will produce a temporary t and emit
311 // for && (there is an analogous case for ||): 315 // for && (there is an analogous case for ||):
312 // 316 //
313 // t = [left] == true; 317 // t = [left] == true;
314 // if (t) { 318 // if (t) {
315 // t = [right] == true; 319 // t = [right] == true;
316 // } 320 // }
317 321
318 // Recall that statements are emitted in reverse order, so first emit the if 322 // Recall that statements are emitted in reverse order, so first emit the if
319 // statement, then the assignment of [left] == true, and then translate left 323 // statement, then the assignment of [left] == true, and then translate left
320 // so any statements it emits occur after in the accumulated list (that is, 324 // so any statements it emits occur after in the accumulated list (that is,
321 // so they occur before in the corresponding block). 325 // so they occur before in the corresponding block).
322 var rightBody = blockOf(rightStatements); 326 var rightBody = blockOf(rightStatements);
323 var result = allocateTemporary(nameIndex); 327 var result = allocateTemporary(nameIndex);
324 rightBody.addStatement(new ExpressionStatement( 328 rightBody.addStatement(new ExpressionStatement(new VariableSet(
325 new VariableSet( 329 result,
326 result, 330 new MethodInvocation(expr.right, new Name('=='),
327 new MethodInvocation( 331 new Arguments(<Expression>[new BoolLiteral(true)])))));
328 expr.right,
329 new Name('=='),
330 new Arguments(<Expression>[new BoolLiteral(true)])))));
331 var then, otherwise; 332 var then, otherwise;
332 if (expr.operator == '&&') { 333 if (expr.operator == '&&') {
333 then = rightBody; 334 then = rightBody;
334 otherwise = null; 335 otherwise = null;
335 } else { 336 } else {
336 then = new EmptyStatement(); 337 then = new EmptyStatement();
337 otherwise = rightBody; 338 otherwise = rightBody;
338 } 339 }
339 statements.add(new IfStatement(new VariableGet(result), then, otherwise)); 340 statements.add(new IfStatement(new VariableGet(result), then, otherwise));
340 341
341 var test = 342 var test = new MethodInvocation(expr.left, new Name('=='),
342 new MethodInvocation( 343 new Arguments(<Expression>[new BoolLiteral(true)]));
343 expr.left, 344 statements.add(new ExpressionStatement(new VariableSet(result, test)));
344 new Name('=='),
345 new Arguments(<Expression>[new BoolLiteral(true)]));
346 statements.add(
347 new ExpressionStatement(new VariableSet(result, test)));
348 345
349 seenAwait = false; 346 seenAwait = false;
350 test.receiver = test.receiver.accept(this)..parent = test; 347 test.receiver = test.receiver.accept(this)..parent = test;
351 348
352 ++nameIndex; 349 ++nameIndex;
353 seenAwait = seenAwait || rightAwait; 350 seenAwait = seenAwait || rightAwait;
354 return new VariableGet(result); 351 return new VariableGet(result);
355 } 352 }
356 353
357 TreeNode visitConditionalExpression(ConditionalExpression expr) { 354 TreeNode visitConditionalExpression(ConditionalExpression expr) {
358 // Then and otherwise are delimited because they are conditionally 355 // Then and otherwise are delimited because they are conditionally
359 // evaluated. 356 // evaluated.
360 var shouldName = seenAwait; 357 var shouldName = seenAwait;
361 358
362 var thenStatements = <Statement>[]; 359 var thenStatements = <Statement>[];
363 seenAwait = false; 360 seenAwait = false;
364 expr.then = delimit(() => expr.then.accept(this), thenStatements) 361 expr.then = delimit(() => expr.then.accept(this), thenStatements)
365 ..parent = expr; 362 ..parent = expr;
366 var thenAwait = seenAwait; 363 var thenAwait = seenAwait;
367 364
368 var otherwiseStatements = <Statement>[]; 365 var otherwiseStatements = <Statement>[];
369 seenAwait = false; 366 seenAwait = false;
370 expr.otherwise = delimit(() => expr.otherwise.accept(this), 367 expr.otherwise =
371 otherwiseStatements)..parent = expr; 368 delimit(() => expr.otherwise.accept(this), otherwiseStatements)
369 ..parent = expr;
372 var otherwiseAwait = seenAwait; 370 var otherwiseAwait = seenAwait;
373 371
374 if (thenStatements.isEmpty && otherwiseStatements.isEmpty) { 372 if (thenStatements.isEmpty && otherwiseStatements.isEmpty) {
375 // Easy case: neither then nor otherwise emitted any statements. 373 // Easy case: neither then nor otherwise emitted any statements.
376 seenAwait = shouldName; 374 seenAwait = shouldName;
377 return transform(expr, () { 375 return transform(expr, () {
378 expr.condition = expr.condition.accept(this)..parent = expr; 376 expr.condition = expr.condition.accept(this)..parent = expr;
379 seenAwait = seenAwait || thenAwait || otherwiseAwait; 377 seenAwait = seenAwait || thenAwait || otherwiseAwait;
380 }); 378 });
381 } 379 }
(...skipping 27 matching lines...) Expand all
409 // Others. 407 // Others.
410 TreeNode visitAwaitExpression(AwaitExpression expr) { 408 TreeNode visitAwaitExpression(AwaitExpression expr) {
411 final R = continuationRewriter; 409 final R = continuationRewriter;
412 var shouldName = seenAwait; 410 var shouldName = seenAwait;
413 var result = new VariableGet(asyncResult); 411 var result = new VariableGet(asyncResult);
414 // The statements are in reverse order, so name the result first if 412 // The statements are in reverse order, so name the result first if
415 // necessary and then add the two other statements in reverse. 413 // necessary and then add the two other statements in reverse.
416 if (shouldName) result = name(result); 414 if (shouldName) result = name(result);
417 statements.add(R.createContinuationPoint()); 415 statements.add(R.createContinuationPoint());
418 Arguments arguments = new Arguments(<Expression>[ 416 Arguments arguments = new Arguments(<Expression>[
419 expr.operand, 417 expr.operand,
420 new VariableGet(R.thenContinuationVariable), 418 new VariableGet(R.thenContinuationVariable),
421 new VariableGet(R.catchErrorContinuationVariable)]); 419 new VariableGet(R.catchErrorContinuationVariable)
420 ]);
422 statements.add(new ExpressionStatement( 421 statements.add(new ExpressionStatement(
423 new StaticInvocation(R.helper.awaitHelper, arguments))); 422 new StaticInvocation(R.helper.awaitHelper, arguments)));
424 423
425 seenAwait = false; 424 seenAwait = false;
426 var index = nameIndex; 425 var index = nameIndex;
427 arguments.positional[0] = expr.operand.accept(this)..parent = arguments; 426 arguments.positional[0] = expr.operand.accept(this)..parent = arguments;
428 427
429 if (shouldName) nameIndex = index + 1; 428 if (shouldName) nameIndex = index + 1;
430 seenAwait = true; 429 seenAwait = true;
431 return result; 430 return result;
(...skipping 22 matching lines...) Expand all
454 // and return the body's value. 453 // and return the body's value.
455 // 454 //
456 // So x is in scope for all the body's statements and the body's value. 455 // So x is in scope for all the body's statements and the body's value.
457 // This has the unpleasant consequence that all let-bound variables with 456 // This has the unpleasant consequence that all let-bound variables with
458 // await in the let's body will end up hoisted out the the expression and 457 // await in the let's body will end up hoisted out the the expression and
459 // allocated to the context in the VM, even if they have no uses 458 // allocated to the context in the VM, even if they have no uses
460 // (`let _ = e0 in e1` can be used for sequencing of `e0` and `e1`). 459 // (`let _ = e0 in e1` can be used for sequencing of `e0` and `e1`).
461 statements.add(variable); 460 statements.add(variable);
462 var index = nameIndex; 461 var index = nameIndex;
463 seenAwait = false; 462 seenAwait = false;
464 variable.initializer = 463 variable.initializer = variable.initializer.accept(this)
465 variable.initializer.accept(this)..parent = variable; 464 ..parent = variable;
466 // Temporaries used in the initializer or the body are not live but the 465 // Temporaries used in the initializer or the body are not live but the
467 // temporary used for the body is. 466 // temporary used for the body is.
468 nameIndex = index + 1; 467 nameIndex = index + 1;
469 seenAwait = true; 468 seenAwait = true;
470 return body; 469 return body;
471 } else { 470 } else {
472 // The body in `let x = initializer in body` did not contain an await. We 471 // The body in `let x = initializer in body` did not contain an await. We
473 // can leave a let expression. 472 // can leave a let expression.
474 seenAwait = shouldName; 473 seenAwait = shouldName;
475 return transform(expr, () { 474 return transform(expr, () {
476 // The body has already been translated. 475 // The body has already been translated.
477 expr.body = body..parent = expr; 476 expr.body = body..parent = expr;
478 variable.initializer = 477 variable.initializer = variable.initializer.accept(this)
479 variable.initializer.accept(this)..parent = variable; 478 ..parent = variable;
480 }); 479 });
481 } 480 }
482 } 481 }
483 482
484 visitFunctionNode(FunctionNode node) { 483 visitFunctionNode(FunctionNode node) {
485 var nestedRewriter = new RecursiveContinuationRewriter( 484 var nestedRewriter =
486 continuationRewriter.helper); 485 new RecursiveContinuationRewriter(continuationRewriter.helper);
487 return node.accept(nestedRewriter); 486 return node.accept(nestedRewriter);
488 } 487 }
489 } 488 }
OLDNEW
« no previous file with comments | « pkg/kernel/lib/kernel.dart ('k') | pkg/kernel/lib/transformations/closure/clone_without_body.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698