| 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 9985c94238817fc53740c5e4128d485febf25762..e18f276b65844621dc714f73c54df9b1daf70301 100644
|
| --- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
|
| +++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
|
| @@ -375,7 +375,7 @@ abstract class IrBuilderMixin<N> {
|
| }
|
|
|
| /// Shared state between delimited IrBuilders within the same function.
|
| -class IrBuilderDelimitedState {
|
| +class IrBuilderSharedState {
|
| final ConstantSystem constantSystem;
|
|
|
| /// A stack of collectors for breaks.
|
| @@ -394,7 +394,7 @@ class IrBuilderDelimitedState {
|
|
|
| final List<ir.Definition> functionParameters = <ir.Definition>[];
|
|
|
| - IrBuilderDelimitedState(this.constantSystem, this.currentElement);
|
| + IrBuilderSharedState(this.constantSystem, this.currentElement);
|
|
|
| ir.Parameter get thisParameter => _thisParameter;
|
| void set thisParameter(ir.Parameter value) {
|
| @@ -417,20 +417,6 @@ class ThisParameterLocal implements Local {
|
| abstract class IrBuilder {
|
| IrBuilder _makeInstance();
|
|
|
| - /// 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});
|
|
|
| @@ -481,7 +467,7 @@ abstract class IrBuilder {
|
|
|
| final List<ir.Parameter> _parameters = <ir.Parameter>[];
|
|
|
| - IrBuilderDelimitedState state;
|
| + IrBuilderSharedState state;
|
|
|
| /// A map from variable indexes to their values.
|
| ///
|
| @@ -489,6 +475,36 @@ abstract class IrBuilder {
|
| /// in the map; look up their [BoxLocal] instead.
|
| Environment environment;
|
|
|
| + /// A map from mutable local variables to their [ir.MutableVariable]s.
|
| + ///
|
| + /// Mutable variables are treated as boxed. Writes to them are observable
|
| + /// side effects.
|
| + Map<Local, ir.MutableVariable> mutableVariables;
|
| +
|
| + /// True if [local] should currently be accessed from a [ir.MutableVariable].
|
| + bool isInMutableVariable(Local local) {
|
| + return mutableVariables.containsKey(local);
|
| + }
|
| +
|
| + /// Creates a [ir.MutableVariable] for the given local.
|
| + void makeMutableVariable(Local local) {
|
| + mutableVariables[local] =
|
| + new ir.MutableVariable(local.executableContext, local);
|
| + }
|
| +
|
| + /// Remove an [ir.MutableVariable] for a local.
|
| + ///
|
| + /// Subsequent access to the local will be direct rather than through the
|
| + /// mutable variable.
|
| + void removeMutableVariable(Local local) {
|
| + mutableVariables.remove(local);
|
| + }
|
| +
|
| + /// Gets the [MutableVariable] containing the value of [local].
|
| + ir.MutableVariable getMutableVariable(Local local) {
|
| + return mutableVariables[local];
|
| + }
|
| +
|
| // The IR builder maintains a context, which is an expression with a hole in
|
| // it. The hole represents the focus where new expressions can be added.
|
| // The context is implemented by 'root' which is the root of the expression
|
| @@ -518,8 +534,9 @@ abstract class IrBuilder {
|
|
|
| /// Initialize a new top-level IR builder.
|
| void _init(ConstantSystem constantSystem, ExecutableElement currentElement) {
|
| - state = new IrBuilderDelimitedState(constantSystem, currentElement);
|
| + state = new IrBuilderSharedState(constantSystem, currentElement);
|
| environment = new Environment.empty();
|
| + mutableVariables = <Local, ir.MutableVariable>{};
|
| }
|
|
|
| /// Construct a delimited visitor for visiting a subtree.
|
| @@ -534,25 +551,28 @@ abstract class IrBuilder {
|
| IrBuilder makeDelimitedBuilder([Environment env = null]) {
|
| return _makeInstance()
|
| ..state = state
|
| - ..environment = env != null ? env : new Environment.from(environment);
|
| + ..environment = env != null ? env : new Environment.from(environment)
|
| + ..mutableVariables = mutableVariables;
|
| }
|
|
|
| /// Construct a builder for making constructor field initializers.
|
| IrBuilder makeInitializerBuilder() {
|
| return _makeInstance()
|
| - ..state = new IrBuilderDelimitedState(state.constantSystem,
|
| - state.currentElement)
|
| - ..environment = new Environment.from(environment);
|
| + ..state = new IrBuilderSharedState(state.constantSystem,
|
| + state.currentElement)
|
| + ..environment = new Environment.from(environment)
|
| + ..mutableVariables = mutableVariables;
|
| }
|
|
|
| /// Construct a builder for an inner function.
|
| IrBuilder makeInnerFunctionBuilder(ExecutableElement currentElement) {
|
| - IrBuilderDelimitedState innerState =
|
| - new IrBuilderDelimitedState(state.constantSystem, currentElement)
|
| + IrBuilderSharedState innerState =
|
| + new IrBuilderSharedState(state.constantSystem, currentElement)
|
| ..enclosingMethodThisParameter = state.enclosingMethodThisParameter;
|
| return _makeInstance()
|
| ..state = innerState
|
| - ..environment = new Environment.empty();
|
| + ..environment = new Environment.empty()
|
| + ..mutableVariables = <Local, ir.MutableVariable>{};
|
| }
|
|
|
| bool get isOpen => _root == null || _current != null;
|
| @@ -1714,12 +1734,10 @@ abstract class IrBuilder {
|
| 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. 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).
|
| + // Variables treated as mutable in a try are not mutable outside of it.
|
| + // Work with a copy of the outer builder's mutable variables.
|
| + tryCatchBuilder.mutableVariables =
|
| + new Map<Local, ir.MutableVariable>.from(mutableVariables);
|
| for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) {
|
| assert(!tryCatchBuilder.isInMutableVariable(variable));
|
| ir.Primitive value = tryCatchBuilder.buildLocalVariableGet(variable);
|
| @@ -1750,10 +1768,8 @@ abstract class IrBuilder {
|
| for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) {
|
| assert(catchBuilder.isInMutableVariable(variable));
|
| ir.Primitive value = catchBuilder.buildLocalVariableGet(variable);
|
| - // Note that we remove the variable from the set of mutable variables
|
| - // here (and not above for the try body). This is because the set of
|
| - // mutable variables is global for the whole function and not local to
|
| - // a delimited builder.
|
| + // After this point, the variables that were boxed on entry to the try
|
| + // are no longer treated as mutable.
|
| catchBuilder.removeMutableVariable(variable);
|
| catchBuilder.environment.update(variable, value);
|
| }
|
| @@ -2040,23 +2056,8 @@ abstract class IrBuilder {
|
|
|
| /// Shared state between DartIrBuilders within the same method.
|
| class DartIrBuilderSharedState {
|
| - /// Maps local variables to their corresponding [MutableVariable] object.
|
| - final Map<Local, ir.MutableVariable> local2mutable =
|
| - <Local, ir.MutableVariable>{};
|
| -
|
| - /// Creates a [MutableVariable] for the given local.
|
| - void makeMutableVariable(Local local) {
|
| - ir.MutableVariable variable =
|
| - new ir.MutableVariable(local.executableContext, local);
|
| - local2mutable[local] = variable;
|
| - }
|
| -
|
| /// [MutableVariable]s that should temporarily be treated as registers.
|
| final Set<Local> registerizedMutableVariables = new Set<Local>();
|
| -
|
| - DartIrBuilderSharedState(Set<Local> capturedVariables) {
|
| - capturedVariables.forEach(makeMutableVariable);
|
| - }
|
| }
|
|
|
| /// Dart-specific subclass of [IrBuilder].
|
| @@ -2067,36 +2068,24 @@ class DartIrBuilderSharedState {
|
| /// Captured variables are translated to ref cells (see [MutableVariable])
|
| /// using [GetMutableVariable] and [SetMutableVariable].
|
| class DartIrBuilder extends IrBuilder {
|
| - final DartIrBuilderSharedState dartState;
|
| + final DartIrBuilderSharedState dartState = new DartIrBuilderSharedState();
|
|
|
| IrBuilder _makeInstance() => new DartIrBuilder._blank(dartState);
|
| DartIrBuilder._blank(this.dartState);
|
|
|
| DartIrBuilder(ConstantSystem constantSystem,
|
| ExecutableElement currentElement,
|
| - Set<Local> capturedVariables)
|
| - : dartState = new DartIrBuilderSharedState(capturedVariables) {
|
| + Set<Local> capturedVariables) {
|
| _init(constantSystem, currentElement);
|
| + capturedVariables.forEach(makeMutableVariable);
|
| }
|
|
|
| + @override
|
| bool isInMutableVariable(Local local) {
|
| - return dartState.local2mutable.containsKey(local) &&
|
| + return mutableVariables.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];
|
| - }
|
| -
|
| void _enterScope(ClosureScope scope) {
|
| assert(scope == null);
|
| }
|
| @@ -2291,12 +2280,6 @@ 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 enterInitializers() {
|
| assert(jsState.inInitializers == false);
|
| jsState.inInitializers = true;
|
| @@ -2390,6 +2373,9 @@ class JsIrBuilder extends IrBuilder {
|
| add(new ir.SetField(environment.lookup(location.box),
|
| location.field,
|
| initialValue));
|
| + } else if (isInMutableVariable(variableElement)) {
|
| + add(new ir.LetMutable(getMutableVariable(variableElement),
|
| + initialValue));
|
| } else {
|
| initialValue.useElementAsHint(variableElement);
|
| environment.extend(variableElement, initialValue);
|
|
|