mirror of
https://github.com/dart-lang/sdk
synced 2024-09-19 14:32:49 +00:00
dart2dart: Support for break in loops.
Break is supported by collecting all the exits from the loop body and processing them after the loop body is translated. If there are any, a join-point continuation for all the exits is added. This continuation should be in the scope of the nearest common ancestor of all the exits --- which is the scope of the condition since the branch on the condition always has an exit. BUG= R=floitsch@google.com, sigurdm@google.com Review URL: https://codereview.chromium.org//469263002 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@39290 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
b0a1da2971
commit
ee5635056f
|
@ -137,12 +137,19 @@ class _GetterElements {
|
||||||
_GetterElements({this.result, this.index, this.receiver}) ;
|
_GetterElements({this.result, this.index, this.receiver}) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/// A mapping from variable elements to their compile-time values.
|
||||||
*
|
///
|
||||||
*/
|
/// Map elements denoted by parameters and local variables to the
|
||||||
|
/// [ir.Primitive] that is their value. Parameters and locals are
|
||||||
|
/// assigned indexes which can be used to refer to them.
|
||||||
class Environment {
|
class Environment {
|
||||||
|
/// A map from elements to their environment index.
|
||||||
final Map<Element, int> variable2index;
|
final Map<Element, int> variable2index;
|
||||||
|
|
||||||
|
/// A reverse map from environment indexes to the variable.
|
||||||
final List<Element> index2variable;
|
final List<Element> index2variable;
|
||||||
|
|
||||||
|
/// A map from environment indexes to their value.
|
||||||
final List<ir.Primitive> index2value;
|
final List<ir.Primitive> index2value;
|
||||||
|
|
||||||
Environment.empty()
|
Environment.empty()
|
||||||
|
@ -150,6 +157,9 @@ class Environment {
|
||||||
index2variable = <Element>[],
|
index2variable = <Element>[],
|
||||||
index2value = <ir.Primitive>[];
|
index2value = <ir.Primitive>[];
|
||||||
|
|
||||||
|
/// Construct an environment that is a copy of another one.
|
||||||
|
///
|
||||||
|
/// The mapping from elements to indexes is shared, not copied.
|
||||||
Environment.from(Environment other)
|
Environment.from(Environment other)
|
||||||
: variable2index = other.variable2index,
|
: variable2index = other.variable2index,
|
||||||
index2variable = new List<Element>.from(other.index2variable),
|
index2variable = new List<Element>.from(other.index2variable),
|
||||||
|
@ -202,6 +212,38 @@ 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 {
|
||||||
|
final JumpTarget target;
|
||||||
|
final List<ir.InvokeContinuation> _invocations = <ir.InvokeContinuation>[];
|
||||||
|
final List<Environment> _environments = <Environment>[];
|
||||||
|
|
||||||
|
JumpCollector(this.target);
|
||||||
|
|
||||||
|
bool get isEmpty => _invocations.isEmpty;
|
||||||
|
int get length => _invocations.length;
|
||||||
|
List<ir.InvokeContinuation> get invocations => _invocations;
|
||||||
|
List<Environment> get environments => _environments;
|
||||||
|
|
||||||
|
void addJump(IrBuilder builder) {
|
||||||
|
ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized();
|
||||||
|
builder.add(invoke);
|
||||||
|
_invocations.add(invoke);
|
||||||
|
_environments.add(builder.environment);
|
||||||
|
builder.current = null;
|
||||||
|
// TODO(kmillikin): Can we set builder.environment to null to make it
|
||||||
|
// less likely to mutate it?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A tree visitor that builds [IrNodes]. The visit methods add statements using
|
* A tree visitor that builds [IrNodes]. The visit methods add statements using
|
||||||
* to the [builder] and return the last added statement for trees that represent
|
* to the [builder] and return the last added statement for trees that represent
|
||||||
|
@ -260,6 +302,9 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
||||||
/// A map from variable indexes to their values.
|
/// A map from variable indexes to their values.
|
||||||
Environment environment;
|
Environment environment;
|
||||||
|
|
||||||
|
/// A stack of collectors for breaks.
|
||||||
|
final List<JumpCollector> breakCollectors;
|
||||||
|
|
||||||
ConstExpBuilder constantBuilder;
|
ConstExpBuilder constantBuilder;
|
||||||
|
|
||||||
final List<ConstDeclaration> localConstants;
|
final List<ConstDeclaration> localConstants;
|
||||||
|
@ -272,6 +317,7 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
||||||
: returnContinuation = new ir.Continuation.retrn(),
|
: returnContinuation = new ir.Continuation.retrn(),
|
||||||
parameters = <ir.Parameter>[],
|
parameters = <ir.Parameter>[],
|
||||||
environment = new Environment.empty(),
|
environment = new Environment.empty(),
|
||||||
|
breakCollectors = <JumpCollector>[],
|
||||||
localConstants = <ConstDeclaration>[],
|
localConstants = <ConstDeclaration>[],
|
||||||
closureLocals = new DetectClosureVariables(elements),
|
closureLocals = new DetectClosureVariables(elements),
|
||||||
super(elements, compiler) {
|
super(elements, compiler) {
|
||||||
|
@ -289,6 +335,7 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
||||||
returnContinuation = parent.returnContinuation,
|
returnContinuation = parent.returnContinuation,
|
||||||
parameters = <ir.Parameter>[],
|
parameters = <ir.Parameter>[],
|
||||||
environment = new Environment.from(parent.environment),
|
environment = new Environment.from(parent.environment),
|
||||||
|
breakCollectors = parent.breakCollectors,
|
||||||
constantBuilder = parent.constantBuilder,
|
constantBuilder = parent.constantBuilder,
|
||||||
localConstants = parent.localConstants,
|
localConstants = parent.localConstants,
|
||||||
currentFunction = parent.currentFunction,
|
currentFunction = parent.currentFunction,
|
||||||
|
@ -308,6 +355,7 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
||||||
returnContinuation = parent.returnContinuation,
|
returnContinuation = parent.returnContinuation,
|
||||||
parameters = <ir.Parameter>[],
|
parameters = <ir.Parameter>[],
|
||||||
environment = new Environment.empty(),
|
environment = new Environment.empty(),
|
||||||
|
breakCollectors = parent.breakCollectors,
|
||||||
constantBuilder = parent.constantBuilder,
|
constantBuilder = parent.constantBuilder,
|
||||||
localConstants = parent.localConstants,
|
localConstants = parent.localConstants,
|
||||||
currentFunction = parent.currentFunction,
|
currentFunction = parent.currentFunction,
|
||||||
|
@ -420,6 +468,23 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build(BreakStatement L, C) = C[InvokeContinuation(...)]
|
||||||
|
//
|
||||||
|
// The continuation and arguments are filled in later after translating
|
||||||
|
// the body containing the break.
|
||||||
|
ir.Primitive visitBreakStatement(ast.BreakStatement node) {
|
||||||
|
assert(isOpen);
|
||||||
|
JumpTarget target = elements.getTargetOf(node);
|
||||||
|
for (JumpCollector collector in breakCollectors) {
|
||||||
|
if (target == collector.target) {
|
||||||
|
collector.addJump(this);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compiler.internalError(node, "'break' target not found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// Build(EmptyStatement, C) = C
|
// Build(EmptyStatement, C) = C
|
||||||
ir.Primitive visitEmptyStatement(ast.EmptyStatement node) {
|
ir.Primitive visitEmptyStatement(ast.EmptyStatement node) {
|
||||||
assert(isOpen);
|
assert(isOpen);
|
||||||
|
@ -437,24 +502,24 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
||||||
|
|
||||||
/// Create a non-recursive join-point continuation.
|
/// Create a non-recursive join-point continuation.
|
||||||
///
|
///
|
||||||
/// Given the environment length at the join point and a list of open
|
/// Given the environment length at the join point and a list of
|
||||||
/// contexts that should reach the join point, create a join-point
|
/// jumps that should reach the join point, create a join-point
|
||||||
/// continuation. The join-point continuation has a parameter for each
|
/// continuation. The join-point continuation has a parameter for each
|
||||||
/// variable that has different values reaching on different paths.
|
/// variable that has different values reaching on different paths.
|
||||||
///
|
///
|
||||||
/// The holes in the contexts are filled with [ir.InvokeContinuation]
|
/// The jumps are uninitialized [ir.InvokeContinuation] expressions.
|
||||||
/// expressions passing the appropriate arguments.
|
/// They are filled in with the target continuation and appropriate
|
||||||
|
/// arguments.
|
||||||
///
|
///
|
||||||
/// As a side effect, the environment of this builder is updated to include
|
/// As a side effect, the environment of this builder is updated to include
|
||||||
/// the join-point continuation parameters.
|
/// the join-point continuation parameters.
|
||||||
ir.Continuation createJoin(int environmentLength,
|
ir.Continuation createJoin(int environmentLength, JumpCollector jumps) {
|
||||||
List<IrBuilder> contexts) {
|
assert(jumps.length >= 2);
|
||||||
assert(contexts.length >= 2);
|
|
||||||
|
|
||||||
// Compute which values are identical on all paths reaching the join.
|
// Compute which values are identical on all paths reaching the join.
|
||||||
// Handle the common case of a pair of contexts efficiently.
|
// Handle the common case of a pair of contexts efficiently.
|
||||||
Environment first = contexts[0].environment;
|
Environment first = jumps.environments[0];
|
||||||
Environment second = contexts[1].environment;
|
Environment second = jumps.environments[1];
|
||||||
assert(environmentLength <= first.length);
|
assert(environmentLength <= first.length);
|
||||||
assert(environmentLength <= second.length);
|
assert(environmentLength <= second.length);
|
||||||
assert(first.sameDomain(environmentLength, second));
|
assert(first.sameDomain(environmentLength, second));
|
||||||
|
@ -479,10 +544,10 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
||||||
for (int i = 0; i < environmentLength; ++i) {
|
for (int i = 0; i < environmentLength; ++i) {
|
||||||
ir.Primitive candidate = common[i];
|
ir.Primitive candidate = common[i];
|
||||||
if (candidate == null) continue;
|
if (candidate == null) continue;
|
||||||
for (IrBuilder current in contexts.skip(2)) {
|
for (Environment current in jumps.environments.skip(2)) {
|
||||||
assert(environmentLength <= current.environment.length);
|
assert(environmentLength <= current.length);
|
||||||
assert(first.sameDomain(environmentLength, current.environment));
|
assert(first.sameDomain(environmentLength, current));
|
||||||
if (candidate != current.environment[i]) {
|
if (candidate != current[i]) {
|
||||||
common[i] = null;
|
common[i] = null;
|
||||||
++parameterCount;
|
++parameterCount;
|
||||||
break;
|
break;
|
||||||
|
@ -492,40 +557,49 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create the join point continuation.
|
||||||
List<ir.Parameter> parameters = <ir.Parameter>[];
|
List<ir.Parameter> parameters = <ir.Parameter>[];
|
||||||
parameters.length = parameterCount;
|
parameters.length = parameterCount;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (int i = 0; i < environmentLength; ++i) {
|
for (int i = 0; i < environmentLength; ++i) {
|
||||||
if (common[i] == null) {
|
if (common[i] == null) {
|
||||||
ir.Parameter parameter = new ir.Parameter(first.index2variable[i]);
|
parameters[index++] = new ir.Parameter(first.index2variable[i]);
|
||||||
parameters[index++] = parameter;
|
|
||||||
if (i < environment.length) {
|
|
||||||
// The variable is bound to the join-point parameter in the
|
|
||||||
// continuation. Variables outside the range of the environment are
|
|
||||||
// 'phantom' variables used for the values of expressions like
|
|
||||||
// &&, ||, and ?:.
|
|
||||||
environment.index2value[i] = parameter;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(index == parameterCount);
|
assert(index == parameterCount);
|
||||||
ir.Continuation join = new ir.Continuation(parameters);
|
ir.Continuation join = new ir.Continuation(parameters);
|
||||||
|
|
||||||
// Plug all the contexts with continuation invocations.
|
// Fill in all the continuation invocations.
|
||||||
for (IrBuilder context in contexts) {
|
for (int i = 0; i < jumps.length; ++i) {
|
||||||
// Passing `this` as one of the contexts will not do the right thing
|
Environment currentEnvironment = jumps.environments[i];
|
||||||
// (this.environment has already been mutated).
|
ir.InvokeContinuation invoke = jumps.invocations[i];
|
||||||
assert(context != this);
|
// Sharing this.environment with one of the invocations will not do
|
||||||
List<ir.Primitive> arguments = <ir.Primitive>[];
|
// the right thing (this.environment has already been mutated).
|
||||||
|
List<ir.Reference> arguments = <ir.Reference>[];
|
||||||
arguments.length = parameterCount;
|
arguments.length = parameterCount;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (int i = 0; i < environmentLength; ++i) {
|
for (int i = 0; i < environmentLength; ++i) {
|
||||||
if (common[i] == null) {
|
if (common[i] == null) {
|
||||||
arguments[index++] = context.environment[i];
|
arguments[index++] = new ir.Reference(currentEnvironment[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
context.add(new ir.InvokeContinuation(join, arguments));
|
invoke.continuation = new ir.Reference(join);
|
||||||
context.current = null;
|
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++];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return join;
|
return join;
|
||||||
|
@ -561,17 +635,23 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For loops use three named continuations: the entry to the condition,
|
// For loops use four named continuations: the entry to the condition,
|
||||||
// the entry to the body, and the loop exit (break). The CPS translation
|
// the entry to the body, the loop exit, and the loop successor (break).
|
||||||
// of [[for (initializer; condition; update) body; successor]] is:
|
// The CPS translation of
|
||||||
|
// [[for (initializer; condition; update) body; successor]] is:
|
||||||
//
|
//
|
||||||
// [[initializer]];
|
// [[initializer]];
|
||||||
// let cont loop(x, ...) =
|
// let cont loop(x, ...) =
|
||||||
// let prim cond = [[condition]] in
|
// let prim cond = [[condition]] in
|
||||||
// let cont exit() = [[successor]] in
|
// let cont break() = [[successor]] in
|
||||||
|
// let cont exit() = break(v, ...) in
|
||||||
// let cont body() = [[body]]; [[update]]; loop(v, ...) in
|
// let cont body() = [[body]]; [[update]]; loop(v, ...) in
|
||||||
// branch cond (body, exit) in
|
// branch cond (body, exit) in
|
||||||
// loop(v, ...)
|
// 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 (node.initializer != null) visit(node.initializer);
|
if (node.initializer != null) visit(node.initializer);
|
||||||
|
|
||||||
|
@ -585,23 +665,37 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
||||||
condition = condBuilder.visit(node.condition);
|
condition = condBuilder.visit(node.condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JumpCollector breakCollector =
|
||||||
|
new JumpCollector(elements.getTargetDefinition(node));
|
||||||
|
breakCollectors.add(breakCollector);
|
||||||
IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder);
|
IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder);
|
||||||
bodyBuilder.visit(node.body);
|
bodyBuilder.visit(node.body);
|
||||||
for (ast.Node n in node.update) {
|
for (ast.Node n in node.update) {
|
||||||
if (!bodyBuilder.isOpen) break;
|
if (!bodyBuilder.isOpen) break;
|
||||||
bodyBuilder.visit(n);
|
bodyBuilder.visit(n);
|
||||||
}
|
}
|
||||||
|
assert(breakCollectors.last == breakCollector);
|
||||||
|
breakCollectors.removeLast();
|
||||||
|
|
||||||
// Create body entry and loop exit continuations and a join-point
|
// Create body entry and loop exit continuations and a branch to them.
|
||||||
// continuation if control flow reaches the end of the body (update).
|
|
||||||
ir.Continuation bodyContinuation = new ir.Continuation([]);
|
ir.Continuation bodyContinuation = new ir.Continuation([]);
|
||||||
ir.Continuation exitContinuation = new ir.Continuation([]);
|
ir.Continuation exitContinuation = new ir.Continuation([]);
|
||||||
condBuilder.add(
|
ir.LetCont branch =
|
||||||
new ir.LetCont(exitContinuation,
|
new ir.LetCont(exitContinuation,
|
||||||
new ir.LetCont(bodyContinuation,
|
new ir.LetCont(bodyContinuation,
|
||||||
new ir.Branch(new ir.IsTrue(condition),
|
new ir.Branch(new ir.IsTrue(condition),
|
||||||
bodyContinuation,
|
bodyContinuation,
|
||||||
exitContinuation))));
|
exitContinuation)));
|
||||||
|
// If there are breaks in the body, then there must be a join-point
|
||||||
|
// continuation for the normal exit and the breaks.
|
||||||
|
ir.LetCont letJoin;
|
||||||
|
if (breakCollector.isEmpty) {
|
||||||
|
condBuilder.add(branch);
|
||||||
|
} else {
|
||||||
|
letJoin = new ir.LetCont(null, branch);
|
||||||
|
condBuilder.add(letJoin);
|
||||||
|
condBuilder.current = branch;
|
||||||
|
}
|
||||||
List<ir.Parameter> parameters = condBuilder.parameters;
|
List<ir.Parameter> parameters = condBuilder.parameters;
|
||||||
ir.Continuation loopContinuation = new ir.Continuation(parameters);
|
ir.Continuation loopContinuation = new ir.Continuation(parameters);
|
||||||
if (bodyBuilder.isOpen) {
|
if (bodyBuilder.isOpen) {
|
||||||
|
@ -613,8 +707,16 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
||||||
add(new ir.LetCont(loopContinuation,
|
add(new ir.LetCont(loopContinuation,
|
||||||
new ir.InvokeContinuation(loopContinuation,
|
new ir.InvokeContinuation(loopContinuation,
|
||||||
environment.index2value)));
|
environment.index2value)));
|
||||||
current = condBuilder.current;
|
if (letJoin == null) {
|
||||||
environment = condBuilder.environment;
|
current = condBuilder.current;
|
||||||
|
environment = condBuilder.environment;
|
||||||
|
} else {
|
||||||
|
current = branch;
|
||||||
|
environment = condBuilder.environment;
|
||||||
|
breakCollector.addJump(this);
|
||||||
|
letJoin.continuation = createJoin(environment.length, breakCollector);
|
||||||
|
current = letJoin;
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,8 +749,10 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
||||||
// There is a join-point continuation. Build the term
|
// There is a join-point continuation. Build the term
|
||||||
// 'let cont join(x, ...) = [] in Result' and plug invocations of the
|
// 'let cont join(x, ...) = [] in Result' and plug invocations of the
|
||||||
// join-point continuation into the then and else continuations.
|
// join-point continuation into the then and else continuations.
|
||||||
joinContinuation =
|
JumpCollector jumps = new JumpCollector(null);
|
||||||
createJoin(environment.length, [thenBuilder, elseBuilder]);
|
jumps.addJump(thenBuilder);
|
||||||
|
jumps.addJump(elseBuilder);
|
||||||
|
joinContinuation = createJoin(environment.length, jumps);
|
||||||
result = new ir.LetCont(joinContinuation, result);
|
result = new ir.LetCont(joinContinuation, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -678,36 +782,62 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ir.Primitive visitLabeledStatement(ast.LabeledStatement node) {
|
||||||
|
ast.Statement body = node.statement;
|
||||||
|
return body is ast.Loop
|
||||||
|
? visit(body)
|
||||||
|
: giveup(node, 'labeled statement');
|
||||||
|
}
|
||||||
|
|
||||||
ir.Primitive visitWhile(ast.While node) {
|
ir.Primitive visitWhile(ast.While node) {
|
||||||
assert(isOpen);
|
assert(isOpen);
|
||||||
// While loops use three named continuations: the entry to the body,
|
// While loops use four named continuations: the entry to the body, the
|
||||||
// the loop exit (break), and the loop back edge (continue).
|
// loop exit, the loop back edge (continue), and the loop exit (break).
|
||||||
// The CPS translation of [[while (condition) body; successor]] is:
|
// The CPS translation of [[while (condition) body; successor]] is:
|
||||||
//
|
//
|
||||||
// let cont loop(x, ...) =
|
// let cont loop(x, ...) =
|
||||||
// let prim cond = [[condition]] in
|
// let prim cond = [[condition]] in
|
||||||
// let cont exit() = [[successor]] in
|
// let cont break() = [[successor]] in
|
||||||
|
// let cont exit() = break(v, ...) in
|
||||||
// let cont body() = [[body]]; continue(v, ...) in
|
// let cont body() = [[body]]; continue(v, ...) in
|
||||||
// branch cond (body, exit) in
|
// branch cond (body, exit) in
|
||||||
// loop(v, ...)
|
// 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).
|
||||||
|
|
||||||
// The condition and body are delimited.
|
// The condition and body are delimited.
|
||||||
IrBuilder condBuilder = new IrBuilder.recursive(this);
|
IrBuilder condBuilder = new IrBuilder.recursive(this);
|
||||||
ir.Primitive condition = condBuilder.visit(node.condition);
|
ir.Primitive condition = condBuilder.visit(node.condition);
|
||||||
|
|
||||||
|
JumpCollector breakCollector =
|
||||||
|
new JumpCollector(elements.getTargetDefinition(node));
|
||||||
|
breakCollectors.add(breakCollector);
|
||||||
IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder);
|
IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder);
|
||||||
bodyBuilder.visit(node.body);
|
bodyBuilder.visit(node.body);
|
||||||
|
assert(breakCollectors.last == breakCollector);
|
||||||
|
breakCollectors.removeLast();
|
||||||
|
|
||||||
// Create body entry and loop exit continuations and a join-point
|
// Create body entry and loop exit continuations and a branch to them.
|
||||||
// continuation if control flow reaches the end of the body.
|
|
||||||
ir.Continuation bodyContinuation = new ir.Continuation([]);
|
ir.Continuation bodyContinuation = new ir.Continuation([]);
|
||||||
ir.Continuation exitContinuation = new ir.Continuation([]);
|
ir.Continuation exitContinuation = new ir.Continuation([]);
|
||||||
condBuilder.add(
|
ir.LetCont branch =
|
||||||
new ir.LetCont(exitContinuation,
|
new ir.LetCont(exitContinuation,
|
||||||
new ir.LetCont(bodyContinuation,
|
new ir.LetCont(bodyContinuation,
|
||||||
new ir.Branch(new ir.IsTrue(condition),
|
new ir.Branch(new ir.IsTrue(condition),
|
||||||
bodyContinuation,
|
bodyContinuation,
|
||||||
exitContinuation))));
|
exitContinuation)));
|
||||||
|
// If there are breaks in the body, then there must be a join-point
|
||||||
|
// continuation for the normal exit and the breaks.
|
||||||
|
ir.LetCont letJoin;
|
||||||
|
if (breakCollector.isEmpty) {
|
||||||
|
condBuilder.add(branch);
|
||||||
|
} else {
|
||||||
|
letJoin = new ir.LetCont(null, branch);
|
||||||
|
condBuilder.add(letJoin);
|
||||||
|
condBuilder.current = branch;
|
||||||
|
}
|
||||||
List<ir.Parameter> parameters = condBuilder.parameters;
|
List<ir.Parameter> parameters = condBuilder.parameters;
|
||||||
ir.Continuation loopContinuation = new ir.Continuation(parameters);
|
ir.Continuation loopContinuation = new ir.Continuation(parameters);
|
||||||
if (bodyBuilder.isOpen) {
|
if (bodyBuilder.isOpen) {
|
||||||
|
@ -719,8 +849,16 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
||||||
add(new ir.LetCont(loopContinuation,
|
add(new ir.LetCont(loopContinuation,
|
||||||
new ir.InvokeContinuation(loopContinuation,
|
new ir.InvokeContinuation(loopContinuation,
|
||||||
environment.index2value)));
|
environment.index2value)));
|
||||||
current = condBuilder.current;
|
if (letJoin == null) {
|
||||||
environment = condBuilder.environment;
|
current = condBuilder.current;
|
||||||
|
environment = condBuilder.environment;
|
||||||
|
} else {
|
||||||
|
current = branch;
|
||||||
|
environment = condBuilder.environment;
|
||||||
|
breakCollector.addJump(this);
|
||||||
|
letJoin.continuation = createJoin(environment.length, breakCollector);
|
||||||
|
current = letJoin;
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -804,8 +942,11 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
||||||
assert(environment.length == elseBuilder.environment.length);
|
assert(environment.length == elseBuilder.environment.length);
|
||||||
thenBuilder.environment.extend(null, thenValue);
|
thenBuilder.environment.extend(null, thenValue);
|
||||||
elseBuilder.environment.extend(null, elseValue);
|
elseBuilder.environment.extend(null, elseValue);
|
||||||
|
JumpCollector jumps = new JumpCollector(null);
|
||||||
|
jumps.addJump(thenBuilder);
|
||||||
|
jumps.addJump(elseBuilder);
|
||||||
ir.Continuation joinContinuation =
|
ir.Continuation joinContinuation =
|
||||||
createJoin(environment.length + 1, [thenBuilder, elseBuilder]);
|
createJoin(environment.length + 1, jumps);
|
||||||
|
|
||||||
// Build the term
|
// Build the term
|
||||||
// let cont join(x, ..., result) = [] in
|
// let cont join(x, ..., result) = [] in
|
||||||
|
@ -1155,8 +1296,12 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
||||||
|
|
||||||
// Wire up two continuations for the left subexpression, two continuations
|
// Wire up two continuations for the left subexpression, two continuations
|
||||||
// for the right subexpression, and a three-way join continuation.
|
// for the right subexpression, and a three-way join continuation.
|
||||||
ir.Continuation joinContinuation = createJoin(environment.length + 1,
|
JumpCollector jumps = new JumpCollector(null);
|
||||||
[emptyBuilder, rightTrueBuilder, rightFalseBuilder]);
|
jumps.addJump(emptyBuilder);
|
||||||
|
jumps.addJump(rightTrueBuilder);
|
||||||
|
jumps.addJump(rightFalseBuilder);
|
||||||
|
ir.Continuation joinContinuation =
|
||||||
|
createJoin(environment.length + 1, jumps);
|
||||||
ir.Continuation leftTrueContinuation = new ir.Continuation([]);
|
ir.Continuation leftTrueContinuation = new ir.Continuation([]);
|
||||||
ir.Continuation leftFalseContinuation = new ir.Continuation([]);
|
ir.Continuation leftFalseContinuation = new ir.Continuation([]);
|
||||||
ir.Continuation rightTrueContinuation = new ir.Continuation([]);
|
ir.Continuation rightTrueContinuation = new ir.Continuation([]);
|
||||||
|
|
|
@ -12,7 +12,6 @@ import '../elements/elements.dart';
|
||||||
import '../universe/universe.dart' show Selector, SelectorKind;
|
import '../universe/universe.dart' show Selector, SelectorKind;
|
||||||
import '../dart_types.dart' show DartType, GenericType;
|
import '../dart_types.dart' show DartType, GenericType;
|
||||||
import 'const_expression.dart';
|
import 'const_expression.dart';
|
||||||
import '../helpers/helpers.dart';
|
|
||||||
|
|
||||||
abstract class Node {
|
abstract class Node {
|
||||||
static int hashCount = 0;
|
static int hashCount = 0;
|
||||||
|
@ -132,13 +131,13 @@ class LetPrim extends Expression implements InteriorNode {
|
||||||
/// During one-pass construction a LetCont with an empty continuation body is
|
/// During one-pass construction a LetCont with an empty continuation body is
|
||||||
/// used to represent the one-level context 'let cont k(v) = [] in E'.
|
/// used to represent the one-level context 'let cont k(v) = [] in E'.
|
||||||
class LetCont extends Expression implements InteriorNode {
|
class LetCont extends Expression implements InteriorNode {
|
||||||
final Continuation continuation;
|
Continuation continuation;
|
||||||
Expression body;
|
Expression body;
|
||||||
|
|
||||||
LetCont(this.continuation, this.body);
|
LetCont(this.continuation, this.body);
|
||||||
|
|
||||||
Expression plug(Expression expr) {
|
Expression plug(Expression expr) {
|
||||||
assert(continuation.body == null);
|
assert(continuation != null && continuation.body == null);
|
||||||
return continuation.body = expr;
|
return continuation.body = expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,8 +386,8 @@ class DeclareFunction extends Expression implements InteriorNode {
|
||||||
|
|
||||||
/// Invoke a continuation in tail position.
|
/// Invoke a continuation in tail position.
|
||||||
class InvokeContinuation extends Expression {
|
class InvokeContinuation extends Expression {
|
||||||
final Reference continuation;
|
Reference continuation;
|
||||||
final List<Reference> arguments;
|
List<Reference> arguments;
|
||||||
|
|
||||||
// An invocation of a continuation is recursive if it occurs in the body of
|
// An invocation of a continuation is recursive if it occurs in the body of
|
||||||
// the continuation itself.
|
// the continuation itself.
|
||||||
|
@ -404,6 +403,16 @@ class InvokeContinuation extends Expression {
|
||||||
if (recursive) cont.isRecursive = true;
|
if (recursive) cont.isRecursive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A continuation invocation whose target and arguments will be filled
|
||||||
|
/// in later.
|
||||||
|
///
|
||||||
|
/// Used as a placeholder for a jump whose target is not yet created
|
||||||
|
/// (e.g., in the translation of break and continue).
|
||||||
|
InvokeContinuation.uninitialized({recursive: false})
|
||||||
|
: continuation = null,
|
||||||
|
arguments = null,
|
||||||
|
isRecursive = recursive;
|
||||||
|
|
||||||
accept(Visitor visitor) => visitor.visitInvokeContinuation(this);
|
accept(Visitor visitor) => visitor.visitInvokeContinuation(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -415,7 +415,7 @@ class ASTEmitter extends tree.Visitor<dynamic, Expression> {
|
||||||
Statement body = new Block(statementBuffer);
|
Statement body = new Block(statementBuffer);
|
||||||
Statement statement = new While(new Literal(new dart2js.TrueConstant()),
|
Statement statement = new While(new Literal(new dart2js.TrueConstant()),
|
||||||
body);
|
body);
|
||||||
if (usedLabels.remove(stmt.label.name)) {
|
if (usedLabels.remove(stmt.label)) {
|
||||||
statement = new LabeledStatement(stmt.label.name, statement);
|
statement = new LabeledStatement(stmt.label.name, statement);
|
||||||
}
|
}
|
||||||
savedBuffer.add(statement);
|
savedBuffer.add(statement);
|
||||||
|
@ -436,7 +436,7 @@ class ASTEmitter extends tree.Visitor<dynamic, Expression> {
|
||||||
Statement body = new Block(statementBuffer);
|
Statement body = new Block(statementBuffer);
|
||||||
Statement statement;
|
Statement statement;
|
||||||
statement = new While(condition, body);
|
statement = new While(condition, body);
|
||||||
if (usedLabels.remove(stmt.label.name)) {
|
if (usedLabels.remove(stmt.label)) {
|
||||||
statement = new LabeledStatement(stmt.label.name, statement);
|
statement = new LabeledStatement(stmt.label.name, statement);
|
||||||
}
|
}
|
||||||
savedBuffer.add(statement);
|
savedBuffer.add(statement);
|
||||||
|
|
Loading…
Reference in a new issue