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

Unified Diff: pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart

Issue 1040093002: Change the collection of continuation jumps. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Clean up some comments. Created 5 years, 8 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
« no previous file with comments | « no previous file | pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
index fee4b77d92539de4c368501b8077f3b1da952063..fe2af5a2fe5e806bfd7e26bd1675f1c4fefbbe82 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
@@ -44,6 +44,20 @@ class Environment {
index2variable = new List<Local>.from(other.index2variable),
index2value = new List<ir.Primitive>.from(other.index2value);
+ /// Construct an environment that is shaped like another one but with a
+ /// fresh parameter for each variable.
+ ///
+ /// The mapping from elements to indexes is shared, not copied.
+ Environment.fresh(Environment other, List<ir.Parameter> parameters)
Kevin Millikin (Google) 2015/04/07 09:14:55 `parameters` is an output parameter here: the call
asgerf 2015/04/07 13:42:42 But it's a copy of index2value. Could you just cop
Kevin Millikin (Google) 2015/04/08 10:56:59 Yeah, I can do that. I was trying to make it enfo
+ : variable2index = other.variable2index,
+ index2variable = new List<Local>.from(other.index2variable),
+ index2value = other.index2variable.map((Local local) {
+ return new ir.Parameter(local);
+ }).toList() {
+ assert(parameters.isEmpty);
+ index2value.forEach(parameters.add);
+ }
+
get length => index2variable.length;
ir.Primitive operator [](int index) => index2value[index];
@@ -62,6 +76,14 @@ class Environment {
index2value.add(value);
}
+ void discard(int count) {
+ assert(count <= index2variable.length);
+ // The map from variables to their index are shared, so we cannot remove
+ // the mapping in `variable2index`.
+ index2variable.length -= count;
+ index2value.length -= count;
+ }
+
ir.Primitive lookup(Local element) {
assert(invariant(element, variable2index.containsKey(element),
message: "Unknown variable: $element."));
@@ -92,39 +114,110 @@ class Environment {
}
}
-/// A class to collect breaks or continues.
-///
-/// When visiting a potential target of breaks or continues, any breaks or
-/// continues are collected by a JumpCollector and processed later, on demand.
-/// The site of the break or continue is represented by a continuation
-/// invocation that will have its target and arguments filled in later.
-///
-/// The environment of the builder at that point is captured and should not
-/// be subsequently mutated until the jump is resolved.
-class JumpCollector {
+/// The abstract base class of objects that emit jumps to a continuation and
+/// give a handle to the continuation and its environment.
+abstract class JumpCollector {
final JumpTarget target;
- final List<ir.InvokeContinuation> _invocations = <ir.InvokeContinuation>[];
- final List<Environment> _environments = <Environment>[];
- final List<Iterable<LocalVariableElement>> boxedTryVariables =
+
+ ir.Continuation _continuation = null;
+ final Environment _environment;
+
+ final List<Iterable<LocalVariableElement>> _boxedTryVariables =
<Iterable<LocalVariableElement>>[];
- JumpCollector(this.target);
+ JumpCollector(this._environment, this.target);
- bool get isEmpty => _invocations.isEmpty;
- int get length => _invocations.length;
- List<ir.InvokeContinuation> get invocations => _invocations;
- List<Environment> get environments => _environments;
+ /// True if the collector has recorded any jumps to its continuation.
asgerf 2015/04/07 13:42:42 has *not* recorded
Kevin Millikin (Google) 2015/04/08 10:56:59 Done.
+ bool get isEmpty;
- void addJump(IrBuilder builder) {
- // Unbox all variables that were boxed on entry to try blocks between the
- // jump and the target.
- for (Iterable<LocalVariableElement> boxedOnEntry in boxedTryVariables) {
+ /// The continuation encapsulated by this collector.
+ ir.Continuation get continuation;
+
+ /// The compile-time environment to be used for translating code in the body
+ /// of the continuation.
+ Environment get environment;
+
+ /// Emit a jump to the continuation for a given [IrBuilder].
+ void addJump(IrBuilder builder);
+
+ /// Add a set of variables that were boxed on entry to a try block.
+ ///
+ /// Jumps from a try block to targets outside have to unbox the variables
+ /// that were boxed on entry before invoking the target continuation. Call
+ /// this function before translating a try block and call [leaveTry] after
+ /// translating it.
asgerf 2015/04/07 13:42:41 Could you start the comment with "All jumps" inste
Kevin Millikin (Google) 2015/04/08 10:56:59 Done.
+ void enterTry(Iterable<LocalVariableElement> boxedOnEntry) {
+ // The boxed variables are maintained as a stack to make leaving easy.
+ _boxedTryVariables.add(boxedOnEntry);
+ }
+
+ /// Remove the most recently added set of variables boxed on entry to a try
+ /// block.
+ ///
+ /// Call [enterTry] before translating a try block and call this function
+ /// after translating it.
+ void leaveTry() {
+ _boxedTryVariables.removeLast();
+ }
+
+ void _buildTryExit(IrBuilder builder) {
+ for (Iterable<LocalVariableElement> boxedOnEntry in _boxedTryVariables) {
for (LocalVariableElement variable in boxedOnEntry) {
assert(builder.isInMutableVariable(variable));
ir.Primitive value = builder.buildLocalGet(variable);
builder.environment.update(variable, value);
}
}
+ }
+}
+
+/// A class to collect 'forward' jumps.
+///
+/// A forward jump to a continuation in the sense of the CPS translation is
+/// a jump where the jump is emitted before any code in the body of the
+/// continuation is translated. They have the property that continuation
+/// parameters and the environment for the translation of the body can be
+/// determined based on the invocations, before translating the body. A
+/// [ForwardJumpCollector] can encapsulate a continuation where all the
+/// jumps are forward ones.
+///
+/// Examples of forward jumps in the translation are join points of
+/// if-then-else and breaks from loops.
+///
+/// The implementation strategy is that the collector collects invocation
+/// sites and the environments at those sites. Then it constructs a
+/// continuation 'on demand' after all the jumps are seen. It determines
+/// continuation parameters, the environment for the translation of code in
+/// the continuation body, and the arguments at the invocation site only
+/// after all the jumps to the continuation are seen.
+class ForwardJumpCollector extends JumpCollector {
+ final List<ir.InvokeContinuation> _invocations = <ir.InvokeContinuation>[];
+ final List<Environment> _environments = <Environment>[];
asgerf 2015/04/07 13:42:42 Could we rename this to _invocationEnvironments?
Kevin Millikin (Google) 2015/04/08 10:56:59 Done.
+
+ /// Construct a collector with a given base environment.
+ ///
+ /// The base environment is the one in scope at the site that the
+ /// continuation represented by this collector will be bound. The
+ /// environment is copied by the collector. Subsequent mutation of the
+ /// original environment will not effect the collector.
asgerf 2015/04/07 13:42:41 affect
Kevin Millikin (Google) 2015/04/08 10:56:59 Done.
+ ForwardJumpCollector(Environment environment, {JumpTarget target: null})
+ : super(new Environment.from(environment), target);
+
+ bool get isEmpty => _invocations.isEmpty;
+
+ ir.Continuation get continuation {
+ if (_continuation == null) _setContinuation();
+ return _continuation;
+ }
+
+ Environment get environment {
+ if (_continuation == null) _setContinuation();
+ return _environment;
+ }
+
+ void addJump(IrBuilder builder) {
+ assert(_continuation == null);
+ _buildTryExit(builder);
ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized();
builder.add(invoke);
_invocations.add(invoke);
@@ -134,24 +227,111 @@ class JumpCollector {
// less likely to mutate it?
}
- /// Add a set of variables that were boxed on entry to a try block.
- ///
- /// Jumps from a try block to targets outside have to unbox the variables
- /// that were boxed on entry before invoking the target continuation. Call
- /// this function before translating a try block and call [leaveTry] after
- /// translating it.
- void enterTry(Iterable<LocalVariableElement> boxedOnEntry) {
- // The boxed variables are maintained as a stack to make leaving easy.
- boxedTryVariables.add(boxedOnEntry);
+ void _setContinuation() {
+ assert(_continuation == null);
+ // We have seen all invocations of this continuation, and recorded the
+ // environment in effect at each invocation site.
+
+ // Compute the union of the assigned variables reaching the continuation.
+ //
+ // There is a continuation parameter for each environment variable
+ // that has a different value (from the environment in scope at the
+ // continuation binding) on some path. `_environment` is initially a copy
+ // of the environment in scope at the continuation binding. Compute the
+ // continuation parameters and add them to `_environment` so it will become
+ // the one in scope for the continuation body.
asgerf 2015/04/07 13:42:41 '_environment' and 'env' (below) are bad names whe
Kevin Millikin (Google) 2015/04/08 10:56:59 Done.
+ List<ir.Parameter> parameters = <ir.Parameter>[];
+ if (_environments.isNotEmpty) {
+ for (int varIndex = 0; varIndex < _environment.length; ++varIndex) {
+ for (Environment env in _environments) {
+ if (env[varIndex] != _environment[varIndex]) {
+ ir.Parameter parameter =
+ new ir.Parameter(_environment.index2variable[varIndex]);
+ _environment.index2value[varIndex] = parameter;
+ parameters.add(parameter);
+ break;
+ }
+ }
+ }
+ }
+ _continuation = new ir.Continuation(parameters);
+
+ // Compute the intersection of the parameters with the environments at
+ // each continuation invocation. Initialize the invocations.
+ for (int jumpIndex = 0; jumpIndex < _invocations.length; ++jumpIndex) {
+ Environment currentEnvironment = _environments[jumpIndex];
asgerf 2015/04/07 13:42:42 Again, something like 'jumpEnvironment' would be b
+ List<ir.Reference> arguments = <ir.Reference>[];
+ if (parameters.isNotEmpty) {
asgerf 2015/04/07 13:42:42 I think we should make 'parameters' the outer loop
Kevin Millikin (Google) 2015/04/08 10:56:59 Done. It is probably better, though not simpler,
+ arguments.length = parameters.length;
+ int argIndex = 0;
+ for (int varIndex = 0; varIndex < _environment.length; ++varIndex) {
+ if (_environment[varIndex] == parameters[argIndex]) {
+ arguments[argIndex++] =
+ new ir.Reference(currentEnvironment[varIndex]);
+ if (argIndex == parameters.length) break;
+ }
+ }
+ }
+ ir.InvokeContinuation invocation = _invocations[jumpIndex];
+ invocation.continuation = new ir.Reference(_continuation);
+ invocation.arguments = arguments;
+ }
}
+}
- /// Remove the most recently added set of variables boxed on entry to a try
- /// block.
+/// A class to collect 'backward' jumps.
+///
+/// A backward jump to a continuation in the sense of the CPS translation is
+/// a jump where some code in the body of the continuation is translated
+/// before the jump is emitted. They have the property that the
+/// continuation parameters and the environment for the translation of the
+/// body must be determined before emitting all the invocations. A
+/// [BackwardJumpCollector] can ecapsulate a continuation where some jumps
+/// are backward ones.
+///
+/// Examples of backward jumps in the translation are the recursive
+/// invocations of loop continuations.
+///
+/// The implementation strategy is that the collector inserts a continuation
+/// parameter for each variable in scope at the entry to the continuation,
+/// before emitting any jump to the continuation. When a jump is added, it
+/// is given an argument for each continuation parameter.
+class BackwardJumpCollector extends JumpCollector {
+ List<ir.Parameter> _parameters;
+
+ /// Construct a collector with a given base environment.
///
- /// Call [enterTry] before translating a try block and call this function
- /// after translating it.
- void leaveTry() {
- boxedTryVariables.removeLast();
+ /// The base environment is the one in scope at the site that the
+ /// continuation represented by this collector will be bound. The
+ /// translation of the continuation body will use an environment with the
+ /// same shape, but with fresh continuation parameters for each variable.
+ factory BackwardJumpCollector(Environment environment,
+ {JumpTarget target: null}) {
+ List<ir.Parameter> parameters = <ir.Parameter>[];
+ Environment fresh = new Environment.fresh(environment, parameters);
+ return new BackwardJumpCollector._internal(fresh, parameters, target);
+ }
+
+ BackwardJumpCollector._internal(Environment environment,
+ this._parameters,
+ JumpTarget target)
+ : super(environment, target) {
+ _continuation = new ir.Continuation(_parameters, isRecursive: true);
+ }
+
+ bool isEmpty = true;
+
+ ir.Continuation get continuation => _continuation;
+ Environment get environment => _environment;
+
+ void addJump(IrBuilder builder) {
+ assert(_parameters.length <= builder.environment.length);
+ isEmpty = false;
+ _buildTryExit(builder);
+ builder.add(new ir.InvokeContinuation(_continuation,
+ builder.environment.index2value.take(_parameters.length).toList(),
+ isRecursive: true));
+ builder._current = null;
}
}
@@ -366,14 +546,17 @@ abstract class IrBuilder {
/// Construct a delimited visitor for visiting a subtree.
///
- /// The delimited visitor has its own compile-time environment mapping
- /// local variables to their values, which is initially a copy of the parent
- /// environment. It has its own context for building an IR expression, so
- /// the built expression is not plugged into the parent's context.
- IrBuilder makeDelimitedBuilder() {
+ /// Build a subterm that is not (yet) connected to the CPS term. The
+ /// delimited visitor has its own has its own context for building an IR
+ /// expression, so the built expression is not plugged into the parent's
+ /// context. It has its own compile-time environment mapping local
+ /// variables to their values. If an optional environment argument is
+ /// supplied, it is used as the builder's initial environment. Otherwise
+ /// the environment is initially a copy of the parent builder's environment.
+ IrBuilder makeDelimitedBuilder([Environment env = null]) {
return _makeInstance()
..state = state
- ..environment = new Environment.from(environment);
+ ..environment = env != null ? env : new Environment.from(environment);
}
/// Construct a builder for making constructor field initializers.
@@ -580,7 +763,6 @@ abstract class IrBuilder {
ir.Primitive condition,
ir.Primitive buildThenExpression(IrBuilder builder),
ir.Primitive buildElseExpression(IrBuilder builder)) {
-
assert(isOpen);
// The then and else expressions are delimited.
@@ -591,16 +773,23 @@ abstract class IrBuilder {
// Treat the values of the subexpressions as named values in the
// environment, so they will be treated as arguments to the join-point
- // continuation.
+ // continuation. We know the environments are the right size because
+ // expressions cannot introduce variable bindings.
assert(environment.length == thenBuilder.environment.length);
assert(environment.length == elseBuilder.environment.length);
+ // Optimistically assume that the value in the incoming environment is the
+ // value of the first subexpression, which might not even be in scope
+ // because it's bound in the first subexpression. However, if that is the
+ // case, it will necessarily differ from the value of the other
+ // subexpression and cause the introduction of a join-point continuation
+ // parameter. If the two values do happen to be the same, this will
+ // avoid inserting a useless continuation parameter.
asgerf 2015/04/07 13:42:42 I really like using the environment like this. Bef
Kevin Millikin (Google) 2015/04/08 10:56:59 I've mentioned that first, though I thought the co
asgerf 2015/04/08 11:10:21 You are right, I overlooked the comment before the
+ environment.extend(null, thenValue);
thenBuilder.environment.extend(null, thenValue);
elseBuilder.environment.extend(null, elseValue);
- JumpCollector jumps = new JumpCollector(null);
- jumps.addJump(thenBuilder);
- jumps.addJump(elseBuilder);
- ir.Continuation joinContinuation =
- createJoin(environment.length + 1, jumps);
+ JumpCollector join = new ForwardJumpCollector(environment);
+ thenBuilder.jumpTo(join);
+ elseBuilder.jumpTo(join);
// Build the term
// let cont join(x, ..., result) = [] in
@@ -612,15 +801,17 @@ abstract class IrBuilder {
ir.Continuation elseContinuation = new ir.Continuation([]);
thenContinuation.body = thenBuilder._root;
elseContinuation.body = elseBuilder._root;
- add(new ir.LetCont(joinContinuation,
+ add(new ir.LetCont(join.continuation,
new ir.LetCont.many(<ir.Continuation>[thenContinuation,
elseContinuation],
new ir.Branch(new ir.IsTrue(condition),
thenContinuation,
elseContinuation))));
+ environment = join.environment;
+ environment.discard(1);
return (thenValue == elseValue)
? thenValue
- : joinContinuation.parameters.last;
+ : join.continuation.parameters.last;
}
/**
@@ -887,16 +1078,15 @@ abstract class IrBuilder {
thenContinuation,
elseContinuation));
- ir.Continuation joinContinuation; // Null if there is no join.
+ JumpCollector join; // Null if there is no join.
if (thenBuilder.isOpen && elseBuilder.isOpen) {
// There is a join-point continuation. Build the term
// 'let cont join(x, ...) = [] in Result' and plug invocations of the
// join-point continuation into the then and else continuations.
- JumpCollector jumps = new JumpCollector(null);
- jumps.addJump(thenBuilder);
- jumps.addJump(elseBuilder);
- joinContinuation = createJoin(environment.length, jumps);
- result = new ir.LetCont(joinContinuation, result);
+ join = new ForwardJumpCollector(environment);
+ thenBuilder.jumpTo(join);
+ elseBuilder.jumpTo(join);
+ result = new ir.LetCont(join.continuation, result);
}
// The then or else term root could be null, but not both. If there is
@@ -910,7 +1100,7 @@ abstract class IrBuilder {
elseContinuation.body = elseBuilder._root;
add(result);
- if (joinContinuation == null) {
+ if (join == null) {
// At least one subexpression is closed.
if (thenBuilder.isOpen) {
if (thenBuilder._root != null) _current = thenBuilder._current;
@@ -921,43 +1111,21 @@ abstract class IrBuilder {
} else {
_current = null;
}
+ } else {
+ environment = join.environment;
}
}
- void jumpTo(ir.Continuation continuation) {
- assert(isOpen);
- assert(environment.length >= continuation.parameters.length);
- ir.InvokeContinuation jump = new ir.InvokeContinuation.uninitialized();
- jump.continuation = new ir.Reference(continuation);
- jump.arguments = new List<ir.Reference>.generate(
- continuation.parameters.length, (i) {
- return new ir.Reference(environment[i]);
- });
- add(jump);
- _current = null;
+ void jumpTo(JumpCollector collector) {
+ collector.addJump(this);
}
- /// 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}) {
- // TODO(kmillikin): If the JumpCollector collected open IrBuilders instead
- // of pairs of invocations and environments, we could use IrBuilder.jumpTo
- // here --- the code is almost the same.
- 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 addRecursiveContinuation(BackwardJumpCollector collector) {
+ assert(environment.length == collector.environment.length);
+ add(new ir.LetCont(collector.continuation,
+ new ir.InvokeContinuation(collector.continuation,
+ environment.index2value)));
+ environment = collector.environment;
}
/// Creates a for loop in which the initializer, condition, body, update are
@@ -991,7 +1159,7 @@ abstract class IrBuilder {
// [[initializer]];
// let cont loop(x, ...) =
// let prim cond = [[condition]] in
- // let cont break() = [[successor]] in
+ // let cont break(x, ...) = [[successor]] in
// let cont exit() = break(v, ...) in
// let cont body() =
// _enterForLoopBody();
@@ -1009,28 +1177,33 @@ abstract class IrBuilder {
// 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.
-
_enterForLoopInitializer(closureScope, loopVariables);
-
buildInitializer(this);
- IrBuilder condBuilder = makeRecursiveBuilder();
- ir.Primitive condition = buildCondition(condBuilder);
+ JumpCollector loop = new BackwardJumpCollector(environment);
+ addRecursiveContinuation(loop);
+
+ ir.Primitive condition = buildCondition(this);
if (condition == null) {
// If the condition is empty then the body is entered unconditionally.
- condition = condBuilder.buildBooleanLiteral(true);
+ condition = buildBooleanLiteral(true);
}
+ JumpCollector breakCollector =
+ new ForwardJumpCollector(environment, target: target);
- JumpCollector breakCollector = new JumpCollector(target);
- JumpCollector continueCollector = new JumpCollector(target);
- state.breakCollectors.add(breakCollector);
- state.continueCollectors.add(continueCollector);
-
- IrBuilder outerBodyBuilder = condBuilder.makeDelimitedBuilder();
+ // Use a pair of builders for the body, one for the entry code if any
+ // and one for the body itself. We only decide whether to insert a
+ // continue continuation until after translating the body and there is no
+ // way to insert such a continuation between the entry code and the body
+ // if they are translated together.
+ IrBuilder outerBodyBuilder = makeDelimitedBuilder();
outerBodyBuilder._enterForLoopBody(closureScope, loopVariables);
+ JumpCollector continueCollector =
+ new ForwardJumpCollector(outerBodyBuilder.environment, target: target);
IrBuilder innerBodyBuilder = outerBodyBuilder.makeDelimitedBuilder();
-
+ state.breakCollectors.add(breakCollector);
+ state.continueCollectors.add(continueCollector);
buildBody(innerBodyBuilder);
assert(state.breakCollectors.last == breakCollector);
assert(state.continueCollectors.last == continueCollector);
@@ -1040,17 +1213,34 @@ abstract class IrBuilder {
// 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.
+ // is instead placed just outside the translation of the loop body. In
+ // the case where there are no continues in the body, the updates are
+ // translated immediately after the body.
bool hasContinues = !continueCollector.isEmpty;
- IrBuilder updateBuilder = hasContinues
- ? outerBodyBuilder.makeRecursiveBuilder()
- : innerBodyBuilder;
+ IrBuilder updateBuilder;
+ if (hasContinues) {
+ if (innerBodyBuilder.isOpen) innerBodyBuilder.jumpTo(continueCollector);
+ updateBuilder = makeDelimitedBuilder(continueCollector.environment);
+ } else {
+ updateBuilder = innerBodyBuilder;
+ }
updateBuilder._enterForLoopUpdate(closureScope, loopVariables);
buildUpdate(updateBuilder);
+ if (updateBuilder.isOpen) updateBuilder.jumpTo(loop);
+ // Connect the inner and outer body builders. This is done only after
+ // it is guaranteed that the updateBuilder has a non-empty term.
+ if (hasContinues) {
+ outerBodyBuilder.add(new ir.LetCont(continueCollector.continuation,
+ innerBodyBuilder._root));
+ continueCollector.continuation.body = updateBuilder._root;
+ } else {
+ outerBodyBuilder.add(innerBodyBuilder._root);
+ }
- // Create body entry and loop exit continuations and a branch to them.
- ir.Continuation bodyContinuation = new ir.Continuation([]);
+ // Create loop exit and body entry continuations and a branch to them.
ir.Continuation exitContinuation = new ir.Continuation([]);
+ ir.Continuation bodyContinuation = new ir.Continuation([]);
+ bodyContinuation.body = outerBodyBuilder._root;
// Note the order of continuations: the first one is the one that will
// be filled by LetCont.plug.
ir.LetCont branch =
@@ -1060,57 +1250,19 @@ abstract class IrBuilder {
bodyContinuation,
exitContinuation));
// If there are breaks in the body, then there must be a join-point
- // continuation for the normal exit and the breaks.
+ // continuation for the normal exit and the breaks. Otherwise, the
+ // successor is translated in the hole in the exit continuation.
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 (innerBodyBuilder.isOpen) continueCollector.addJump(innerBodyBuilder);
- 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;
- outerBodyBuilder.add(new ir.LetCont(continueContinuation,
- innerBodyBuilder._root));
- } else {
- outerBodyBuilder.add(innerBodyBuilder._root);
- }
- bodyContinuation.body = outerBodyBuilder._root;
-
- loopContinuation.body = condBuilder._root;
- add(new ir.LetCont(loopContinuation,
- new ir.InvokeContinuation(loopContinuation,
- environment.index2value)));
+ ir.LetCont letBreak;
if (hasBreaks) {
- _current = branch;
- environment = condBuilder.environment;
- breakCollector.addJump(this);
- letJoin.continuations =
- <ir.Continuation>[createJoin(environment.length, breakCollector)];
- _current = letJoin;
+ IrBuilder exitBuilder = makeDelimitedBuilder();
+ exitBuilder.jumpTo(breakCollector);
+ exitContinuation.body = exitBuilder._root;
+ letBreak = new ir.LetCont(breakCollector.continuation, branch);
+ add(letBreak);
+ environment = breakCollector.environment;
} else {
- _current = condBuilder._current;
- environment = condBuilder.environment;
+ add(branch);
}
}
@@ -1149,37 +1301,50 @@ abstract class IrBuilder {
// s;
// }
- // The condition and body are delimited.
- IrBuilder condBuilder = makeRecursiveBuilder();
-
+ // Fill the current hole with:
+ // let prim expressionReceiver = [[e]] in
+ // let cont iteratorInvoked(iterator) =
+ // [ ]
+ // in expressionReceiver.iterator () iteratorInvoked
ir.Primitive expressionReceiver = buildExpression(this);
- List<ir.Primitive> emptyArguments = new List<ir.Primitive>();
-
+ List<ir.Primitive> emptyArguments = <ir.Primitive>[];
ir.Parameter iterator = new ir.Parameter(null);
ir.Continuation iteratorInvoked = new ir.Continuation([iterator]);
add(new ir.LetCont(iteratorInvoked,
new ir.InvokeMethod(expressionReceiver,
- new Selector.getter("iterator", null), iteratorInvoked,
+ new Selector.getter("iterator", null),
+ iteratorInvoked,
emptyArguments)));
+ // Fill with:
+ // let cont loop(x, ...) =
+ // let cont moveNextInvoked(condition) =
+ // [ ]
+ // in iterator.moveNext () moveNextInvoked
+ // in loop(v, ...)
+ JumpCollector loop = new BackwardJumpCollector(environment, target: target);
+ addRecursiveContinuation(loop);
ir.Parameter condition = new ir.Parameter(null);
ir.Continuation moveNextInvoked = new ir.Continuation([condition]);
- condBuilder.add(new ir.LetCont(moveNextInvoked,
+ add(new ir.LetCont(moveNextInvoked,
new ir.InvokeMethod(iterator,
new Selector.call("moveNext", null, 0),
- moveNextInvoked, emptyArguments)));
-
- JumpCollector breakCollector = new JumpCollector(target);
- JumpCollector continueCollector = new JumpCollector(target);
- state.breakCollectors.add(breakCollector);
- state.continueCollectors.add(continueCollector);
+ moveNextInvoked,
+ emptyArguments)));
- IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder();
+ // As a delimited term, build:
+ // <<BODY>> =
+ // _enterScope();
+ // [[variableDeclaration]]
+ // let cont currentInvoked(currentValue) =
+ // [[a = currentValue]];
+ // [ ]
+ // in iterator.current () currentInvoked
+ IrBuilder bodyBuilder = makeDelimitedBuilder();
bodyBuilder._enterScope(closureScope);
if (buildVariableDeclaration != null) {
buildVariableDeclaration(bodyBuilder);
}
-
ir.Parameter currentValue = new ir.Parameter(null);
ir.Continuation currentInvoked = new ir.Continuation([currentValue]);
bodyBuilder.add(new ir.LetCont(currentInvoked,
@@ -1198,15 +1363,27 @@ abstract class IrBuilder {
bodyBuilder.buildDynamicSet(receiver, variableSelector, currentValue);
}
+ // Translate the body in the hole in the delimited term above, and add
+ // a jump to the loop if control flow is live after the body.
+ JumpCollector breakCollector =
+ new ForwardJumpCollector(environment, target: target);
+ state.breakCollectors.add(breakCollector);
+ state.continueCollectors.add(loop);
buildBody(bodyBuilder);
assert(state.breakCollectors.last == breakCollector);
- assert(state.continueCollectors.last == continueCollector);
+ assert(state.continueCollectors.last == loop);
state.breakCollectors.removeLast();
state.continueCollectors.removeLast();
+ if (bodyBuilder.isOpen) bodyBuilder.jumpTo(loop);
// Create body entry and loop exit continuations and a branch to them.
- ir.Continuation bodyContinuation = new ir.Continuation([]);
+ //
+ // let cont exit() = [ ]
+ // and body() = <<BODY>>
+ // in branch condition (body, exit)
ir.Continuation exitContinuation = new ir.Continuation([]);
+ ir.Continuation bodyContinuation = new ir.Continuation([]);
+ bodyContinuation.body = bodyBuilder._root;
// Note the order of continuations: the first one is the one that will
// be filled by LetCont.plug.
ir.LetCont branch =
@@ -1216,37 +1393,19 @@ abstract class IrBuilder {
bodyContinuation,
exitContinuation));
// If there are breaks in the body, then there must be a join-point
- // continuation for the normal exit and the breaks.
+ // continuation for the normal exit and the breaks. Otherwise, the
+ // successor is translated in the hole in the exit continuation.
bool hasBreaks = !breakCollector.isEmpty;
- ir.LetCont letJoin;
+ ir.LetCont letBreak;
if (hasBreaks) {
- letJoin = new ir.LetCont(null, branch);
- condBuilder.add(letJoin);
- condBuilder._current = branch;
+ IrBuilder exitBuilder = makeDelimitedBuilder();
+ exitBuilder.jumpTo(breakCollector);
+ exitContinuation.body = exitBuilder._root;
+ letBreak = new ir.LetCont(breakCollector.continuation, branch);
+ add(letBreak);
+ environment = breakCollector.environment;
} else {
- condBuilder.add(branch);
- }
- ir.Continuation loopContinuation =
- new ir.Continuation(condBuilder._parameters);
- if (bodyBuilder.isOpen) continueCollector.addJump(bodyBuilder);
- invokeFullJoin(
- loopContinuation, continueCollector, recursive: true);
- 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.continuations =
- <ir.Continuation>[createJoin(environment.length, breakCollector)];
- _current = letJoin;
- } else {
- _current = condBuilder._current;
- environment = condBuilder.environment;
+ add(branch);
}
}
@@ -1268,34 +1427,39 @@ abstract class IrBuilder {
// let prim cond = [[condition]] in
// let cont break(x, ...) = [[successor]] in
// let cont exit() = break(v, ...)
- // and body() = [[body]]; continue(v, ...)
+ // and body() =
+ // _enterScope();
+ // [[body]];
+ // continue(v, ...)
// in branch cond (body, exit)
// in continue(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).
+ JumpCollector loop = new BackwardJumpCollector(environment, target: target);
+ addRecursiveContinuation(loop);
- // The condition and body are delimited.
- IrBuilder condBuilder = makeRecursiveBuilder();
- ir.Primitive condition = buildCondition(condBuilder);
+ ir.Primitive condition = buildCondition(this);
- JumpCollector breakCollector = new JumpCollector(target);
- JumpCollector continueCollector = new JumpCollector(target);
- state.breakCollectors.add(breakCollector);
- state.continueCollectors.add(continueCollector);
+ JumpCollector breakCollector =
+ new ForwardJumpCollector(environment, target: target);
- IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder();
+ IrBuilder bodyBuilder = makeDelimitedBuilder();
bodyBuilder._enterScope(closureScope);
+ state.breakCollectors.add(breakCollector);
+ state.continueCollectors.add(loop);
buildBody(bodyBuilder);
assert(state.breakCollectors.last == breakCollector);
- assert(state.continueCollectors.last == continueCollector);
+ assert(state.continueCollectors.last == loop);
state.breakCollectors.removeLast();
state.continueCollectors.removeLast();
+ if (bodyBuilder.isOpen) bodyBuilder.jumpTo(loop);
// 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.Continuation bodyContinuation = new ir.Continuation([]);
+ bodyContinuation.body = bodyBuilder._root;
// Note the order of continuations: the first one is the one that will
// be filled by LetCont.plug.
ir.LetCont branch =
@@ -1305,36 +1469,19 @@ abstract class IrBuilder {
bodyContinuation,
exitContinuation));
// If there are breaks in the body, then there must be a join-point
- // continuation for the normal exit and the breaks.
+ // continuation for the normal exit and the breaks. Otherwise, the
+ // successor is translated in the hole in the exit continuation.
bool hasBreaks = !breakCollector.isEmpty;
- ir.LetCont letJoin;
+ ir.LetCont letBreak;
if (hasBreaks) {
- letJoin = new ir.LetCont(null, branch);
- condBuilder.add(letJoin);
- condBuilder._current = branch;
+ IrBuilder exitBuilder = makeDelimitedBuilder();
+ exitBuilder.jumpTo(breakCollector);
+ exitContinuation.body = exitBuilder._root;
+ letBreak = new ir.LetCont(breakCollector.continuation, branch);
+ add(letBreak);
+ environment = breakCollector.environment;
} else {
- condBuilder.add(branch);
- }
- ir.Continuation loopContinuation =
- new ir.Continuation(condBuilder._parameters);
- if (bodyBuilder.isOpen) continueCollector.addJump(bodyBuilder);
- invokeFullJoin(loopContinuation, continueCollector, recursive: true);
- 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.continuations =
- <ir.Continuation>[createJoin(environment.length, breakCollector)];
- _current = letJoin;
- } else {
- _current = condBuilder._current;
- environment = condBuilder.environment;
+ add(branch);
}
}
@@ -1362,99 +1509,66 @@ abstract class IrBuilder {
// in branch cond (repeat, exit)
// in [[body]]; continue(v, ...)
// in loop(v, ...)
- IrBuilder bodyBuilder = makeRecursiveBuilder();
- IrBuilder continueBuilder = bodyBuilder.makeRecursiveBuilder();
+ IrBuilder loopBuilder = makeDelimitedBuilder();
+ JumpCollector loop =
+ new BackwardJumpCollector(loopBuilder.environment, target: target);
+ loopBuilder.addRecursiveContinuation(loop);
+
+ // Translate the body.
+ JumpCollector breakCollector =
+ new ForwardJumpCollector(environment, target: target);
+ JumpCollector continueCollector =
+ new ForwardJumpCollector(loopBuilder.environment, target: target);
+ IrBuilder bodyBuilder = loopBuilder.makeDelimitedBuilder();
+ bodyBuilder._enterScope(closureScope);
+ state.breakCollectors.add(breakCollector);
+ state.continueCollectors.add(continueCollector);
+ buildBody(bodyBuilder);
+ assert(state.breakCollectors.last == breakCollector);
+ assert(state.continueCollectors.last == continueCollector);
+ state.breakCollectors.removeLast();
+ state.continueCollectors.removeLast();
+ if (bodyBuilder.isOpen) bodyBuilder.jumpTo(continueCollector);
- // Construct the continue continuation (i.e., the condition).
+ // Construct the body of the continue continuation (i.e., the condition).
// <Continue> =
// let prim cond = [[condition]] in
// let cont exit() = break(v, ...)
// and repeat() = loop(v, ...)
// in branch cond (repeat, exit)
+ IrBuilder continueBuilder = loopBuilder.makeDelimitedBuilder();
+ continueBuilder.environment = continueCollector.environment;
ir.Primitive condition = buildCondition(continueBuilder);
- // Use a delimited IrBuilder for the exit continuation's body so that
- // we can capture the break with the body's break collector.
+
ir.Continuation exitContinuation = new ir.Continuation([]);
IrBuilder exitBuilder = continueBuilder.makeDelimitedBuilder();
+ exitBuilder.jumpTo(breakCollector);
+ exitContinuation.body = exitBuilder._root;
ir.Continuation repeatContinuation = new ir.Continuation([]);
- ir.InvokeContinuation invokeLoop =
- new ir.InvokeContinuation.uninitialized(recursive: true);
- invokeLoop.arguments =
- continueBuilder.environment.index2value.map(
- (ir.Primitive value) => new ir.Reference(value)).toList();
- repeatContinuation.body = invokeLoop;
+ IrBuilder repeatBuilder = continueBuilder.makeDelimitedBuilder();
+ repeatBuilder.jumpTo(loop);
+ repeatContinuation.body = repeatBuilder._root;
+
continueBuilder.add(
new ir.LetCont.many(<ir.Continuation>[exitContinuation,
repeatContinuation],
new ir.Branch(new ir.IsTrue(condition),
repeatContinuation,
exitContinuation)));
- ir.Continuation continueContinuation =
- new ir.Continuation(continueBuilder._parameters);
- continueContinuation.body = continueBuilder._root;
+ continueCollector.continuation.body = continueBuilder._root;
// Construct the loop continuation (i.e., the body and condition).
// <Loop> =
// let cont continue(x, ...) =
// <Continue>
// in [[body]]; continue(v, ...)
- JumpCollector breakCollector = new JumpCollector(target);
- JumpCollector continueCollector = new JumpCollector(target);
- state.breakCollectors.add(breakCollector);
- state.continueCollectors.add(continueCollector);
- bodyBuilder._enterScope(closureScope);
- buildBody(bodyBuilder);
- assert(state.breakCollectors.last == breakCollector);
- assert(state.continueCollectors.last == continueCollector);
- state.breakCollectors.removeLast();
- state.continueCollectors.removeLast();
- // Add the jump from the loop's exit to the break condition. It is only
- // here where the exitBuilder's root is non-null and we can set the
- // exitContinuation's body.
- breakCollector.addJump(exitBuilder);
- exitContinuation.body = exitBuilder._root;
- if (bodyBuilder.isOpen) {
- continueCollector.addJump(bodyBuilder);
- }
- invokeFullJoin(continueContinuation, continueCollector, recursive: false);
- ir.Continuation loopContinuation =
- new ir.Continuation(bodyBuilder._parameters);
- loopContinuation.isRecursive = true;
- loopContinuation.body =
- new ir.LetCont(continueContinuation, bodyBuilder._root);
- invokeLoop.continuation =
- new ir.Reference<ir.Continuation>(loopContinuation);
- ir.LetCont letLoop =
- new ir.LetCont(loopContinuation,
- new ir.InvokeContinuation(loopContinuation,
- environment.index2value));
-
- // Add the break condition.
- ir.Continuation breakContinuation;
- if (breakCollector.length == 1) {
- // createJoin only works when there is more than one jump to a join-point
- // continuation. This is to potentially catch errors in the case that
- // a join was intended and at least one jump is missing. Unfortunately
- // we have the explicit code below for the (common?) case that the
- // only break from the do-while is the implicit one when the condition
- // is false.
- List<ir.Parameter> parameters = <ir.Parameter>[];
- List<ir.Reference> arguments = <ir.Reference>[];
- for (int i = 0; i < environment.length; ++i) {
- ir.Parameter parameter =
- new ir.Parameter(environment.index2variable[i]);
- parameters.add(parameter);
- environment.index2value[i] = parameter;
- arguments.add(new ir.Reference(breakCollector.environments.first[i]));
- }
- breakContinuation = new ir.Continuation(parameters);
- breakCollector.invocations.first.arguments = arguments;
- breakCollector.invocations.first.continuation =
- new ir.Reference(breakContinuation);
- } else {
- breakContinuation = createJoin(environment.length, breakCollector);
- }
- add(new ir.LetCont(breakContinuation, letLoop));
+ loopBuilder.add(
+ new ir.LetCont(continueCollector.continuation,
+ bodyBuilder._root));
+
+ // And tie it all together.
+ add(new ir.LetCont(breakCollector.continuation, loopBuilder._root));
+ environment = breakCollector.environment;
}
/// Creates a try-statement.
@@ -1499,14 +1613,15 @@ abstract class IrBuilder {
// scope of the handler. The mutable bindings are dereferenced at the end
// of the try block and at the beginning of the catch block, so the
// variables are unboxed in the catch block and at the join point.
-
+ JumpCollector join = new ForwardJumpCollector(environment);
IrBuilder tryCatchBuilder = makeDelimitedBuilder();
+
// Variables that are boxed due to being captured in a closure are boxed
// for their entire lifetime, and so they do not need to be boxed on
- // entry to any try block. We check for them here because we can not
- // identify all of them in the same pass where we identify the variables
- // assigned in the try (the may be captured by a closure after the try
- // statement).
+ // entry to any try block. They are not filtered out before this because
+ // we can not identify all of them in the same pass where we identify the
+ // variables assigned in the try (they may be captured by a closure after
+ // the try statement).
Iterable<LocalVariableElement> boxedOnEntry =
tryStatementInfo.boxedOnEntry.where((LocalVariableElement variable) {
return !tryCatchBuilder.mutableCapturedVariables.contains(variable);
@@ -1518,34 +1633,26 @@ abstract class IrBuilder {
tryCatchBuilder.declareLocalVariable(variable, initialValue: value);
}
- IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder();
IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder();
- List<ir.Parameter> joinParameters =
- new List<ir.Parameter>.generate(environment.length, (i) {
- return new ir.Parameter(environment.index2variable[i]);
- });
- ir.Continuation joinContinuation = new ir.Continuation(joinParameters);
void interceptJumps(JumpCollector collector) {
collector.enterTry(boxedOnEntry);
}
- void restoreJumps(JumpCollector collector) {
- collector.leaveTry();
- }
tryBuilder.state.breakCollectors.forEach(interceptJumps);
tryBuilder.state.continueCollectors.forEach(interceptJumps);
buildTryBlock(tryBuilder);
+ void restoreJumps(JumpCollector collector) {
+ collector.leaveTry();
+ }
tryBuilder.state.breakCollectors.forEach(restoreJumps);
tryBuilder.state.continueCollectors.forEach(restoreJumps);
if (tryBuilder.isOpen) {
- for (LocalVariableElement variable in boxedOnEntry) {
- assert(tryBuilder.isInMutableVariable(variable));
- ir.Primitive value = tryBuilder.buildLocalGet(variable);
- tryBuilder.environment.update(variable, value);
- }
- tryBuilder.jumpTo(joinContinuation);
+ interceptJumps(join);
+ tryBuilder.jumpTo(join);
+ restoreJumps(join);
}
asgerf 2015/04/07 13:42:42 I may be nitpicking now, but could we please resto
Kevin Millikin (Google) 2015/04/08 10:56:59 That's fine. I can even restore the break and con
asgerf 2015/04/08 11:10:21 Just don't do breakCollectors.reversed.forEach(res
+ IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder();
for (LocalVariableElement variable in boxedOnEntry) {
assert(catchBuilder.isInMutableVariable(variable));
ir.Primitive value = catchBuilder.buildLocalGet(variable);
@@ -1577,9 +1684,7 @@ abstract class IrBuilder {
traceParameter = new ir.Parameter(null);
}
catchClauseInfo.buildCatchBlock(catchBuilder);
- if (catchBuilder.isOpen) {
- catchBuilder.jumpTo(joinContinuation);
- }
+ if (catchBuilder.isOpen) catchBuilder.jumpTo(join);
List<ir.Parameter> catchParameters =
<ir.Parameter>[exceptionParameter, traceParameter];
ir.Continuation catchContinuation = new ir.Continuation(catchParameters);
@@ -1590,10 +1695,8 @@ abstract class IrBuilder {
tryCatchBuilder._current = null;
}
- add(new ir.LetCont(joinContinuation, tryCatchBuilder._root));
- for (int i = 0; i < environment.length; ++i) {
- environment.index2value[i] = joinParameters[i];
- }
+ add(new ir.LetCont(join.continuation, tryCatchBuilder._root));
+ environment = join.environment;
}
/// Create a return statement `return value;` or `return;` if [value] is
@@ -1634,48 +1737,26 @@ abstract class IrBuilder {
}
}
-
/// Creates a labeled statement
void buildLabeledStatement({SubbuildFunction buildBody,
JumpTarget target}) {
- JumpCollector jumps = new JumpCollector(target);
- state.breakCollectors.add(jumps);
+ JumpCollector join = new ForwardJumpCollector(environment, target: target);
IrBuilder innerBuilder = makeDelimitedBuilder();
+ innerBuilder.state.breakCollectors.add(join);
buildBody(innerBuilder);
- state.breakCollectors.removeLast();
- bool hasBreaks = !jumps.isEmpty;
- ir.Continuation joinContinuation;
+ innerBuilder.state.breakCollectors.removeLast();
+ bool hasBreaks = !join.isEmpty;
if (hasBreaks) {
- if (innerBuilder.isOpen) {
- jumps.addJump(innerBuilder);
- }
-
- // All jumps to the break continuation must be in the scope of the
- // continuation's binding. The continuation is bound just outside the
- // body to satisfy this property without extra analysis.
- // As a consequence, the break continuation needs parameters for all
- // local variables in scope at the exit from the body.
- List<ir.Parameter> parameters =
- new List<ir.Parameter>.generate(environment.length, (i) {
- return new ir.Parameter(environment.index2variable[i]);
- });
- joinContinuation = new ir.Continuation(parameters);
- invokeFullJoin(joinContinuation, jumps, recursive: false);
- add(new ir.LetCont(joinContinuation, innerBuilder._root));
- for (int i = 0; i < environment.length; ++i) {
- environment.index2value[i] = parameters[i];
- }
- } else {
- if (innerBuilder._root != null) {
- add(innerBuilder._root);
- _current = innerBuilder._current;
- environment = innerBuilder.environment;
- }
+ if (innerBuilder.isOpen) innerBuilder.jumpTo(join);
+ add(new ir.LetCont(join.continuation, innerBuilder._root));
+ environment = join.environment;
+ } else if (innerBuilder._root != null) {
+ add(innerBuilder._root);
+ _current = innerBuilder._current;
+ environment = innerBuilder.environment;
}
asgerf 2015/04/07 13:42:41 Could we have an else with a comment saying that t
Kevin Millikin (Google) 2015/04/08 10:56:59 Done.
- return null;
}
-
// Build(BreakStatement L, C) = C[InvokeContinuation(...)]
//
// The continuation and arguments are filled in later after translating
@@ -1697,7 +1778,7 @@ abstract class IrBuilder {
assert(isOpen);
for (JumpCollector collector in collectors) {
if (target == collector.target) {
- collector.addJump(this);
+ jumpTo(collector);
return true;
}
}
@@ -1765,7 +1846,6 @@ abstract class IrBuilder {
// e0 || e1 is translated as if e0 ? true : (e1 == true).
// The translation must convert both e0 and e1 to booleans and handle
// local variable assignments in e1.
-
IrBuilder rightBuilder = makeDelimitedBuilder();
ir.Primitive rightValue = buildRightValue(rightBuilder);
// A dummy empty target for the branch on the left subexpression branch.
@@ -1792,18 +1872,19 @@ abstract class IrBuilder {
assert(environment.length == emptyBuilder.environment.length);
assert(environment.length == rightTrueBuilder.environment.length);
assert(environment.length == rightFalseBuilder.environment.length);
+ // Treat the value of the expression as a local variable so it will get
+ // a continuation parameter.
+ environment.extend(null, null);
asgerf 2015/04/07 13:42:42 I love this!
emptyBuilder.environment.extend(null, leftBool);
rightTrueBuilder.environment.extend(null, rightTrue);
rightFalseBuilder.environment.extend(null, rightFalse);
// Wire up two continuations for the left subexpression, two continuations
// for the right subexpression, and a three-way join continuation.
- JumpCollector jumps = new JumpCollector(null);
- jumps.addJump(emptyBuilder);
- jumps.addJump(rightTrueBuilder);
- jumps.addJump(rightFalseBuilder);
- ir.Continuation joinContinuation =
- createJoin(environment.length + 1, jumps);
+ JumpCollector join = new ForwardJumpCollector(environment);
+ emptyBuilder.jumpTo(join);
+ rightTrueBuilder.jumpTo(join);
+ rightFalseBuilder.jumpTo(join);
ir.Continuation leftTrueContinuation = new ir.Continuation([]);
ir.Continuation leftFalseContinuation = new ir.Continuation([]);
ir.Continuation rightTrueContinuation = new ir.Continuation([]);
@@ -1828,120 +1909,17 @@ abstract class IrBuilder {
leftFalseContinuation.body = emptyBuilder._root;
}
- add(new ir.LetCont(joinContinuation,
+ add(new ir.LetCont(join.continuation,
new ir.LetCont.many(<ir.Continuation>[leftTrueContinuation,
leftFalseContinuation],
new ir.Branch(new ir.IsTrue(leftValue),
leftTrueContinuation,
leftFalseContinuation))));
+ environment = join.environment;
+ environment.discard(1);
// There is always a join parameter for the result value, because it
// is different on at least two paths.
- return joinContinuation.parameters.last;
- }
-
- /// Create a non-recursive join-point continuation.
- ///
- /// Given the environment length at the join point and a list of
- /// jumps that should reach the join point, create a join-point
- /// continuation. The join-point continuation has a parameter for each
- /// variable that has different values reaching on different paths.
- ///
- /// The jumps are uninitialized [ir.InvokeContinuation] expressions.
- /// They are filled in with the target continuation and appropriate
- /// arguments.
- ///
- /// As a side effect, the environment of this builder is updated to include
- /// the join-point continuation parameters.
- ir.Continuation createJoin(int environmentLength, JumpCollector jumps) {
- assert(jumps.length >= 2);
-
- // Compute which values are identical on all paths reaching the join.
- // Handle the common case of a pair of contexts efficiently.
- Environment first = jumps.environments[0];
- Environment second = jumps.environments[1];
- assert(environmentLength <= first.length);
- assert(environmentLength <= second.length);
- assert(first.sameDomain(environmentLength, second));
- // A running count of the join-point parameters.
- int parameterCount = 0;
- // The null elements of common correspond to required parameters of the
- // join-point continuation.
- List<ir.Primitive> common =
- new List<ir.Primitive>.generate(environmentLength,
- (i) {
- ir.Primitive candidate = first[i];
- if (second[i] == candidate) {
- return candidate;
- } else {
- ++parameterCount;
- return null;
- }
- });
- // If there is already a parameter for each variable, the other
- // environments do not need to be considered.
- if (parameterCount < environmentLength) {
- for (int i = 0; i < environmentLength; ++i) {
- ir.Primitive candidate = common[i];
- if (candidate == null) continue;
- for (Environment current in jumps.environments.skip(2)) {
- assert(environmentLength <= current.length);
- assert(first.sameDomain(environmentLength, current));
- if (candidate != current[i]) {
- common[i] = null;
- ++parameterCount;
- break;
- }
- }
- if (parameterCount >= environmentLength) break;
- }
- }
-
- // Create the join point continuation.
- List<ir.Parameter> parameters = <ir.Parameter>[];
- parameters.length = parameterCount;
- int index = 0;
- for (int i = 0; i < environmentLength; ++i) {
- if (common[i] == null) {
- parameters[index++] = new ir.Parameter(first.index2variable[i]);
- }
- }
- assert(index == parameterCount);
- ir.Continuation join = new ir.Continuation(parameters);
-
- // Fill in all the continuation invocations.
- for (int i = 0; i < jumps.length; ++i) {
- Environment currentEnvironment = jumps.environments[i];
- ir.InvokeContinuation invoke = jumps.invocations[i];
- // Sharing this.environment with one of the invocations will not do
- // the right thing (this.environment has already been mutated).
- List<ir.Reference> arguments = <ir.Reference>[];
- arguments.length = parameterCount;
- int index = 0;
- for (int i = 0; i < environmentLength; ++i) {
- if (common[i] == null) {
- arguments[index++] = new ir.Reference(currentEnvironment[i]);
- }
- }
- invoke.continuation = new ir.Reference(join);
- invoke.arguments = arguments;
- }
-
- // Mutate this.environment to be the environment at the join point. Do
- // this after adding the continuation invocations, because this.environment
- // might be collected by the jump collector and so the old environment
- // values are needed for the continuation invocation.
- //
- // Iterate to environment.length because environmentLength includes values
- // outside the environment which are 'phantom' variables used for the
- // values of expressions like &&, ||, and ?:.
- index = 0;
- for (int i = 0; i < environment.length; ++i) {
- if (common[i] == null) {
- environment.index2value[i] = parameters[index++];
- }
- }
-
asgerf 2015/04/07 13:42:42 I think red is my new favorite color.
- return join;
+ return join.continuation.parameters.last;
}
}
« no previous file with comments | « no previous file | pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698