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

Unified 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, 2 months 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 side-by-side diff with in-line comments
Download patch
Index: sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_builder.dart
diff --git a/sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_builder.dart b/sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_builder.dart
index c12cd4da4100a1715f56345c5d05e1aab6517dbc..c8a62e0b0738bfc55fbaceb17b8d8e9bdf0964b5 100644
--- a/sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_builder.dart
@@ -162,6 +162,16 @@ abstract class IrBuilderMixin<N> {
SubbuildFunction subbuild(N node) {
return (IrBuilder builder) => withBuilder(builder, () => build(node));
}
+
+ /// Returns a closure that takes an [IrBuilder] and builds the sequence of
+ /// [nodes] in its context using [build].
+ // TODO(johnniwinther): Type [nodes] as `Iterable<N>` when `NodeList` uses
+ // `List` instead of `Link`.
+ SubbuildFunction subbuildSequence(/*Iterable<N>*/ nodes) {
+ return (IrBuilder builder) {
+ return withBuilder(builder, () => builder.buildSequence(nodes, build));
+ };
+ }
}
/// Shared state between nested builders.
@@ -619,6 +629,148 @@ class IrBuilder {
}
}
+ /// Invoke a join-point continuation that contains arguments for all local
+ /// variables.
+ ///
+ /// Given the continuation and a list of uninitialized invocations, fill
+ /// in each invocation with the continuation and appropriate arguments.
+ void invokeFullJoin(ir.Continuation join,
+ JumpCollector jumps,
+ {recursive: false}) {
+ join.isRecursive = recursive;
+ for (int i = 0; i < jumps.length; ++i) {
+ Environment currentEnvironment = jumps.environments[i];
+ ir.InvokeContinuation invoke = jumps.invocations[i];
+ invoke.continuation = new ir.Reference(join);
+ invoke.arguments = new List<ir.Reference>.generate(
+ join.parameters.length,
+ (i) => new ir.Reference(currentEnvironment[i]));
+ invoke.isRecursive = recursive;
+ }
+ }
+
+ void buildFor({SubbuildFunction buildInitializer,
+ SubbuildFunction buildCondition,
+ SubbuildFunction buildBody,
+ SubbuildFunction buildUpdate,
+ JumpTarget target}) {
+ assert(isOpen);
+
+ // For loops use four named continuations: the entry to the condition,
+ // the entry to the body, the loop exit, and the loop successor (break).
+ // The CPS translation of
+ // [[for (initializer; condition; update) body; successor]] is:
+ //
+ // [[initializer]];
+ // let cont loop(x, ...) =
+ // let prim cond = [[condition]] in
+ // let cont break() = [[successor]] in
+ // let cont exit() = break(v, ...) in
+ // let cont body() =
+ // let cont continue(x, ...) = [[update]]; loop(v, ...) in
+ // [[body]]; continue(v, ...) in
+ // branch cond (body, exit) in
+ // loop(v, ...)
+ //
+ // If there are no breaks in the body, the break continuation is inlined
+ // in the exit continuation (i.e., the translation of the successor
+ // statement occurs in the exit continuation). If there is only one
+ // invocation of the continue continuation (i.e., no continues in the
+ // body), the continue continuation is inlined in the body.
+
+ buildInitializer(this);
+
+ IrBuilder condBuilder = new IrBuilder.recursive(this);
+ ir.Primitive condition = buildCondition(condBuilder);
+ if (condition == null) {
+ // If the condition is empty then the body is entered unconditionally.
+ condition = condBuilder.buildBooleanLiteral(true);
+ }
+
+ JumpCollector breakCollector = new JumpCollector(target);
+ JumpCollector continueCollector = new JumpCollector(target);
+ state.breakCollectors.add(breakCollector);
+ state.continueCollectors.add(continueCollector);
+
+ IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder);
+ buildBody(bodyBuilder);
+ assert(state.breakCollectors.last == breakCollector);
+ assert(state.continueCollectors.last == continueCollector);
+ state.breakCollectors.removeLast();
+ state.continueCollectors.removeLast();
+
+ // The binding of the continue continuation should occur as late as
+ // possible, that is, at the nearest common ancestor of all the continue
+ // sites in the body. However, that is difficult to compute here, so it
+ // is instead placed just outside the body of the body continuation.
+ bool hasContinues = !continueCollector.isEmpty;
+ IrBuilder updateBuilder = hasContinues
+ ? new IrBuilder.recursive(condBuilder)
+ : bodyBuilder;
+ buildUpdate(updateBuilder);
+
+ // Create body entry and loop exit continuations and a branch to them.
+ ir.Continuation bodyContinuation = new ir.Continuation([]);
+ ir.Continuation exitContinuation = new ir.Continuation([]);
+ ir.LetCont branch =
+ new ir.LetCont(exitContinuation,
+ new ir.LetCont(bodyContinuation,
+ new ir.Branch(new ir.IsTrue(condition),
+ bodyContinuation,
+ exitContinuation)));
+ // If there are breaks in the body, then there must be a join-point
+ // continuation for the normal exit and the breaks.
+ bool hasBreaks = !breakCollector.isEmpty;
+ ir.LetCont letJoin;
+ if (hasBreaks) {
+ letJoin = new ir.LetCont(null, branch);
+ condBuilder.add(letJoin);
+ condBuilder._current = branch;
+ } else {
+ condBuilder.add(branch);
+ }
+ ir.Continuation continueContinuation;
+ if (hasContinues) {
+ // If there are continues in the body, we need a named continue
+ // continuation as a join point.
+ continueContinuation = new ir.Continuation(updateBuilder._parameters);
+ if (bodyBuilder.isOpen) continueCollector.addJump(bodyBuilder);
+ invokeFullJoin(continueContinuation, continueCollector);
+ }
+ ir.Continuation loopContinuation =
+ new ir.Continuation(condBuilder._parameters);
+ if (updateBuilder.isOpen) {
+ JumpCollector backEdges = new JumpCollector(null);
+ backEdges.addJump(updateBuilder);
+ invokeFullJoin(loopContinuation, backEdges, recursive: true);
+ }
+
+ // Fill in the body and possible continue continuation bodies. Do this
+ // only after it is guaranteed that they are not empty.
+ if (hasContinues) {
+ continueContinuation.body = updateBuilder._root;
+ bodyContinuation.body =
+ new ir.LetCont(continueContinuation, bodyBuilder._root);
+ } else {
+ bodyContinuation.body = bodyBuilder._root;
+ }
+
+ loopContinuation.body = condBuilder._root;
+ add(new ir.LetCont(loopContinuation,
+ new ir.InvokeContinuation(loopContinuation,
+ environment.index2value)));
+ if (hasBreaks) {
+ _current = branch;
+ environment = condBuilder.environment;
+ breakCollector.addJump(this);
+ letJoin.continuation = createJoin(environment.length, breakCollector);
+ _current = letJoin;
+ } else {
+ _current = condBuilder._current;
+ environment = condBuilder.environment;
+ }
+ }
+
/// Create a return statement `return value;` or `return;` if [value] is
/// null.
void buildReturn([ir.Primitive value]) {
@@ -642,9 +794,16 @@ class IrBuilder {
// Build(Block(stamements), C) = C'
// where C' = statements.fold(Build, C)
assert(isOpen);
- for (var statement in statements) {
- build(statement);
+ return buildSequence(statements, build);
+ }
+
+ /// 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.
+ // TODO(johnniwinther): Type [nodes] as `Iterable` when `NodeList` uses
+ // `List` instead of `Link`.
+ void buildSequence(var nodes, build(node)) {
+ for (var node in nodes) {
if (!isOpen) return;
+ build(node);
}
}
« 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