Chromium Code Reviews| 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 6a2c566ff9469224862ea35b446dfe719ec7f4d2..38c036ee37c8b26e4d843553b546195cde68d743 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 |
| @@ -495,4 +495,230 @@ class IrBuilder { |
| } |
| return false; |
| } |
| + |
|
Johnni Winther
2014/10/17 11:37:40
These are moved/adapted from IrBuilderVisitor.
|
| + /// Create a negation of [condition]. |
| + ir.Primitive buildNegation(ir.Primitive condition) { |
| + // ! e is translated as e ? false : true |
| + |
| + // Add a continuation parameter for the result of the expression. |
| + ir.Parameter resultParameter = new ir.Parameter(null); |
| + |
| + ir.Continuation joinContinuation = new ir.Continuation([resultParameter]); |
| + ir.Continuation thenContinuation = new ir.Continuation([]); |
| + ir.Continuation elseContinuation = new ir.Continuation([]); |
| + |
| + ir.Constant trueConstant = |
| + makePrimConst(state.constantSystem.createBool(true)); |
| + ir.Constant falseConstant = |
| + makePrimConst(state.constantSystem.createBool(false)); |
| + |
| + thenContinuation.body = new ir.LetPrim(falseConstant) |
| + ..plug(new ir.InvokeContinuation(joinContinuation, [falseConstant])); |
| + elseContinuation.body = new ir.LetPrim(trueConstant) |
| + ..plug(new ir.InvokeContinuation(joinContinuation, [trueConstant])); |
| + |
| + add(new ir.LetCont(joinContinuation, |
| + new ir.LetCont(thenContinuation, |
| + new ir.LetCont(elseContinuation, |
| + new ir.Branch(new ir.IsTrue(condition), |
| + thenContinuation, |
| + elseContinuation))))); |
| + return resultParameter; |
| + } |
| + |
| + /// Create a lazy and/or expression. [leftValue] is the value of the left |
| + /// operand and [buildRightValue] is called to process the value of the right |
| + /// operand in the context of its own [IrBuilder]. |
| + ir.Primitive buildLogicalOperator( |
| + ir.Primitive leftValue, |
| + ir.Primitive buildRightValue(IrBuilder builder), |
| + {bool isLazyOr: false}) { |
| + // e0 && e1 is translated as if e0 ? (e1 == true) : false. |
| + // 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 = new IrBuilder.delimited(this); |
| + ir.Primitive rightValue = buildRightValue(rightBuilder); |
| + // A dummy empty target for the branch on the left subexpression branch. |
| + // This enables using the same infrastructure for join-point continuations |
| + // as in visitIf and visitConditional. It will hold a definition of the |
| + // appropriate constant and an invocation of the join-point continuation. |
| + IrBuilder emptyBuilder = new IrBuilder.delimited(this); |
| + // Dummy empty targets for right true and right false. They hold |
| + // definitions of the appropriate constant and an invocation of the |
| + // join-point continuation. |
| + IrBuilder rightTrueBuilder = new IrBuilder.delimited(rightBuilder); |
| + IrBuilder rightFalseBuilder = new IrBuilder.delimited(rightBuilder); |
| + |
| + // If we don't evaluate the right subexpression, the value of the whole |
| + // expression is this constant. |
| + ir.Constant leftBool = emptyBuilder.makePrimConst( |
| + emptyBuilder.state.constantSystem.createBool(isLazyOr)); |
| + // If we do evaluate the right subexpression, the value of the expression |
| + // is a true or false constant. |
| + ir.Constant rightTrue = rightTrueBuilder.makePrimConst( |
| + rightTrueBuilder.state.constantSystem.createBool(true)); |
| + ir.Constant rightFalse = rightFalseBuilder.makePrimConst( |
| + rightFalseBuilder.state.constantSystem.createBool(false)); |
| + emptyBuilder.add(new ir.LetPrim(leftBool)); |
| + rightTrueBuilder.add(new ir.LetPrim(rightTrue)); |
| + rightFalseBuilder.add(new ir.LetPrim(rightFalse)); |
| + |
| + // Treat the result values as named values in the environment, so they |
| + // will be treated as arguments to the join-point continuation. |
| + assert(environment.length == emptyBuilder.environment.length); |
| + assert(environment.length == rightTrueBuilder.environment.length); |
| + assert(environment.length == rightFalseBuilder.environment.length); |
| + 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); |
| + ir.Continuation leftTrueContinuation = new ir.Continuation([]); |
| + ir.Continuation leftFalseContinuation = new ir.Continuation([]); |
| + ir.Continuation rightTrueContinuation = new ir.Continuation([]); |
| + ir.Continuation rightFalseContinuation = new ir.Continuation([]); |
| + rightTrueContinuation.body = rightTrueBuilder._root; |
| + rightFalseContinuation.body = rightFalseBuilder._root; |
| + // The right subexpression has two continuations. |
| + rightBuilder.add( |
| + new ir.LetCont(rightTrueContinuation, |
| + new ir.LetCont(rightFalseContinuation, |
| + new ir.Branch(new ir.IsTrue(rightValue), |
| + rightTrueContinuation, |
| + rightFalseContinuation)))); |
| + // Depending on the operator, the left subexpression's continuations are |
| + // either the right subexpression or an invocation of the join-point |
| + // continuation. |
| + if (isLazyOr) { |
| + leftTrueContinuation.body = emptyBuilder._root; |
| + leftFalseContinuation.body = rightBuilder._root; |
| + } else { |
| + leftTrueContinuation.body = rightBuilder._root; |
| + leftFalseContinuation.body = emptyBuilder._root; |
| + } |
| + |
| + add(new ir.LetCont(joinContinuation, |
| + new ir.LetCont(leftTrueContinuation, |
| + new ir.LetCont(leftFalseContinuation, |
| + new ir.Branch(new ir.IsTrue(leftValue), |
| + leftTrueContinuation, |
| + leftFalseContinuation))))); |
| + // 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++]; |
| + } |
| + } |
| + |
| + return join; |
| + } |
| } |