| 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 e45762e17e6cc81c29a39a56869bd915c10d8273..b9702dcaaf3635c66a6463f66e91a64b0105d9c7 100644
|
| --- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
|
| +++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
|
| @@ -111,6 +111,8 @@ class JumpCollector {
|
| final JumpTarget target;
|
| final List<ir.InvokeContinuation> _invocations = <ir.InvokeContinuation>[];
|
| final List<Environment> _environments = <Environment>[];
|
| + final List<Iterable<LocalVariableElement>> boxedTryVariables =
|
| + <Iterable<LocalVariableElement>>[];
|
|
|
| JumpCollector(this.target);
|
|
|
| @@ -120,6 +122,15 @@ class JumpCollector {
|
| List<Environment> get environments => _environments;
|
|
|
| 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) {
|
| + for (LocalVariableElement variable in boxedOnEntry) {
|
| + assert(builder.isInMutableVariable(variable));
|
| + ir.Primitive value = builder.buildLocalGet(variable);
|
| + builder.environment.update(variable, value);
|
| + }
|
| + }
|
| ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized();
|
| builder.add(invoke);
|
| _invocations.add(invoke);
|
| @@ -128,6 +139,26 @@ class JumpCollector {
|
| // TODO(kmillikin): Can we set builder.environment to null to make it
|
| // 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);
|
| + }
|
| +
|
| + /// 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();
|
| + }
|
| }
|
|
|
| /// Function for building a node in the context of the current builder.
|
| @@ -208,6 +239,30 @@ class IrBuilderDelimitedState {
|
| abstract class IrBuilder {
|
| IrBuilder _makeInstance();
|
|
|
| + /// A map from TryStatements in the AST to their analysis information.
|
| + ///
|
| + /// This includes which variables should be copied into [ir.MutableVariable]s
|
| + /// on entry to the try and copied out on exit.
|
| + Map<ast.TryStatement, TryStatementInfo> get tryStatements;
|
| +
|
| + /// The set of local variables that will spend their lifetime as
|
| + /// [ir.MutableVariable]s due to being captured by a nested function.
|
| + Set<Local> get mutableCapturedVariables;
|
| +
|
| + /// True if [local] should currently be accessed from a [ir.MutableVariable].
|
| + bool isInMutableVariable(Local local);
|
| +
|
| + /// Creates a [ir.MutableVariable] for the given local.
|
| + void makeMutableVariable(Local local);
|
| +
|
| + /// Remove an [ir.MutableVariable] for a local.
|
| + ///
|
| + /// Subsequent access to the local will be direct rather than through the
|
| + /// mutable variable. This is used for variables that do not spend their
|
| + /// entire lifetime as mutable variables (e.g., variables that are boxed
|
| + /// in mutable variables for a try block).
|
| + void removeMutableVariable(Local local);
|
| +
|
| void declareLocalVariable(LocalVariableElement element,
|
| {ir.Primitive initialValue});
|
| ir.Primitive buildLocalGet(LocalElement element);
|
| @@ -816,6 +871,19 @@ abstract class IrBuilder {
|
| }
|
| }
|
|
|
| + 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;
|
| + }
|
| +
|
| /// Invoke a join-point continuation that contains arguments for all local
|
| /// variables.
|
| ///
|
| @@ -824,6 +892,9 @@ abstract class IrBuilder {
|
| 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];
|
| @@ -1518,7 +1589,7 @@ class DartIrBuilderSharedState {
|
| final Map<Local, ir.MutableVariable> local2mutable =
|
| <Local, ir.MutableVariable>{};
|
|
|
| - final DartCapturedVariableInfo capturedVariables;
|
| + final DartCapturedVariables capturedVariables;
|
|
|
| /// Creates a [MutableVariable] for the given local.
|
| void makeMutableVariable(Local local) {
|
| @@ -1550,17 +1621,32 @@ class DartIrBuilder extends IrBuilder {
|
|
|
| DartIrBuilder(ConstantSystem constantSystem,
|
| ExecutableElement currentElement,
|
| - DartCapturedVariableInfo capturedVariables)
|
| + DartCapturedVariables capturedVariables)
|
| : dartState = new DartIrBuilderSharedState(capturedVariables) {
|
| _init(constantSystem, currentElement);
|
| }
|
|
|
| - /// True if [local] should currently be accessed from a [MutableVariable].
|
| + Map<ast.TryStatement, TryStatementInfo> get tryStatements {
|
| + return dartState.capturedVariables.tryStatements;
|
| + }
|
| +
|
| + Set<Local> get mutableCapturedVariables {
|
| + return dartState.capturedVariables.capturedVariables;
|
| + }
|
| +
|
| bool isInMutableVariable(Local local) {
|
| return dartState.local2mutable.containsKey(local) &&
|
| !dartState.registerizedMutableVariables.contains(local);
|
| }
|
|
|
| + void makeMutableVariable(Local local) {
|
| + dartState.makeMutableVariable(local);
|
| + }
|
| +
|
| + void removeMutableVariable(Local local) {
|
| + dartState.local2mutable.remove(local);
|
| + }
|
| +
|
| /// Gets the [MutableVariable] containing the value of [local].
|
| ir.MutableVariable getMutableVariable(Local local) {
|
| return dartState.local2mutable[local];
|
| @@ -1734,6 +1820,12 @@ class JsIrBuilder extends IrBuilder {
|
| _init(constantSystem, currentElement);
|
| }
|
|
|
| + Map<ast.TryStatement, TryStatementInfo> get tryStatements => null;
|
| + Set<Local> get mutableCapturedVariables => null;
|
| + bool isInMutableVariable(Local local) => false;
|
| + void makeMutableVariable(Local local) {}
|
| + void removeMutableVariable(Local local) {}
|
| +
|
| void _enterClosureEnvironment(ClosureEnvironment env) {
|
| if (env == null) return;
|
|
|
| @@ -2012,10 +2104,8 @@ class ClosureEnvironment {
|
| ClosureEnvironment(this.selfReference, this.thisLocal, this.freeVariables);
|
| }
|
|
|
| -/// Information about which variables are captured by a nested function.
|
| -///
|
| -/// This is used by the [DartIrBuilder] instead of [ClosureScope] and
|
| -/// [ClosureEnvironment].
|
| -abstract class DartCapturedVariableInfo {
|
| - Iterable<Local> get capturedVariables;
|
| +class TryStatementInfo {
|
| + final Set<LocalVariableElement> declared = new Set<LocalVariableElement>();
|
| + final Set<LocalVariableElement> boxedOnEntry =
|
| + new Set<LocalVariableElement>();
|
| }
|
|
|