Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 dart2js.ir_builder; | 5 library dart2js.ir_builder; |
| 6 | 6 |
| 7 import '../constants/expressions.dart'; | 7 import '../constants/expressions.dart'; |
| 8 import '../constants/values.dart' show PrimitiveConstantValue; | 8 import '../constants/values.dart' show PrimitiveConstantValue; |
| 9 import '../dart_backend/dart_backend.dart' show DartBackend; | 9 import '../dart_backend/dart_backend.dart' show DartBackend; |
| 10 import '../dart_types.dart'; | 10 import '../dart_types.dart'; |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 155 | 155 |
| 156 /// Builds and returns the [ir.Node] for [node] or returns `null` if | 156 /// Builds and returns the [ir.Node] for [node] or returns `null` if |
| 157 /// [node] is `null`. | 157 /// [node] is `null`. |
| 158 ir.Node build(N node) => node != null ? visit(node) : null; | 158 ir.Node build(N node) => node != null ? visit(node) : null; |
| 159 | 159 |
| 160 /// Returns a closure that takes an [IrBuilder] and builds [node] in its | 160 /// Returns a closure that takes an [IrBuilder] and builds [node] in its |
| 161 /// context using [build]. | 161 /// context using [build]. |
| 162 SubbuildFunction subbuild(N node) { | 162 SubbuildFunction subbuild(N node) { |
| 163 return (IrBuilder builder) => withBuilder(builder, () => build(node)); | 163 return (IrBuilder builder) => withBuilder(builder, () => build(node)); |
| 164 } | 164 } |
| 165 | |
| 166 /// Returns a closure that takes an [IrBuilder] and builds the sequence of | |
| 167 /// [nodes] in its context using [build]. | |
| 168 // TODO(johnniwinther): Type [nodes] as `Iterable<N>` when `NodeList` uses | |
| 169 // `List` instead of `Link`. | |
| 170 SubbuildFunction subbuildSequence(/*Iterable<N>*/ nodes) { | |
| 171 return (IrBuilder builder) { | |
| 172 return withBuilder(builder, () => builder.buildSequence(nodes, build)); | |
| 173 }; | |
| 174 } | |
| 165 } | 175 } |
| 166 | 176 |
| 167 /// Shared state between nested builders. | 177 /// Shared state between nested builders. |
| 168 class IrBuilderSharedState { | 178 class IrBuilderSharedState { |
| 169 final ConstantSystem constantSystem; | 179 final ConstantSystem constantSystem; |
| 170 | 180 |
| 171 /// A stack of collectors for breaks. | 181 /// A stack of collectors for breaks. |
| 172 final List<JumpCollector> breakCollectors = <JumpCollector>[]; | 182 final List<JumpCollector> breakCollectors = <JumpCollector>[]; |
| 173 | 183 |
| 174 /// A stack of collectors for continues. | 184 /// A stack of collectors for continues. |
| (...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 612 } else if (elseBuilder.isOpen) { | 622 } else if (elseBuilder.isOpen) { |
| 613 _current = | 623 _current = |
| 614 (elseBuilder._root == null) ? letElse : elseBuilder._current; | 624 (elseBuilder._root == null) ? letElse : elseBuilder._current; |
| 615 environment = elseBuilder.environment; | 625 environment = elseBuilder.environment; |
| 616 } else { | 626 } else { |
| 617 _current = null; | 627 _current = null; |
| 618 } | 628 } |
| 619 } | 629 } |
| 620 } | 630 } |
| 621 | 631 |
| 632 /// Invoke a join-point continuation that contains arguments for all local | |
| 633 /// variables. | |
| 634 /// | |
| 635 /// Given the continuation and a list of uninitialized invocations, fill | |
| 636 /// in each invocation with the continuation and appropriate arguments. | |
| 637 void invokeFullJoin(ir.Continuation join, | |
| 638 JumpCollector jumps, | |
| 639 {recursive: false}) { | |
| 640 join.isRecursive = recursive; | |
| 641 for (int i = 0; i < jumps.length; ++i) { | |
| 642 Environment currentEnvironment = jumps.environments[i]; | |
| 643 ir.InvokeContinuation invoke = jumps.invocations[i]; | |
| 644 invoke.continuation = new ir.Reference(join); | |
| 645 invoke.arguments = new List<ir.Reference>.generate( | |
| 646 join.parameters.length, | |
| 647 (i) => new ir.Reference(currentEnvironment[i])); | |
| 648 invoke.isRecursive = recursive; | |
| 649 } | |
| 650 } | |
| 651 | |
| 652 void buildFor({SubbuildFunction buildInitializer, | |
| 653 SubbuildFunction buildCondition, | |
| 654 SubbuildFunction buildBody, | |
| 655 SubbuildFunction buildUpdate, | |
| 656 JumpTarget target}) { | |
| 657 assert(isOpen); | |
| 658 | |
| 659 // For loops use four named continuations: the entry to the condition, | |
| 660 // the entry to the body, the loop exit, and the loop successor (break). | |
| 661 // The CPS translation of | |
| 662 // [[for (initializer; condition; update) body; successor]] is: | |
| 663 // | |
| 664 // [[initializer]]; | |
| 665 // let cont loop(x, ...) = | |
| 666 // let prim cond = [[condition]] in | |
| 667 // let cont break() = [[successor]] in | |
| 668 // let cont exit() = break(v, ...) in | |
| 669 // let cont body() = | |
| 670 // let cont continue(x, ...) = [[update]]; loop(v, ...) in | |
| 671 // [[body]]; continue(v, ...) in | |
| 672 // branch cond (body, exit) in | |
| 673 // loop(v, ...) | |
| 674 // | |
| 675 // If there are no breaks in the body, the break continuation is inlined | |
| 676 // in the exit continuation (i.e., the translation of the successor | |
| 677 // statement occurs in the exit continuation). If there is only one | |
| 678 // invocation of the continue continuation (i.e., no continues in the | |
| 679 // body), the continue continuation is inlined in the body. | |
| 680 | |
| 681 buildInitializer(this); | |
| 682 | |
| 683 IrBuilder condBuilder = new IrBuilder.recursive(this); | |
| 684 ir.Primitive condition = buildCondition(condBuilder); | |
| 685 if (condition == null) { | |
| 686 // If the condition is empty then the body is entered unconditionally. | |
| 687 condition = condBuilder.buildBooleanLiteral(true); | |
| 688 } | |
| 689 | |
| 690 JumpCollector breakCollector = new JumpCollector(target); | |
| 691 JumpCollector continueCollector = new JumpCollector(target); | |
| 692 state.breakCollectors.add(breakCollector); | |
| 693 state.continueCollectors.add(continueCollector); | |
| 694 | |
| 695 IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder); | |
| 696 buildBody(bodyBuilder); | |
| 697 assert(state.breakCollectors.last == breakCollector); | |
| 698 assert(state.continueCollectors.last == continueCollector); | |
| 699 state.breakCollectors.removeLast(); | |
| 700 state.continueCollectors.removeLast(); | |
| 701 | |
| 702 // The binding of the continue continuation should occur as late as | |
| 703 // possible, that is, at the nearest common ancestor of all the continue | |
| 704 // sites in the body. However, that is difficult to compute here, so it | |
| 705 // is instead placed just outside the body of the body continuation. | |
| 706 bool hasContinues = !continueCollector.isEmpty; | |
| 707 IrBuilder updateBuilder = hasContinues | |
| 708 ? new IrBuilder.recursive(condBuilder) | |
| 709 : bodyBuilder; | |
| 710 buildUpdate(updateBuilder); | |
| 711 | |
| 712 // Create body entry and loop exit continuations and a branch to them. | |
| 713 ir.Continuation bodyContinuation = new ir.Continuation([]); | |
| 714 ir.Continuation exitContinuation = new ir.Continuation([]); | |
| 715 ir.LetCont branch = | |
| 716 new ir.LetCont(exitContinuation, | |
| 717 new ir.LetCont(bodyContinuation, | |
| 718 new ir.Branch(new ir.IsTrue(condition), | |
| 719 bodyContinuation, | |
| 720 exitContinuation))); | |
| 721 // If there are breaks in the body, then there must be a join-point | |
| 722 // continuation for the normal exit and the breaks. | |
| 723 bool hasBreaks = !breakCollector.isEmpty; | |
| 724 ir.LetCont letJoin; | |
| 725 if (hasBreaks) { | |
| 726 letJoin = new ir.LetCont(null, branch); | |
| 727 condBuilder.add(letJoin); | |
| 728 condBuilder._current = branch; | |
| 729 } else { | |
| 730 condBuilder.add(branch); | |
| 731 } | |
| 732 ir.Continuation continueContinuation; | |
| 733 if (hasContinues) { | |
| 734 // If there are continues in the body, we need a named continue | |
| 735 // continuation as a join point. | |
| 736 continueContinuation = new ir.Continuation(updateBuilder._parameters); | |
| 737 if (bodyBuilder.isOpen) continueCollector.addJump(bodyBuilder); | |
| 738 invokeFullJoin(continueContinuation, continueCollector); | |
| 739 } | |
| 740 ir.Continuation loopContinuation = | |
| 741 new ir.Continuation(condBuilder._parameters); | |
| 742 if (updateBuilder.isOpen) { | |
| 743 JumpCollector backEdges = new JumpCollector(null); | |
| 744 backEdges.addJump(updateBuilder); | |
| 745 invokeFullJoin(loopContinuation, backEdges, recursive: true); | |
| 746 } | |
| 747 | |
| 748 // Fill in the body and possible continue continuation bodies. Do this | |
| 749 // only after it is guaranteed that they are not empty. | |
| 750 if (hasContinues) { | |
| 751 continueContinuation.body = updateBuilder._root; | |
| 752 bodyContinuation.body = | |
| 753 new ir.LetCont(continueContinuation, bodyBuilder._root); | |
| 754 } else { | |
| 755 bodyContinuation.body = bodyBuilder._root; | |
| 756 } | |
| 757 | |
| 758 loopContinuation.body = condBuilder._root; | |
| 759 add(new ir.LetCont(loopContinuation, | |
| 760 new ir.InvokeContinuation(loopContinuation, | |
| 761 environment.index2value))); | |
| 762 if (hasBreaks) { | |
| 763 _current = branch; | |
| 764 environment = condBuilder.environment; | |
| 765 breakCollector.addJump(this); | |
| 766 letJoin.continuation = createJoin(environment.length, breakCollector); | |
| 767 _current = letJoin; | |
| 768 } else { | |
| 769 _current = condBuilder._current; | |
| 770 environment = condBuilder.environment; | |
| 771 } | |
| 772 } | |
| 773 | |
| 622 /// Create a return statement `return value;` or `return;` if [value] is | 774 /// Create a return statement `return value;` or `return;` if [value] is |
| 623 /// null. | 775 /// null. |
| 624 void buildReturn([ir.Primitive value]) { | 776 void buildReturn([ir.Primitive value]) { |
| 625 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] | 777 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] |
| 626 // where (C', x) = Build(e, C) | 778 // where (C', x) = Build(e, C) |
| 627 // | 779 // |
| 628 // Return without a subexpression is translated as if it were return null. | 780 // Return without a subexpression is translated as if it were return null. |
| 629 assert(isOpen); | 781 assert(isOpen); |
| 630 if (value == null) { | 782 if (value == null) { |
| 631 value = buildNullLiteral(); | 783 value = buildNullLiteral(); |
| 632 } | 784 } |
| 633 add(new ir.InvokeContinuation(state.returnContinuation, [value])); | 785 add(new ir.InvokeContinuation(state.returnContinuation, [value])); |
| 634 _current = null; | 786 _current = null; |
| 635 } | 787 } |
| 636 | 788 |
| 637 /// Create a blocks of [statements] by applying [build] to all reachable | 789 /// Create a blocks of [statements] by applying [build] to all reachable |
| 638 /// statements. | 790 /// statements. |
| 639 // TODO(johnniwinther): Type [statements] as `Iterable` when `NodeList` uses | 791 // TODO(johnniwinther): Type [statements] as `Iterable` when `NodeList` uses |
| 640 // `List` instead of `Link`. | 792 // `List` instead of `Link`. |
| 641 void buildBlock(var statements, build(statement)) { | 793 void buildBlock(var statements, build(statement)) { |
| 642 // Build(Block(stamements), C) = C' | 794 // Build(Block(stamements), C) = C' |
| 643 // where C' = statements.fold(Build, C) | 795 // where C' = statements.fold(Build, C) |
| 644 assert(isOpen); | 796 assert(isOpen); |
| 645 for (var statement in statements) { | 797 return buildSequence(statements, build); |
| 646 build(statement); | 798 } |
| 799 | |
| 800 /// Creates a sequence of [nodes] by applying [build] to all reachable nodes. | |
|
sigurdm
2014/10/28 12:33:57
Make the difference to buildblock explicit in the
Johnni Winther
2014/10/28 12:48:46
Done.
| |
| 801 // TODO(johnniwinther): Type [nodes] as `Iterable` when `NodeList` uses | |
| 802 // `List` instead of `Link`. | |
| 803 void buildSequence(var nodes, build(node)) { | |
| 804 for (var node in nodes) { | |
| 647 if (!isOpen) return; | 805 if (!isOpen) return; |
| 806 build(node); | |
| 648 } | 807 } |
| 649 } | 808 } |
| 650 | 809 |
| 651 | 810 |
| 652 // Build(BreakStatement L, C) = C[InvokeContinuation(...)] | 811 // Build(BreakStatement L, C) = C[InvokeContinuation(...)] |
| 653 // | 812 // |
| 654 // The continuation and arguments are filled in later after translating | 813 // The continuation and arguments are filled in later after translating |
| 655 // the body containing the break. | 814 // the body containing the break. |
| 656 bool buildBreak(JumpTarget target) { | 815 bool buildBreak(JumpTarget target) { |
| 657 return buildJumpInternal(target, state.breakCollectors); | 816 return buildJumpInternal(target, state.breakCollectors); |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 893 index = 0; | 1052 index = 0; |
| 894 for (int i = 0; i < environment.length; ++i) { | 1053 for (int i = 0; i < environment.length; ++i) { |
| 895 if (common[i] == null) { | 1054 if (common[i] == null) { |
| 896 environment.index2value[i] = parameters[index++]; | 1055 environment.index2value[i] = parameters[index++]; |
| 897 } | 1056 } |
| 898 } | 1057 } |
| 899 | 1058 |
| 900 return join; | 1059 return join; |
| 901 } | 1060 } |
| 902 } | 1061 } |
| OLD | NEW |