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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_builder.dart

Issue 683803003: Support for loops in analyzer2dart. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Updated cf. comments. Created 6 years, 1 month 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
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
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
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 /// Creates a for loop in which the initializer, condition, body, update are
653 /// created by [buildInitializer], [buildCondition], [buildBody] and
654 /// [buildUpdate], respectively.
655 ///
656 /// The jump [target] is used to identify which `break` and `continue`
657 /// statements that have this `for` statement as their target.
658 void buildFor({SubbuildFunction buildInitializer,
659 SubbuildFunction buildCondition,
660 SubbuildFunction buildBody,
661 SubbuildFunction buildUpdate,
662 JumpTarget target}) {
663 assert(isOpen);
664
665 // For loops use four named continuations: the entry to the condition,
666 // the entry to the body, the loop exit, and the loop successor (break).
667 // The CPS translation of
668 // [[for (initializer; condition; update) body; successor]] is:
669 //
670 // [[initializer]];
671 // let cont loop(x, ...) =
672 // let prim cond = [[condition]] in
673 // let cont break() = [[successor]] in
674 // let cont exit() = break(v, ...) in
675 // let cont body() =
676 // let cont continue(x, ...) = [[update]]; loop(v, ...) in
677 // [[body]]; continue(v, ...) in
678 // branch cond (body, exit) in
679 // loop(v, ...)
680 //
681 // If there are no breaks in the body, the break continuation is inlined
682 // in the exit continuation (i.e., the translation of the successor
683 // statement occurs in the exit continuation). If there is only one
684 // invocation of the continue continuation (i.e., no continues in the
685 // body), the continue continuation is inlined in the body.
686
687 buildInitializer(this);
688
689 IrBuilder condBuilder = new IrBuilder.recursive(this);
690 ir.Primitive condition = buildCondition(condBuilder);
691 if (condition == null) {
692 // If the condition is empty then the body is entered unconditionally.
693 condition = condBuilder.buildBooleanLiteral(true);
694 }
695
696 JumpCollector breakCollector = new JumpCollector(target);
697 JumpCollector continueCollector = new JumpCollector(target);
698 state.breakCollectors.add(breakCollector);
699 state.continueCollectors.add(continueCollector);
700
701 IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder);
702 buildBody(bodyBuilder);
703 assert(state.breakCollectors.last == breakCollector);
704 assert(state.continueCollectors.last == continueCollector);
705 state.breakCollectors.removeLast();
706 state.continueCollectors.removeLast();
707
708 // The binding of the continue continuation should occur as late as
709 // possible, that is, at the nearest common ancestor of all the continue
710 // sites in the body. However, that is difficult to compute here, so it
711 // is instead placed just outside the body of the body continuation.
712 bool hasContinues = !continueCollector.isEmpty;
713 IrBuilder updateBuilder = hasContinues
714 ? new IrBuilder.recursive(condBuilder)
715 : bodyBuilder;
716 buildUpdate(updateBuilder);
717
718 // Create body entry and loop exit continuations and a branch to them.
719 ir.Continuation bodyContinuation = new ir.Continuation([]);
720 ir.Continuation exitContinuation = new ir.Continuation([]);
721 ir.LetCont branch =
722 new ir.LetCont(exitContinuation,
723 new ir.LetCont(bodyContinuation,
724 new ir.Branch(new ir.IsTrue(condition),
725 bodyContinuation,
726 exitContinuation)));
727 // If there are breaks in the body, then there must be a join-point
728 // continuation for the normal exit and the breaks.
729 bool hasBreaks = !breakCollector.isEmpty;
730 ir.LetCont letJoin;
731 if (hasBreaks) {
732 letJoin = new ir.LetCont(null, branch);
733 condBuilder.add(letJoin);
734 condBuilder._current = branch;
735 } else {
736 condBuilder.add(branch);
737 }
738 ir.Continuation continueContinuation;
739 if (hasContinues) {
740 // If there are continues in the body, we need a named continue
741 // continuation as a join point.
742 continueContinuation = new ir.Continuation(updateBuilder._parameters);
743 if (bodyBuilder.isOpen) continueCollector.addJump(bodyBuilder);
744 invokeFullJoin(continueContinuation, continueCollector);
745 }
746 ir.Continuation loopContinuation =
747 new ir.Continuation(condBuilder._parameters);
748 if (updateBuilder.isOpen) {
749 JumpCollector backEdges = new JumpCollector(null);
750 backEdges.addJump(updateBuilder);
751 invokeFullJoin(loopContinuation, backEdges, recursive: true);
752 }
753
754 // Fill in the body and possible continue continuation bodies. Do this
755 // only after it is guaranteed that they are not empty.
756 if (hasContinues) {
757 continueContinuation.body = updateBuilder._root;
758 bodyContinuation.body =
759 new ir.LetCont(continueContinuation, bodyBuilder._root);
760 } else {
761 bodyContinuation.body = bodyBuilder._root;
762 }
763
764 loopContinuation.body = condBuilder._root;
765 add(new ir.LetCont(loopContinuation,
766 new ir.InvokeContinuation(loopContinuation,
767 environment.index2value)));
768 if (hasBreaks) {
769 _current = branch;
770 environment = condBuilder.environment;
771 breakCollector.addJump(this);
772 letJoin.continuation = createJoin(environment.length, breakCollector);
773 _current = letJoin;
774 } else {
775 _current = condBuilder._current;
776 environment = condBuilder.environment;
777 }
778 }
779
622 /// Create a return statement `return value;` or `return;` if [value] is 780 /// Create a return statement `return value;` or `return;` if [value] is
623 /// null. 781 /// null.
624 void buildReturn([ir.Primitive value]) { 782 void buildReturn([ir.Primitive value]) {
625 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] 783 // Build(Return(e), C) = C'[InvokeContinuation(return, x)]
626 // where (C', x) = Build(e, C) 784 // where (C', x) = Build(e, C)
627 // 785 //
628 // Return without a subexpression is translated as if it were return null. 786 // Return without a subexpression is translated as if it were return null.
629 assert(isOpen); 787 assert(isOpen);
630 if (value == null) { 788 if (value == null) {
631 value = buildNullLiteral(); 789 value = buildNullLiteral();
632 } 790 }
633 add(new ir.InvokeContinuation(state.returnContinuation, [value])); 791 add(new ir.InvokeContinuation(state.returnContinuation, [value]));
634 _current = null; 792 _current = null;
635 } 793 }
636 794
637 /// Create a blocks of [statements] by applying [build] to all reachable 795 /// Create a blocks of [statements] by applying [build] to all reachable
638 /// statements. 796 /// statements. The first statement is assumed to be reachable.
639 // TODO(johnniwinther): Type [statements] as `Iterable` when `NodeList` uses 797 // TODO(johnniwinther): Type [statements] as `Iterable` when `NodeList` uses
640 // `List` instead of `Link`. 798 // `List` instead of `Link`.
641 void buildBlock(var statements, build(statement)) { 799 void buildBlock(var statements, build(statement)) {
642 // Build(Block(stamements), C) = C' 800 // Build(Block(stamements), C) = C'
643 // where C' = statements.fold(Build, C) 801 // where C' = statements.fold(Build, C)
644 assert(isOpen); 802 assert(isOpen);
645 for (var statement in statements) { 803 return buildSequence(statements, build);
646 build(statement); 804 }
805
806 /// Creates a sequence of [nodes] by applying [build] to all reachable nodes.
807 ///
808 /// The first node in the sequence does not need to be reachable.
809 // TODO(johnniwinther): Type [nodes] as `Iterable` when `NodeList` uses
810 // `List` instead of `Link`.
811 void buildSequence(var nodes, build(node)) {
812 for (var node in nodes) {
647 if (!isOpen) return; 813 if (!isOpen) return;
814 build(node);
648 } 815 }
649 } 816 }
650 817
651 818
652 // Build(BreakStatement L, C) = C[InvokeContinuation(...)] 819 // Build(BreakStatement L, C) = C[InvokeContinuation(...)]
653 // 820 //
654 // The continuation and arguments are filled in later after translating 821 // The continuation and arguments are filled in later after translating
655 // the body containing the break. 822 // the body containing the break.
656 bool buildBreak(JumpTarget target) { 823 bool buildBreak(JumpTarget target) {
657 return buildJumpInternal(target, state.breakCollectors); 824 return buildJumpInternal(target, state.breakCollectors);
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after
893 index = 0; 1060 index = 0;
894 for (int i = 0; i < environment.length; ++i) { 1061 for (int i = 0; i < environment.length; ++i) {
895 if (common[i] == null) { 1062 if (common[i] == null) {
896 environment.index2value[i] = parameters[index++]; 1063 environment.index2value[i] = parameters[index++];
897 } 1064 }
898 } 1065 }
899 1066
900 return join; 1067 return join;
901 } 1068 }
902 } 1069 }
OLDNEW
« no previous file with comments | « pkg/analyzer2dart/test/sexpr_data.dart ('k') | sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_builder_visitor.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698