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

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: Add TODO. 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 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
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 }
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