| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library dart2js.ir_builder; | 5 library dart2js.ir_builder; |
| 6 | 6 |
| 7 import '../constants/expressions.dart'; | 7 import '../constants/expressions.dart'; |
| 8 import '../constants/values.dart' show PrimitiveConstantValue; | 8 import '../constants/values.dart' show PrimitiveConstantValue; |
| 9 import '../dart_types.dart'; | 9 import '../dart_types.dart'; |
| 10 import '../dart2jslib.dart'; | 10 import '../dart2jslib.dart'; |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 104 /// continues are collected by a JumpCollector and processed later, on demand. | 104 /// continues are collected by a JumpCollector and processed later, on demand. |
| 105 /// The site of the break or continue is represented by a continuation | 105 /// The site of the break or continue is represented by a continuation |
| 106 /// invocation that will have its target and arguments filled in later. | 106 /// invocation that will have its target and arguments filled in later. |
| 107 /// | 107 /// |
| 108 /// The environment of the builder at that point is captured and should not | 108 /// The environment of the builder at that point is captured and should not |
| 109 /// be subsequently mutated until the jump is resolved. | 109 /// be subsequently mutated until the jump is resolved. |
| 110 class JumpCollector { | 110 class JumpCollector { |
| 111 final JumpTarget target; | 111 final JumpTarget target; |
| 112 final List<ir.InvokeContinuation> _invocations = <ir.InvokeContinuation>[]; | 112 final List<ir.InvokeContinuation> _invocations = <ir.InvokeContinuation>[]; |
| 113 final List<Environment> _environments = <Environment>[]; | 113 final List<Environment> _environments = <Environment>[]; |
| 114 final List<Iterable<LocalVariableElement>> boxedTryVariables = |
| 115 <Iterable<LocalVariableElement>>[]; |
| 114 | 116 |
| 115 JumpCollector(this.target); | 117 JumpCollector(this.target); |
| 116 | 118 |
| 117 bool get isEmpty => _invocations.isEmpty; | 119 bool get isEmpty => _invocations.isEmpty; |
| 118 int get length => _invocations.length; | 120 int get length => _invocations.length; |
| 119 List<ir.InvokeContinuation> get invocations => _invocations; | 121 List<ir.InvokeContinuation> get invocations => _invocations; |
| 120 List<Environment> get environments => _environments; | 122 List<Environment> get environments => _environments; |
| 121 | 123 |
| 122 void addJump(IrBuilder builder) { | 124 void addJump(IrBuilder builder) { |
| 125 // Unbox all variables that were boxed on entry to try blocks between the |
| 126 // jump and the target. |
| 127 for (Iterable<LocalVariableElement> boxedOnEntry in boxedTryVariables) { |
| 128 for (LocalVariableElement variable in boxedOnEntry) { |
| 129 assert(builder.isInMutableVariable(variable)); |
| 130 ir.Primitive value = builder.buildLocalGet(variable); |
| 131 builder.environment.update(variable, value); |
| 132 } |
| 133 } |
| 123 ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized(); | 134 ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized(); |
| 124 builder.add(invoke); | 135 builder.add(invoke); |
| 125 _invocations.add(invoke); | 136 _invocations.add(invoke); |
| 126 _environments.add(builder.environment); | 137 _environments.add(builder.environment); |
| 127 builder._current = null; | 138 builder._current = null; |
| 128 // TODO(kmillikin): Can we set builder.environment to null to make it | 139 // TODO(kmillikin): Can we set builder.environment to null to make it |
| 129 // less likely to mutate it? | 140 // less likely to mutate it? |
| 130 } | 141 } |
| 142 |
| 143 /// Add a set of variables that were boxed on entry to a try block. |
| 144 /// |
| 145 /// Jumps from a try block to targets outside have to unbox the variables |
| 146 /// that were boxed on entry before invoking the target continuation. Call |
| 147 /// this function before translating a try block and call [leaveTry] after |
| 148 /// translating it. |
| 149 void enterTry(Iterable<LocalVariableElement> boxedOnEntry) { |
| 150 // The boxed variables are maintained as a stack to make leaving easy. |
| 151 boxedTryVariables.add(boxedOnEntry); |
| 152 } |
| 153 |
| 154 /// Remove the most recently added set of variables boxed on entry to a try |
| 155 /// block. |
| 156 /// |
| 157 /// Call [enterTry] before translating a try block and call this function |
| 158 /// after translating it. |
| 159 void leaveTry() { |
| 160 boxedTryVariables.removeLast(); |
| 161 } |
| 131 } | 162 } |
| 132 | 163 |
| 133 /// Function for building a node in the context of the current builder. | 164 /// Function for building a node in the context of the current builder. |
| 134 typedef ir.Node BuildFunction(node); | 165 typedef ir.Node BuildFunction(node); |
| 135 | 166 |
| 136 /// Function for building nodes in the context of the provided [builder]. | 167 /// Function for building nodes in the context of the provided [builder]. |
| 137 typedef ir.Node SubbuildFunction(IrBuilder builder); | 168 typedef ir.Node SubbuildFunction(IrBuilder builder); |
| 138 | 169 |
| 139 /// Mixin that provides encapsulated access to nested builders. | 170 /// Mixin that provides encapsulated access to nested builders. |
| 140 abstract class IrBuilderMixin<N> { | 171 abstract class IrBuilderMixin<N> { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 201 IrBuilderDelimitedState(this.constantSystem, this.currentElement); | 232 IrBuilderDelimitedState(this.constantSystem, this.currentElement); |
| 202 } | 233 } |
| 203 | 234 |
| 204 /// A factory for building the cps IR. | 235 /// A factory for building the cps IR. |
| 205 /// | 236 /// |
| 206 /// [DartIrBuilder] and [JsIrBuilder] implement nested functions and captured | 237 /// [DartIrBuilder] and [JsIrBuilder] implement nested functions and captured |
| 207 /// variables in different ways. | 238 /// variables in different ways. |
| 208 abstract class IrBuilder { | 239 abstract class IrBuilder { |
| 209 IrBuilder _makeInstance(); | 240 IrBuilder _makeInstance(); |
| 210 | 241 |
| 242 /// A map from TryStatements in the AST to their analysis information. |
| 243 /// |
| 244 /// This includes which variables should be copied into [ir.MutableVariable]s |
| 245 /// on entry to the try and copied out on exit. |
| 246 Map<ast.TryStatement, TryStatementInfo> get tryStatements; |
| 247 |
| 248 /// The set of local variables that will spend their lifetime as |
| 249 /// [ir.MutableVariable]s due to being captured by a nested function. |
| 250 Set<Local> get mutableCapturedVariables; |
| 251 |
| 252 /// True if [local] should currently be accessed from a [ir.MutableVariable]. |
| 253 bool isInMutableVariable(Local local); |
| 254 |
| 255 /// Creates a [ir.MutableVariable] for the given local. |
| 256 void makeMutableVariable(Local local); |
| 257 |
| 258 /// Remove an [ir.MutableVariable] for a local. |
| 259 /// |
| 260 /// Subsequent access to the local will be direct rather than through the |
| 261 /// mutable variable. This is used for variables that do not spend their |
| 262 /// entire lifetime as mutable variables (e.g., variables that are boxed |
| 263 /// in mutable variables for a try block). |
| 264 void removeMutableVariable(Local local); |
| 265 |
| 211 void declareLocalVariable(LocalVariableElement element, | 266 void declareLocalVariable(LocalVariableElement element, |
| 212 {ir.Primitive initialValue}); | 267 {ir.Primitive initialValue}); |
| 213 ir.Primitive buildLocalGet(LocalElement element); | 268 ir.Primitive buildLocalGet(LocalElement element); |
| 214 ir.Primitive buildLocalSet(LocalElement element, ir.Primitive value); | 269 ir.Primitive buildLocalSet(LocalElement element, ir.Primitive value); |
| 215 | 270 |
| 216 /// Called when entering a nested function with free variables. | 271 /// Called when entering a nested function with free variables. |
| 217 /// | 272 /// |
| 218 /// The free variables must subsequently be accessible using [buildLocalGet] | 273 /// The free variables must subsequently be accessible using [buildLocalGet] |
| 219 /// and [buildLocalSet]. | 274 /// and [buildLocalSet]. |
| 220 void _enterClosureEnvironment(ClosureEnvironment env); | 275 void _enterClosureEnvironment(ClosureEnvironment env); |
| (...skipping 588 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 809 environment = thenBuilder.environment; | 864 environment = thenBuilder.environment; |
| 810 } else if (elseBuilder.isOpen) { | 865 } else if (elseBuilder.isOpen) { |
| 811 if (elseBuilder._root != null) _current = elseBuilder._current; | 866 if (elseBuilder._root != null) _current = elseBuilder._current; |
| 812 environment = elseBuilder.environment; | 867 environment = elseBuilder.environment; |
| 813 } else { | 868 } else { |
| 814 _current = null; | 869 _current = null; |
| 815 } | 870 } |
| 816 } | 871 } |
| 817 } | 872 } |
| 818 | 873 |
| 874 void jumpTo(ir.Continuation continuation) { |
| 875 assert(isOpen); |
| 876 assert(environment.length >= continuation.parameters.length); |
| 877 ir.InvokeContinuation jump = new ir.InvokeContinuation.uninitialized(); |
| 878 jump.continuation = new ir.Reference(continuation); |
| 879 jump.arguments = new List<ir.Reference>.generate( |
| 880 continuation.parameters.length, (i) { |
| 881 return new ir.Reference(environment[i]); |
| 882 }); |
| 883 add(jump); |
| 884 _current = null; |
| 885 } |
| 886 |
| 819 /// Invoke a join-point continuation that contains arguments for all local | 887 /// Invoke a join-point continuation that contains arguments for all local |
| 820 /// variables. | 888 /// variables. |
| 821 /// | 889 /// |
| 822 /// Given the continuation and a list of uninitialized invocations, fill | 890 /// Given the continuation and a list of uninitialized invocations, fill |
| 823 /// in each invocation with the continuation and appropriate arguments. | 891 /// in each invocation with the continuation and appropriate arguments. |
| 824 void invokeFullJoin(ir.Continuation join, | 892 void invokeFullJoin(ir.Continuation join, |
| 825 JumpCollector jumps, | 893 JumpCollector jumps, |
| 826 {recursive: false}) { | 894 {recursive: false}) { |
| 895 // TODO(kmillikin): If the JumpCollector collected open IrBuilders instead |
| 896 // of pairs of invocations and environments, we could use IrBuilder.jumpTo |
| 897 // here --- the code is almost the same. |
| 827 join.isRecursive = recursive; | 898 join.isRecursive = recursive; |
| 828 for (int i = 0; i < jumps.length; ++i) { | 899 for (int i = 0; i < jumps.length; ++i) { |
| 829 Environment currentEnvironment = jumps.environments[i]; | 900 Environment currentEnvironment = jumps.environments[i]; |
| 830 ir.InvokeContinuation invoke = jumps.invocations[i]; | 901 ir.InvokeContinuation invoke = jumps.invocations[i]; |
| 831 invoke.continuation = new ir.Reference(join); | 902 invoke.continuation = new ir.Reference(join); |
| 832 invoke.arguments = new List<ir.Reference>.generate( | 903 invoke.arguments = new List<ir.Reference>.generate( |
| 833 join.parameters.length, | 904 join.parameters.length, |
| 834 (i) => new ir.Reference(currentEnvironment[i])); | 905 (i) => new ir.Reference(currentEnvironment[i])); |
| 835 invoke.isRecursive = recursive; | 906 invoke.isRecursive = recursive; |
| 836 } | 907 } |
| (...skipping 674 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1511 return join; | 1582 return join; |
| 1512 } | 1583 } |
| 1513 } | 1584 } |
| 1514 | 1585 |
| 1515 /// Shared state between DartIrBuilders within the same method. | 1586 /// Shared state between DartIrBuilders within the same method. |
| 1516 class DartIrBuilderSharedState { | 1587 class DartIrBuilderSharedState { |
| 1517 /// Maps local variables to their corresponding [MutableVariable] object. | 1588 /// Maps local variables to their corresponding [MutableVariable] object. |
| 1518 final Map<Local, ir.MutableVariable> local2mutable = | 1589 final Map<Local, ir.MutableVariable> local2mutable = |
| 1519 <Local, ir.MutableVariable>{}; | 1590 <Local, ir.MutableVariable>{}; |
| 1520 | 1591 |
| 1521 final DartCapturedVariableInfo capturedVariables; | 1592 final DartCapturedVariables capturedVariables; |
| 1522 | 1593 |
| 1523 /// Creates a [MutableVariable] for the given local. | 1594 /// Creates a [MutableVariable] for the given local. |
| 1524 void makeMutableVariable(Local local) { | 1595 void makeMutableVariable(Local local) { |
| 1525 ir.MutableVariable variable = | 1596 ir.MutableVariable variable = |
| 1526 new ir.MutableVariable(local.executableContext, local); | 1597 new ir.MutableVariable(local.executableContext, local); |
| 1527 local2mutable[local] = variable; | 1598 local2mutable[local] = variable; |
| 1528 } | 1599 } |
| 1529 | 1600 |
| 1530 /// [MutableVariable]s that should temporarily be treated as registers. | 1601 /// [MutableVariable]s that should temporarily be treated as registers. |
| 1531 final Set<Local> registerizedMutableVariables = new Set<Local>(); | 1602 final Set<Local> registerizedMutableVariables = new Set<Local>(); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1543 /// Captured variables are translated to ref cells (see [MutableVariable]) | 1614 /// Captured variables are translated to ref cells (see [MutableVariable]) |
| 1544 /// using [GetMutableVariable] and [SetMutableVariable]. | 1615 /// using [GetMutableVariable] and [SetMutableVariable]. |
| 1545 class DartIrBuilder extends IrBuilder { | 1616 class DartIrBuilder extends IrBuilder { |
| 1546 final DartIrBuilderSharedState dartState; | 1617 final DartIrBuilderSharedState dartState; |
| 1547 | 1618 |
| 1548 IrBuilder _makeInstance() => new DartIrBuilder._blank(dartState); | 1619 IrBuilder _makeInstance() => new DartIrBuilder._blank(dartState); |
| 1549 DartIrBuilder._blank(this.dartState); | 1620 DartIrBuilder._blank(this.dartState); |
| 1550 | 1621 |
| 1551 DartIrBuilder(ConstantSystem constantSystem, | 1622 DartIrBuilder(ConstantSystem constantSystem, |
| 1552 ExecutableElement currentElement, | 1623 ExecutableElement currentElement, |
| 1553 DartCapturedVariableInfo capturedVariables) | 1624 DartCapturedVariables capturedVariables) |
| 1554 : dartState = new DartIrBuilderSharedState(capturedVariables) { | 1625 : dartState = new DartIrBuilderSharedState(capturedVariables) { |
| 1555 _init(constantSystem, currentElement); | 1626 _init(constantSystem, currentElement); |
| 1556 } | 1627 } |
| 1557 | 1628 |
| 1558 /// True if [local] should currently be accessed from a [MutableVariable]. | 1629 Map<ast.TryStatement, TryStatementInfo> get tryStatements { |
| 1630 return dartState.capturedVariables.tryStatements; |
| 1631 } |
| 1632 |
| 1633 Set<Local> get mutableCapturedVariables { |
| 1634 return dartState.capturedVariables.capturedVariables; |
| 1635 } |
| 1636 |
| 1559 bool isInMutableVariable(Local local) { | 1637 bool isInMutableVariable(Local local) { |
| 1560 return dartState.local2mutable.containsKey(local) && | 1638 return dartState.local2mutable.containsKey(local) && |
| 1561 !dartState.registerizedMutableVariables.contains(local); | 1639 !dartState.registerizedMutableVariables.contains(local); |
| 1562 } | 1640 } |
| 1563 | 1641 |
| 1642 void makeMutableVariable(Local local) { |
| 1643 dartState.makeMutableVariable(local); |
| 1644 } |
| 1645 |
| 1646 void removeMutableVariable(Local local) { |
| 1647 dartState.local2mutable.remove(local); |
| 1648 } |
| 1649 |
| 1564 /// Gets the [MutableVariable] containing the value of [local]. | 1650 /// Gets the [MutableVariable] containing the value of [local]. |
| 1565 ir.MutableVariable getMutableVariable(Local local) { | 1651 ir.MutableVariable getMutableVariable(Local local) { |
| 1566 return dartState.local2mutable[local]; | 1652 return dartState.local2mutable[local]; |
| 1567 } | 1653 } |
| 1568 | 1654 |
| 1569 void _enterScope(ClosureScope scope) { | 1655 void _enterScope(ClosureScope scope) { |
| 1570 assert(scope == null); | 1656 assert(scope == null); |
| 1571 } | 1657 } |
| 1572 | 1658 |
| 1573 void _enterClosureEnvironment(ClosureEnvironment env) { | 1659 void _enterClosureEnvironment(ClosureEnvironment env) { |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1727 final JsIrBuilderSharedState jsState; | 1813 final JsIrBuilderSharedState jsState; |
| 1728 | 1814 |
| 1729 IrBuilder _makeInstance() => new JsIrBuilder._blank(jsState); | 1815 IrBuilder _makeInstance() => new JsIrBuilder._blank(jsState); |
| 1730 JsIrBuilder._blank(this.jsState); | 1816 JsIrBuilder._blank(this.jsState); |
| 1731 | 1817 |
| 1732 JsIrBuilder(ConstantSystem constantSystem, ExecutableElement currentElement) | 1818 JsIrBuilder(ConstantSystem constantSystem, ExecutableElement currentElement) |
| 1733 : jsState = new JsIrBuilderSharedState() { | 1819 : jsState = new JsIrBuilderSharedState() { |
| 1734 _init(constantSystem, currentElement); | 1820 _init(constantSystem, currentElement); |
| 1735 } | 1821 } |
| 1736 | 1822 |
| 1823 Map<ast.TryStatement, TryStatementInfo> get tryStatements => null; |
| 1824 Set<Local> get mutableCapturedVariables => null; |
| 1825 bool isInMutableVariable(Local local) => false; |
| 1826 void makeMutableVariable(Local local) {} |
| 1827 void removeMutableVariable(Local local) {} |
| 1828 |
| 1737 void _enterClosureEnvironment(ClosureEnvironment env) { | 1829 void _enterClosureEnvironment(ClosureEnvironment env) { |
| 1738 if (env == null) return; | 1830 if (env == null) return; |
| 1739 | 1831 |
| 1740 // Obtain a reference to the function object (this). | 1832 // Obtain a reference to the function object (this). |
| 1741 ir.Primitive thisPrim = new ir.This(); | 1833 ir.Primitive thisPrim = new ir.This(); |
| 1742 add(new ir.LetPrim(thisPrim)); | 1834 add(new ir.LetPrim(thisPrim)); |
| 1743 | 1835 |
| 1744 // Obtain access to the free variables. | 1836 // Obtain access to the free variables. |
| 1745 env.freeVariables.forEach((Local local, ClosureLocation location) { | 1837 env.freeVariables.forEach((Local local, ClosureLocation location) { |
| 1746 if (location.isBox) { | 1838 if (location.isBox) { |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2005 /// If non-null, [thisLocal] has an entry in [freeVariables] describing where | 2097 /// If non-null, [thisLocal] has an entry in [freeVariables] describing where |
| 2006 /// to find the captured value of `this`. | 2098 /// to find the captured value of `this`. |
| 2007 final ThisLocal thisLocal; | 2099 final ThisLocal thisLocal; |
| 2008 | 2100 |
| 2009 /// Maps [LocalElement]s, [BoxLocal]s and [ThisLocal] to their location. | 2101 /// Maps [LocalElement]s, [BoxLocal]s and [ThisLocal] to their location. |
| 2010 final Map<Local, ClosureLocation> freeVariables; | 2102 final Map<Local, ClosureLocation> freeVariables; |
| 2011 | 2103 |
| 2012 ClosureEnvironment(this.selfReference, this.thisLocal, this.freeVariables); | 2104 ClosureEnvironment(this.selfReference, this.thisLocal, this.freeVariables); |
| 2013 } | 2105 } |
| 2014 | 2106 |
| 2015 /// Information about which variables are captured by a nested function. | 2107 class TryStatementInfo { |
| 2016 /// | 2108 final Set<LocalVariableElement> declared = new Set<LocalVariableElement>(); |
| 2017 /// This is used by the [DartIrBuilder] instead of [ClosureScope] and | 2109 final Set<LocalVariableElement> boxedOnEntry = |
| 2018 /// [ClosureEnvironment]. | 2110 new Set<LocalVariableElement>(); |
| 2019 abstract class DartCapturedVariableInfo { | |
| 2020 Iterable<Local> get capturedVariables; | |
| 2021 } | 2111 } |
| OLD | NEW |