| 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 library tree_ir_builder; | 5 library tree_ir_builder; |
| 6 | 6 |
| 7 import '../dart2jslib.dart' as dart2js; | 7 import '../dart2jslib.dart' as dart2js; |
| 8 import '../dart_types.dart'; | 8 import '../dart_types.dart'; |
| 9 import '../elements/elements.dart'; | 9 import '../elements/elements.dart'; |
| 10 import '../cps_ir/cps_ir_nodes.dart' as cps_ir; | 10 import '../cps_ir/cps_ir_nodes.dart' as cps_ir; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 50 final Map<Local, List<Variable>> local2variables = <Local, List<Variable>>{}; | 50 final Map<Local, List<Variable>> local2variables = <Local, List<Variable>>{}; |
| 51 | 51 |
| 52 /// Like [local2variables], except for mutable variables. | 52 /// Like [local2variables], except for mutable variables. |
| 53 final Map<cps_ir.MutableVariable, Variable> local2mutable = | 53 final Map<cps_ir.MutableVariable, Variable> local2mutable = |
| 54 <cps_ir.MutableVariable, Variable>{}; | 54 <cps_ir.MutableVariable, Variable>{}; |
| 55 | 55 |
| 56 // Continuations with more than one use are replaced with Tree labels. This | 56 // Continuations with more than one use are replaced with Tree labels. This |
| 57 // is the mapping from continuations to labels. | 57 // is the mapping from continuations to labels. |
| 58 final Map<cps_ir.Continuation, Label> labels = <cps_ir.Continuation, Label>{}; | 58 final Map<cps_ir.Continuation, Label> labels = <cps_ir.Continuation, Label>{}; |
| 59 | 59 |
| 60 /// A stack of singly-used labels that can be safely inlined at their use |
| 61 /// site. |
| 62 /// |
| 63 /// Code for continuations with exactly one use is inlined at the use site. |
| 64 /// This is not safe if the code is moved inside the scope of an exception |
| 65 /// handler (i.e., into a try block). We keep a stack of singly-referenced |
| 66 /// continuations that are in scope without crossing a binding for a handler. |
| 67 List<cps_ir.Continuation> safeForInlining = <cps_ir.Continuation>[]; |
| 68 |
| 60 ExecutableElement currentElement; | 69 ExecutableElement currentElement; |
| 61 cps_ir.Continuation returnContinuation; | 70 cps_ir.Continuation returnContinuation; |
| 62 | 71 |
| 63 Builder parent; | 72 Builder parent; |
| 64 | 73 |
| 65 Builder(this.internalError, [this.parent]); | 74 Builder(this.internalError, [this.parent]); |
| 66 | 75 |
| 67 Builder createInnerBuilder() { | 76 Builder createInnerBuilder() { |
| 68 return new Builder(internalError, this); | 77 return new Builder(internalError, this); |
| 69 } | 78 } |
| (...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 365 return new Assign(variable, definition, visit(node.body)); | 374 return new Assign(variable, definition, visit(node.body)); |
| 366 } | 375 } |
| 367 } | 376 } |
| 368 | 377 |
| 369 Statement visitRunnableBody(cps_ir.RunnableBody node) { | 378 Statement visitRunnableBody(cps_ir.RunnableBody node) { |
| 370 return visit(node.body); | 379 return visit(node.body); |
| 371 } | 380 } |
| 372 | 381 |
| 373 Statement visitLetCont(cps_ir.LetCont node) { | 382 Statement visitLetCont(cps_ir.LetCont node) { |
| 374 // Introduce labels for continuations that need them. | 383 // Introduce labels for continuations that need them. |
| 384 int safeForInliningLengthOnEntry = safeForInlining.length; |
| 375 for (cps_ir.Continuation continuation in node.continuations) { | 385 for (cps_ir.Continuation continuation in node.continuations) { |
| 376 if (continuation.hasMultipleUses) { | 386 if (continuation.hasMultipleUses) { |
| 377 labels[continuation] = new Label(); | 387 labels[continuation] = new Label(); |
| 388 } else { |
| 389 safeForInlining.add(continuation); |
| 378 } | 390 } |
| 379 } | 391 } |
| 380 Statement body = visit(node.body); | 392 Statement body = visit(node.body); |
| 393 safeForInlining.length = safeForInliningLengthOnEntry; |
| 381 // Continuations are bound at the same level, but they have to be | 394 // Continuations are bound at the same level, but they have to be |
| 382 // translated as if nested. This is because the body can invoke any | 395 // translated as if nested. This is because the body can invoke any |
| 383 // of them from anywhere, so it must be nested inside all of them. | 396 // of them from anywhere, so it must be nested inside all of them. |
| 384 // | 397 // |
| 385 // The continuation bodies are not always translated directly here because | 398 // The continuation bodies are not always translated directly here because |
| 386 // they may have been already translated: | 399 // they may have been already translated: |
| 387 // * For singly-used continuations, the continuation's body is | 400 // * For singly-used continuations, the continuation's body is |
| 388 // translated at the site of the continuation invocation. | 401 // translated at the site of the continuation invocation. |
| 389 // * For recursive continuations, there is a single non-recursive | 402 // * For recursive continuations, there is a single non-recursive |
| 390 // invocation. The continuation's body is translated at the site | 403 // invocation. The continuation's body is translated at the site |
| 391 // of the non-recursive continuation invocation. | 404 // of the non-recursive continuation invocation. |
| 392 // See visitInvokeContinuation for the implementation. | 405 // See visitInvokeContinuation for the implementation. |
| 393 Statement current = body; | 406 Statement current = body; |
| 394 for (cps_ir.Continuation continuation in node.continuations.reversed) { | 407 for (cps_ir.Continuation continuation in node.continuations.reversed) { |
| 395 Label label = labels[continuation]; | 408 Label label = labels[continuation]; |
| 396 if (label != null && !continuation.isRecursive) { | 409 if (label != null && !continuation.isRecursive) { |
| 397 current = | 410 current = |
| 398 new LabeledStatement(label, current, visit(continuation.body)); | 411 new LabeledStatement(label, current, visit(continuation.body)); |
| 399 } | 412 } |
| 400 } | 413 } |
| 401 return current; | 414 return current; |
| 402 } | 415 } |
| 403 | 416 |
| 417 Statement visitLetHandler(cps_ir.LetHandler node) { |
| 418 List<cps_ir.Continuation> saved = safeForInlining; |
| 419 safeForInlining = <cps_ir.Continuation>[]; |
| 420 Statement tryBody = visit(node.body); |
| 421 safeForInlining = saved; |
| 422 List<Variable> catchParameters = |
| 423 node.handler.parameters.map(getVariable).toList(); |
| 424 Statement catchBody = visit(node.handler.body); |
| 425 return new Try(tryBody, catchParameters, catchBody); |
| 426 } |
| 427 |
| 404 Statement visitInvokeStatic(cps_ir.InvokeStatic node) { | 428 Statement visitInvokeStatic(cps_ir.InvokeStatic node) { |
| 405 // Calls are translated to direct style. | 429 // Calls are translated to direct style. |
| 406 List<Expression> arguments = translateArguments(node.arguments); | 430 List<Expression> arguments = translateArguments(node.arguments); |
| 407 Expression invoke = new InvokeStatic(node.target, node.selector, arguments); | 431 Expression invoke = new InvokeStatic(node.target, node.selector, arguments); |
| 408 return continueWithExpression(node.continuation, invoke); | 432 return continueWithExpression(node.continuation, invoke); |
| 409 } | 433 } |
| 410 | 434 |
| 411 Statement visitInvokeMethod(cps_ir.InvokeMethod node) { | 435 Statement visitInvokeMethod(cps_ir.InvokeMethod node) { |
| 412 Expression invoke = new InvokeMethod(getVariableReference(node.receiver), | 436 Expression invoke = new InvokeMethod(getVariableReference(node.receiver), |
| 413 node.selector, | 437 node.selector, |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 502 // * Recursive continuations | 526 // * Recursive continuations |
| 503 // - There is a single non-recursive invocation. Translate | 527 // - There is a single non-recursive invocation. Translate |
| 504 // the continuation body inline as a labeled loop at the | 528 // the continuation body inline as a labeled loop at the |
| 505 // invocation site. | 529 // invocation site. |
| 506 // - Translate the recursive invocations to Continue. | 530 // - Translate the recursive invocations to Continue. |
| 507 if (cont.isRecursive) { | 531 if (cont.isRecursive) { |
| 508 return node.isRecursive | 532 return node.isRecursive |
| 509 ? new Continue(labels[cont]) | 533 ? new Continue(labels[cont]) |
| 510 : new WhileTrue(labels[cont], visit(cont.body)); | 534 : new WhileTrue(labels[cont], visit(cont.body)); |
| 511 } else { | 535 } else { |
| 512 return cont.hasExactlyOneUse | 536 if (cont.hasExactlyOneUse) { |
| 513 ? visit(cont.body) | 537 if (safeForInlining.contains(cont)) { |
| 514 : new Break(labels[cont]); | 538 return visit(cont.body); |
| 539 } |
| 540 labels[cont] = new Label(); |
| 541 } |
| 542 return new Break(labels[cont]); |
| 515 } | 543 } |
| 516 }); | 544 }); |
| 517 } | 545 } |
| 518 } | 546 } |
| 519 | 547 |
| 520 Statement visitBranch(cps_ir.Branch node) { | 548 Statement visitBranch(cps_ir.Branch node) { |
| 521 Expression condition = visit(node.condition); | 549 Expression condition = visit(node.condition); |
| 522 Statement thenStatement, elseStatement; | 550 Statement thenStatement, elseStatement; |
| 523 cps_ir.Continuation cont = node.trueContinuation.definition; | 551 cps_ir.Continuation cont = node.trueContinuation.definition; |
| 524 assert(cont.parameters.isEmpty); | 552 assert(cont.parameters.isEmpty); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 589 // visited. | 617 // visited. |
| 590 internalError(CURRENT_ELEMENT_SPANNABLE, 'Unexpected IR node: $node.'); | 618 internalError(CURRENT_ELEMENT_SPANNABLE, 'Unexpected IR node: $node.'); |
| 591 return null; | 619 return null; |
| 592 } | 620 } |
| 593 | 621 |
| 594 Expression visitIsTrue(cps_ir.IsTrue node) { | 622 Expression visitIsTrue(cps_ir.IsTrue node) { |
| 595 return getVariableReference(node.value); | 623 return getVariableReference(node.value); |
| 596 } | 624 } |
| 597 } | 625 } |
| 598 | 626 |
| OLD | NEW |