Chromium Code Reviews| 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 '../compile_time_constants.dart' show BackendConstantEnvironment; | 7 import '../compile_time_constants.dart' show BackendConstantEnvironment; |
| 8 import '../constants/constant_system.dart'; | 8 import '../constants/constant_system.dart'; |
| 9 import '../constants/expressions.dart'; | 9 import '../constants/expressions.dart'; |
| 10 import '../constants/values.dart' show ConstantValue, PrimitiveConstantValue; | 10 import '../constants/values.dart' show ConstantValue, PrimitiveConstantValue; |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 124 /// give a handle to the continuation and its environment. | 124 /// give a handle to the continuation and its environment. |
| 125 abstract class JumpCollector { | 125 abstract class JumpCollector { |
| 126 final JumpTarget target; | 126 final JumpTarget target; |
| 127 | 127 |
| 128 ir.Continuation _continuation = null; | 128 ir.Continuation _continuation = null; |
| 129 final Environment _continuationEnvironment; | 129 final Environment _continuationEnvironment; |
| 130 | 130 |
| 131 final List<Iterable<LocalVariableElement>> _boxedTryVariables = | 131 final List<Iterable<LocalVariableElement>> _boxedTryVariables = |
| 132 <Iterable<LocalVariableElement>>[]; | 132 <Iterable<LocalVariableElement>>[]; |
| 133 | 133 |
| 134 /// A stack of all the enclosing finally blocks up to the target of the jump. | |
| 135 /// | |
| 136 /// There are null entries which correspond to try/catch (no finally). | |
| 137 final List<SubbuildFunction> _finallyBlocks = <SubbuildFunction>[]; | |
| 138 | |
| 134 JumpCollector(this._continuationEnvironment, this.target); | 139 JumpCollector(this._continuationEnvironment, this.target); |
| 135 | 140 |
| 136 /// True if the collector has not recorded any jumps to its continuation. | 141 /// True if the collector has not recorded any jumps to its continuation. |
| 137 bool get isEmpty; | 142 bool get isEmpty; |
| 138 | 143 |
| 139 /// The continuation encapsulated by this collector. | 144 /// The continuation encapsulated by this collector. |
| 140 ir.Continuation get continuation; | 145 ir.Continuation get continuation; |
| 141 | 146 |
| 142 /// The compile-time environment to be used for translating code in the body | 147 /// The compile-time environment to be used for translating code in the body |
| 143 /// of the continuation. | 148 /// of the continuation. |
| 144 Environment get environment; | 149 Environment get environment; |
| 145 | 150 |
| 146 /// Emit a jump to the continuation for a given [IrBuilder]. | 151 /// Emit a jump to the continuation for a given [IrBuilder]. |
| 147 void addJump(IrBuilder builder); | 152 void addJump(IrBuilder builder); |
| 148 | 153 |
| 149 /// Add a set of variables that were boxed on entry to a try block. | 154 /// Add a set of variables that were boxed on entry to a try block. |
| 150 /// | 155 /// |
| 151 /// All jumps from a try block to targets outside have to unbox the | 156 /// All jumps from a try block to targets outside have to unbox the |
| 152 /// variables that were boxed on entry before invoking the target | 157 /// variables that were boxed on entry before invoking the target |
| 153 /// continuation. Call this function before translating a try block and | 158 /// continuation. Call this function before translating a try block and |
| 154 /// call [leaveTry] after translating it. | 159 /// call [leaveTry] after translating it. |
| 155 void enterTry(Iterable<LocalVariableElement> boxedOnEntry) { | 160 void enterTry(Iterable<LocalVariableElement> boxedOnEntry, |
| 161 [SubbuildFunction buildFinallyBlock]) { | |
| 156 // The boxed variables are maintained as a stack to make leaving easy. | 162 // The boxed variables are maintained as a stack to make leaving easy. |
| 157 _boxedTryVariables.add(boxedOnEntry); | 163 _boxedTryVariables.add(boxedOnEntry); |
| 164 _finallyBlocks.add(buildFinallyBlock); | |
| 158 } | 165 } |
| 159 | 166 |
| 160 /// Remove the most recently added set of variables boxed on entry to a try | 167 /// Remove the most recently added set of variables boxed on entry to a try |
| 161 /// block. | 168 /// block. |
| 162 /// | 169 /// |
| 163 /// Call [enterTry] before translating a try block and call this function | 170 /// Call [enterTry] before translating a try block and call this function |
| 164 /// after translating it. | 171 /// after translating it. |
| 165 void leaveTry() { | 172 void leaveTry() { |
| 166 _boxedTryVariables.removeLast(); | 173 _boxedTryVariables.removeLast(); |
| 174 _finallyBlocks.removeLast(); | |
| 167 } | 175 } |
| 168 | 176 |
| 169 void _buildTryExit(IrBuilder builder) { | 177 void _buildTryExit(IrBuilder builder) { |
| 170 for (Iterable<LocalVariableElement> boxedOnEntry in _boxedTryVariables) { | 178 for (Iterable<LocalVariableElement> boxedOnEntry in _boxedTryVariables) { |
| 171 for (LocalVariableElement variable in boxedOnEntry) { | 179 for (LocalVariableElement variable in boxedOnEntry) { |
| 172 assert(builder.isInMutableVariable(variable)); | 180 assert(builder.isInMutableVariable(variable)); |
| 173 ir.Primitive value = builder.buildLocalVariableGet(variable); | 181 ir.Primitive value = builder.buildLocalVariableGet(variable); |
| 174 builder.environment.update(variable, value); | 182 builder.environment.update(variable, value); |
| 175 } | 183 } |
| 176 } | 184 } |
| 185 for (SubbuildFunction buildFinallyBlock in _finallyBlocks.reversed) { | |
| 186 if (buildFinallyBlock != null) buildFinallyBlock(builder); | |
| 187 if (!builder.isOpen) return; | |
|
asgerf
2015/06/23 08:43:40
The inlined finally block seems to be evaluated in
Kevin Millikin (Google)
2015/06/23 09:26:59
That's pretty serious, thanks for spotting it.
| |
| 188 } | |
| 177 } | 189 } |
| 178 } | 190 } |
| 179 | 191 |
| 180 /// A class to collect 'forward' jumps. | 192 /// A class to collect 'forward' jumps. |
| 181 /// | 193 /// |
| 182 /// A forward jump to a continuation in the sense of the CPS translation is | 194 /// A forward jump to a continuation in the sense of the CPS translation is |
| 183 /// a jump where the jump is emitted before any code in the body of the | 195 /// a jump where the jump is emitted before any code in the body of the |
| 184 /// continuation is translated. They have the property that continuation | 196 /// continuation is translated. They have the property that continuation |
| 185 /// parameters and the environment for the translation of the body can be | 197 /// parameters and the environment for the translation of the body can be |
| 186 /// determined based on the invocations, before translating the body. A | 198 /// determined based on the invocations, before translating the body. A |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 217 } | 229 } |
| 218 | 230 |
| 219 Environment get environment { | 231 Environment get environment { |
| 220 if (_continuation == null) _setContinuation(); | 232 if (_continuation == null) _setContinuation(); |
| 221 return _continuationEnvironment; | 233 return _continuationEnvironment; |
| 222 } | 234 } |
| 223 | 235 |
| 224 void addJump(IrBuilder builder) { | 236 void addJump(IrBuilder builder) { |
| 225 assert(_continuation == null); | 237 assert(_continuation == null); |
| 226 _buildTryExit(builder); | 238 _buildTryExit(builder); |
| 239 if (!builder.isOpen) return; | |
| 240 | |
| 227 ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized(); | 241 ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized(); |
| 228 builder.add(invoke); | 242 builder.add(invoke); |
| 229 _invocations.add(invoke); | 243 _invocations.add(invoke); |
| 230 _invocationEnvironments.add(builder.environment); | 244 _invocationEnvironments.add(builder.environment); |
| 231 builder._current = null; | 245 builder._current = null; |
| 232 // TODO(kmillikin): Can we set builder.environment to null to make it | 246 // TODO(kmillikin): Can we set builder.environment to null to make it |
| 233 // less likely to mutate it? | 247 // less likely to mutate it? |
| 234 } | 248 } |
| 235 | 249 |
| 236 void _setContinuation() { | 250 void _setContinuation() { |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 315 _continuation = new ir.Continuation(parameters, isRecursive: true); | 329 _continuation = new ir.Continuation(parameters, isRecursive: true); |
| 316 } | 330 } |
| 317 | 331 |
| 318 bool isEmpty = true; | 332 bool isEmpty = true; |
| 319 | 333 |
| 320 ir.Continuation get continuation => _continuation; | 334 ir.Continuation get continuation => _continuation; |
| 321 Environment get environment => _continuationEnvironment; | 335 Environment get environment => _continuationEnvironment; |
| 322 | 336 |
| 323 void addJump(IrBuilder builder) { | 337 void addJump(IrBuilder builder) { |
| 324 assert(_continuation.parameters.length <= builder.environment.length); | 338 assert(_continuation.parameters.length <= builder.environment.length); |
| 339 _buildTryExit(builder); | |
| 340 if (!builder.isOpen) return; | |
| 341 | |
| 325 isEmpty = false; | 342 isEmpty = false; |
| 326 _buildTryExit(builder); | |
| 327 builder.add(new ir.InvokeContinuation(_continuation, | 343 builder.add(new ir.InvokeContinuation(_continuation, |
| 328 builder.environment.index2value.take(_continuation.parameters.length) | 344 builder.environment.index2value.take(_continuation.parameters.length) |
| 329 .toList(), | 345 .toList(), |
| 330 isRecursive: true)); | 346 isRecursive: true)); |
| 331 builder._current = null; | 347 builder._current = null; |
| 332 } | 348 } |
| 333 } | 349 } |
| 334 | 350 |
| 335 /// Function for building a node in the context of the current builder. | 351 /// Function for building a node in the context of the current builder. |
| 336 typedef ir.Node BuildFunction(node); | 352 typedef ir.Node BuildFunction(node); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 392 final BackendConstantEnvironment constants; | 408 final BackendConstantEnvironment constants; |
| 393 | 409 |
| 394 ConstantSystem get constantSystem => constants.constantSystem; | 410 ConstantSystem get constantSystem => constants.constantSystem; |
| 395 | 411 |
| 396 /// A stack of collectors for breaks. | 412 /// A stack of collectors for breaks. |
| 397 final List<JumpCollector> breakCollectors = <JumpCollector>[]; | 413 final List<JumpCollector> breakCollectors = <JumpCollector>[]; |
| 398 | 414 |
| 399 /// A stack of collectors for continues. | 415 /// A stack of collectors for continues. |
| 400 final List<JumpCollector> continueCollectors = <JumpCollector>[]; | 416 final List<JumpCollector> continueCollectors = <JumpCollector>[]; |
| 401 | 417 |
| 418 /// A stack of enclosing finally blocks, used when translating return. | |
| 419 final List<SubbuildFunction> finallyBlocks = <SubbuildFunction>[]; | |
| 420 | |
| 402 final List<ConstDeclaration> localConstants = <ConstDeclaration>[]; | 421 final List<ConstDeclaration> localConstants = <ConstDeclaration>[]; |
| 403 | 422 |
| 404 final ExecutableElement currentElement; | 423 final ExecutableElement currentElement; |
| 405 | 424 |
| 406 final ir.Continuation returnContinuation = new ir.Continuation.retrn(); | 425 final ir.Continuation returnContinuation = new ir.Continuation.retrn(); |
| 407 ir.Parameter _thisParameter; | 426 ir.Parameter _thisParameter; |
| 408 ir.Parameter enclosingMethodThisParameter; | 427 ir.Parameter enclosingMethodThisParameter; |
| 409 | 428 |
| 410 final List<ir.Parameter> functionParameters = <ir.Parameter>[]; | 429 final List<ir.Parameter> functionParameters = <ir.Parameter>[]; |
| 411 | 430 |
| (...skipping 1312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1724 /// | 1743 /// |
| 1725 /// [tryInfo] provides information on local variables declared and boxed | 1744 /// [tryInfo] provides information on local variables declared and boxed |
| 1726 /// within this try statement. | 1745 /// within this try statement. |
| 1727 /// [buildTryBlock] builds the try block. | 1746 /// [buildTryBlock] builds the try block. |
| 1728 /// [catchClauseInfos] provides access to the catch type, exception variable, | 1747 /// [catchClauseInfos] provides access to the catch type, exception variable, |
| 1729 /// and stack trace variable, and a function for building the catch block. | 1748 /// and stack trace variable, and a function for building the catch block. |
| 1730 void buildTry( | 1749 void buildTry( |
| 1731 {TryStatementInfo tryStatementInfo, | 1750 {TryStatementInfo tryStatementInfo, |
| 1732 SubbuildFunction buildTryBlock, | 1751 SubbuildFunction buildTryBlock, |
| 1733 List<CatchClauseInfo> catchClauseInfos: const <CatchClauseInfo>[], | 1752 List<CatchClauseInfo> catchClauseInfos: const <CatchClauseInfo>[], |
| 1753 SubbuildFunction buildFinallyBlock, | |
| 1734 ClosureClassMap closureClassMap}) { | 1754 ClosureClassMap closureClassMap}) { |
| 1735 assert(isOpen); | 1755 assert(isOpen); |
| 1736 | 1756 |
| 1737 // Catch handlers are in scope for their body. The CPS translation of | 1757 // Catch handlers are in scope for their body. The CPS translation of |
| 1738 // [[try tryBlock catch (e) catchBlock; successor]] is: | 1758 // [[try tryBlock catch (e) catchBlock; successor]] is: |
| 1739 // | 1759 // |
| 1740 // let cont join(v0, v1, ...) = [[successor]] in | 1760 // let cont join(v0, v1, ...) = [[successor]] in |
| 1741 // let mutable m0 = x0 in | 1761 // let mutable m0 = x0 in |
| 1742 // let mutable m1 = x1 in | 1762 // let mutable m1 = x1 in |
| 1743 // ... | 1763 // ... |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1756 // | 1776 // |
| 1757 // In other words, both the try and catch block are in the scope of the | 1777 // In other words, both the try and catch block are in the scope of the |
| 1758 // join-point continuation, and they are both in the scope of a sequence | 1778 // join-point continuation, and they are both in the scope of a sequence |
| 1759 // of mutable bindings for the variables assigned in the try. The join- | 1779 // of mutable bindings for the variables assigned in the try. The join- |
| 1760 // point continuation is not in the scope of these mutable bindings. | 1780 // point continuation is not in the scope of these mutable bindings. |
| 1761 // The tryBlock is in the scope of a binding for the catch handler. Each | 1781 // The tryBlock is in the scope of a binding for the catch handler. Each |
| 1762 // instruction (specifically, each call) in the tryBlock is in the dynamic | 1782 // instruction (specifically, each call) in the tryBlock is in the dynamic |
| 1763 // scope of the handler. The mutable bindings are dereferenced at the end | 1783 // scope of the handler. The mutable bindings are dereferenced at the end |
| 1764 // of the try block and at the beginning of the catch block, so the | 1784 // of the try block and at the beginning of the catch block, so the |
| 1765 // variables are unboxed in the catch block and at the join point. | 1785 // variables are unboxed in the catch block and at the join point. |
| 1766 JumpCollector join = new ForwardJumpCollector(environment); | 1786 if (catchClauseInfos.isNotEmpty) { |
| 1767 IrBuilder tryCatchBuilder = makeDelimitedBuilder(); | 1787 JumpCollector join = new ForwardJumpCollector(environment); |
| 1788 IrBuilder tryCatchBuilder = makeDelimitedBuilder(); | |
| 1768 | 1789 |
| 1769 // Variables treated as mutable in a try are not mutable outside of it. | 1790 // Variables treated as mutable in a try are not mutable outside of it. |
| 1770 // Work with a copy of the outer builder's mutable variables. | 1791 // Work with a copy of the outer builder's mutable variables. |
| 1771 tryCatchBuilder.mutableVariables = | 1792 tryCatchBuilder.mutableVariables = |
| 1772 new Map<Local, ir.MutableVariable>.from(mutableVariables); | 1793 new Map<Local, ir.MutableVariable>.from(mutableVariables); |
| 1773 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { | 1794 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { |
| 1774 assert(!tryCatchBuilder.isInMutableVariable(variable)); | 1795 assert(!tryCatchBuilder.isInMutableVariable(variable)); |
| 1775 ir.Primitive value = tryCatchBuilder.buildLocalVariableGet(variable); | 1796 ir.Primitive value = tryCatchBuilder.buildLocalVariableGet(variable); |
| 1776 tryCatchBuilder.makeMutableVariable(variable); | 1797 tryCatchBuilder.makeMutableVariable(variable); |
| 1777 tryCatchBuilder.declareLocalVariable(variable, initialValue: value); | 1798 tryCatchBuilder.declareLocalVariable(variable, initialValue: value); |
| 1799 } | |
| 1800 | |
| 1801 IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder(); | |
| 1802 | |
| 1803 void interceptJump(JumpCollector collector) { | |
| 1804 collector.enterTry(tryStatementInfo.boxedOnEntry); | |
| 1805 } | |
| 1806 void restoreJump(JumpCollector collector) { | |
| 1807 collector.leaveTry(); | |
| 1808 } | |
| 1809 tryBuilder.state.breakCollectors.forEach(interceptJump); | |
| 1810 tryBuilder.state.continueCollectors.forEach(interceptJump); | |
| 1811 buildTryBlock(tryBuilder); | |
| 1812 if (tryBuilder.isOpen) { | |
| 1813 interceptJump(join); | |
| 1814 tryBuilder.jumpTo(join); | |
| 1815 restoreJump(join); | |
| 1816 } | |
| 1817 tryBuilder.state.breakCollectors.forEach(restoreJump); | |
| 1818 tryBuilder.state.continueCollectors.forEach(restoreJump); | |
| 1819 | |
| 1820 IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder(); | |
| 1821 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { | |
| 1822 assert(catchBuilder.isInMutableVariable(variable)); | |
| 1823 ir.Primitive value = catchBuilder.buildLocalVariableGet(variable); | |
| 1824 // After this point, the variables that were boxed on entry to the try | |
| 1825 // are no longer treated as mutable. | |
| 1826 catchBuilder.removeMutableVariable(variable); | |
| 1827 catchBuilder.environment.update(variable, value); | |
| 1828 } | |
| 1829 | |
| 1830 // Handlers are always translated as having both exception and stack trace | |
| 1831 // parameters. Multiple clauses do not have to use the same names for | |
| 1832 // them. Choose the first of each as the name hint for the respective | |
| 1833 // handler parameter. | |
| 1834 ir.Parameter exceptionParameter = | |
| 1835 new ir.Parameter(catchClauseInfos.first.exceptionVariable); | |
| 1836 LocalVariableElement traceVariable; | |
| 1837 CatchClauseInfo catchAll; | |
| 1838 for (int i = 0; i < catchClauseInfos.length; ++i) { | |
| 1839 CatchClauseInfo info = catchClauseInfos[i]; | |
| 1840 if (info.type == null) { | |
| 1841 catchAll = info; | |
| 1842 catchClauseInfos.length = i; | |
| 1843 break; | |
| 1844 } | |
| 1845 if (traceVariable == null) { | |
| 1846 traceVariable = info.stackTraceVariable; | |
| 1847 } | |
| 1848 } | |
| 1849 ir.Parameter traceParameter = new ir.Parameter(traceVariable); | |
| 1850 // Expand multiple catch clauses into an explicit if/then/else. Iterate | |
| 1851 // them in reverse so the current block becomes the next else block. | |
| 1852 ir.Expression catchBody; | |
| 1853 if (catchAll == null) { | |
| 1854 catchBody = new ir.Rethrow(); | |
| 1855 } else { | |
| 1856 IrBuilder clauseBuilder = catchBuilder.makeDelimitedBuilder(); | |
| 1857 clauseBuilder.declareLocalVariable(catchAll.exceptionVariable, | |
| 1858 initialValue: exceptionParameter); | |
| 1859 if (catchAll.stackTraceVariable != null) { | |
| 1860 clauseBuilder.declareLocalVariable(catchAll.stackTraceVariable, | |
| 1861 initialValue: traceParameter); | |
| 1862 } | |
| 1863 catchAll.buildCatchBlock(clauseBuilder); | |
| 1864 if (clauseBuilder.isOpen) clauseBuilder.jumpTo(join); | |
| 1865 catchBody = clauseBuilder._root; | |
| 1866 } | |
| 1867 for (CatchClauseInfo clause in catchClauseInfos.reversed) { | |
| 1868 IrBuilder clauseBuilder = catchBuilder.makeDelimitedBuilder(); | |
| 1869 clauseBuilder.declareLocalVariable(clause.exceptionVariable, | |
| 1870 initialValue: exceptionParameter); | |
| 1871 if (clause.stackTraceVariable != null) { | |
| 1872 clauseBuilder.declareLocalVariable(clause.stackTraceVariable, | |
| 1873 initialValue: traceParameter); | |
| 1874 } | |
| 1875 clause.buildCatchBlock(clauseBuilder); | |
| 1876 if (clauseBuilder.isOpen) clauseBuilder.jumpTo(join); | |
| 1877 ir.Continuation thenContinuation = new ir.Continuation([]); | |
| 1878 thenContinuation.body = clauseBuilder._root; | |
| 1879 ir.Continuation elseContinuation = new ir.Continuation([]); | |
| 1880 elseContinuation.body = catchBody; | |
| 1881 | |
| 1882 // Build the type test guarding this clause. We can share the | |
| 1883 // environment with the nested builder because this part cannot mutate | |
| 1884 // it. | |
| 1885 IrBuilder checkBuilder = catchBuilder.makeDelimitedBuilder(environment); | |
| 1886 ir.Primitive typeMatches = | |
| 1887 checkBuilder.buildTypeOperator(exceptionParameter, | |
| 1888 clause.type, | |
| 1889 isTypeTest: true); | |
| 1890 checkBuilder.add(new ir.LetCont.many([thenContinuation, | |
| 1891 elseContinuation], | |
| 1892 new ir.Branch(new ir.IsTrue(typeMatches), | |
| 1893 thenContinuation, | |
| 1894 elseContinuation))); | |
| 1895 catchBody = checkBuilder._root; | |
| 1896 } | |
| 1897 | |
| 1898 List<ir.Parameter> catchParameters = | |
| 1899 <ir.Parameter>[exceptionParameter, traceParameter]; | |
| 1900 ir.Continuation catchContinuation = new ir.Continuation(catchParameters); | |
| 1901 catchBuilder.add(catchBody); | |
| 1902 catchContinuation.body = catchBuilder._root; | |
| 1903 | |
| 1904 tryCatchBuilder.add( | |
| 1905 new ir.LetHandler(catchContinuation, tryBuilder._root)); | |
| 1906 add(new ir.LetCont(join.continuation, tryCatchBuilder._root)); | |
| 1907 environment = join.environment; | |
| 1908 } else { | |
| 1909 // Try/finally. | |
| 1910 JumpCollector join = new ForwardJumpCollector(environment); | |
| 1911 IrBuilder tryFinallyBuilder = makeDelimitedBuilder(); | |
| 1912 | |
| 1913 tryFinallyBuilder.mutableVariables = | |
| 1914 new Map<Local, ir.MutableVariable>.from(mutableVariables); | |
| 1915 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { | |
| 1916 assert(!tryFinallyBuilder.isInMutableVariable(variable)); | |
| 1917 ir.Primitive value = tryFinallyBuilder.buildLocalVariableGet(variable); | |
| 1918 tryFinallyBuilder.makeMutableVariable(variable); | |
| 1919 tryFinallyBuilder.declareLocalVariable(variable, initialValue: value); | |
| 1920 } | |
| 1921 | |
| 1922 IrBuilder tryBuilder = tryFinallyBuilder.makeDelimitedBuilder(); | |
| 1923 | |
| 1924 void interceptJump(JumpCollector collector) { | |
| 1925 collector.enterTry(tryStatementInfo.boxedOnEntry, buildFinallyBlock); | |
| 1926 } | |
| 1927 void restoreJump(JumpCollector collector) { | |
| 1928 collector.leaveTry(); | |
| 1929 } | |
| 1930 tryBuilder.state.breakCollectors.forEach(interceptJump); | |
| 1931 tryBuilder.state.continueCollectors.forEach(interceptJump); | |
| 1932 tryBuilder.state.finallyBlocks.add(buildFinallyBlock); | |
| 1933 buildTryBlock(tryBuilder); | |
| 1934 if (tryBuilder.isOpen) { | |
| 1935 // To cover control falling off the end of the try block, the finally | |
| 1936 // code is translated at the join point. This ensures that it is | |
| 1937 // correctly outside the scope of the catch handler. | |
| 1938 join.enterTry(tryStatementInfo.boxedOnEntry); | |
| 1939 tryBuilder.jumpTo(join); | |
| 1940 join.leaveTry(); | |
| 1941 } | |
| 1942 tryBuilder.state.breakCollectors.forEach(restoreJump); | |
| 1943 tryBuilder.state.continueCollectors.forEach(restoreJump); | |
| 1944 tryBuilder.state.finallyBlocks.removeLast(); | |
| 1945 | |
| 1946 IrBuilder catchBuilder = tryFinallyBuilder.makeDelimitedBuilder(); | |
| 1947 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { | |
| 1948 assert(catchBuilder.isInMutableVariable(variable)); | |
| 1949 ir.Primitive value = catchBuilder.buildLocalVariableGet(variable); | |
| 1950 catchBuilder.removeMutableVariable(variable); | |
| 1951 catchBuilder.environment.update(variable, value); | |
| 1952 } | |
| 1953 | |
| 1954 buildFinallyBlock(catchBuilder); | |
| 1955 if (catchBuilder.isOpen) { | |
| 1956 catchBuilder.add(new ir.Rethrow()); | |
| 1957 catchBuilder._current = null; | |
| 1958 } | |
| 1959 List<ir.Parameter> catchParameters = | |
| 1960 <ir.Parameter>[new ir.Parameter(null), new ir.Parameter(null)]; | |
| 1961 ir.Continuation catchContinuation = new ir.Continuation(catchParameters); | |
| 1962 catchContinuation.body = catchBuilder._root; | |
| 1963 tryFinallyBuilder.add( | |
| 1964 new ir.LetHandler(catchContinuation, tryBuilder._root)); | |
| 1965 add(new ir.LetCont(join.continuation, tryFinallyBuilder._root)); | |
| 1966 environment = join.environment; | |
| 1967 buildFinallyBlock(this); | |
| 1778 } | 1968 } |
| 1779 | |
| 1780 IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder(); | |
| 1781 | |
| 1782 void interceptJumps(JumpCollector collector) { | |
| 1783 collector.enterTry(tryStatementInfo.boxedOnEntry); | |
| 1784 } | |
| 1785 void restoreJumps(JumpCollector collector) { | |
| 1786 collector.leaveTry(); | |
| 1787 } | |
| 1788 tryBuilder.state.breakCollectors.forEach(interceptJumps); | |
| 1789 tryBuilder.state.continueCollectors.forEach(interceptJumps); | |
| 1790 buildTryBlock(tryBuilder); | |
| 1791 if (tryBuilder.isOpen) { | |
| 1792 interceptJumps(join); | |
| 1793 tryBuilder.jumpTo(join); | |
| 1794 restoreJumps(join); | |
| 1795 } | |
| 1796 tryBuilder.state.breakCollectors.forEach(restoreJumps); | |
| 1797 tryBuilder.state.continueCollectors.forEach(restoreJumps); | |
| 1798 | |
| 1799 IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder(); | |
| 1800 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { | |
| 1801 assert(catchBuilder.isInMutableVariable(variable)); | |
| 1802 ir.Primitive value = catchBuilder.buildLocalVariableGet(variable); | |
| 1803 // After this point, the variables that were boxed on entry to the try | |
| 1804 // are no longer treated as mutable. | |
| 1805 catchBuilder.removeMutableVariable(variable); | |
| 1806 catchBuilder.environment.update(variable, value); | |
| 1807 } | |
| 1808 | |
| 1809 // Handlers are always translated as having both exception and stack trace | |
| 1810 // parameters. Multiple clauses do not have to use the same names for | |
| 1811 // them. Choose the first of each as the name hint for the respective | |
| 1812 // handler parameter. | |
| 1813 ir.Parameter exceptionParameter = | |
| 1814 new ir.Parameter(catchClauseInfos.first.exceptionVariable); | |
| 1815 LocalVariableElement traceVariable; | |
| 1816 CatchClauseInfo catchAll; | |
| 1817 for (int i = 0; i < catchClauseInfos.length; ++i) { | |
| 1818 CatchClauseInfo info = catchClauseInfos[i]; | |
| 1819 if (info.type == null) { | |
| 1820 catchAll = info; | |
| 1821 catchClauseInfos.length = i; | |
| 1822 break; | |
| 1823 } | |
| 1824 if (traceVariable == null) { | |
| 1825 traceVariable = info.stackTraceVariable; | |
| 1826 } | |
| 1827 } | |
| 1828 ir.Parameter traceParameter = new ir.Parameter(traceVariable); | |
| 1829 // Expand multiple catch clauses into an explicit if/then/else. Iterate | |
| 1830 // them in reverse so the current block becomes the next else block. | |
| 1831 ir.Expression catchBody; | |
| 1832 if (catchAll == null) { | |
| 1833 catchBody = new ir.Rethrow(); | |
| 1834 } else { | |
| 1835 IrBuilder clauseBuilder = catchBuilder.makeDelimitedBuilder(); | |
| 1836 clauseBuilder.declareLocalVariable(catchAll.exceptionVariable, | |
| 1837 initialValue: exceptionParameter); | |
| 1838 if (catchAll.stackTraceVariable != null) { | |
| 1839 clauseBuilder.declareLocalVariable(catchAll.stackTraceVariable, | |
| 1840 initialValue: traceParameter); | |
| 1841 } | |
| 1842 catchAll.buildCatchBlock(clauseBuilder); | |
| 1843 if (clauseBuilder.isOpen) clauseBuilder.jumpTo(join); | |
| 1844 catchBody = clauseBuilder._root; | |
| 1845 } | |
| 1846 for (CatchClauseInfo clause in catchClauseInfos.reversed) { | |
| 1847 IrBuilder clauseBuilder = catchBuilder.makeDelimitedBuilder(); | |
| 1848 clauseBuilder.declareLocalVariable(clause.exceptionVariable, | |
| 1849 initialValue: exceptionParameter); | |
| 1850 if (clause.stackTraceVariable != null) { | |
| 1851 clauseBuilder.declareLocalVariable(clause.stackTraceVariable, | |
| 1852 initialValue: traceParameter); | |
| 1853 } | |
| 1854 clause.buildCatchBlock(clauseBuilder); | |
| 1855 if (clauseBuilder.isOpen) clauseBuilder.jumpTo(join); | |
| 1856 ir.Continuation thenContinuation = new ir.Continuation([]); | |
| 1857 thenContinuation.body = clauseBuilder._root; | |
| 1858 ir.Continuation elseContinuation = new ir.Continuation([]); | |
| 1859 elseContinuation.body = catchBody; | |
| 1860 | |
| 1861 // Build the type test guarding this clause. We can share the environment | |
| 1862 // with the nested builder because this part cannot mutate it. | |
| 1863 IrBuilder checkBuilder = catchBuilder.makeDelimitedBuilder(environment); | |
| 1864 ir.Primitive typeMatches = | |
| 1865 checkBuilder.buildTypeOperator(exceptionParameter, | |
| 1866 clause.type, | |
| 1867 isTypeTest: true); | |
| 1868 checkBuilder.add(new ir.LetCont.many([thenContinuation, elseContinuation], | |
| 1869 new ir.Branch(new ir.IsTrue(typeMatches), | |
| 1870 thenContinuation, | |
| 1871 elseContinuation))); | |
| 1872 catchBody = checkBuilder._root; | |
| 1873 } | |
| 1874 | |
| 1875 List<ir.Parameter> catchParameters = | |
| 1876 <ir.Parameter>[exceptionParameter, traceParameter]; | |
| 1877 ir.Continuation catchContinuation = new ir.Continuation(catchParameters); | |
| 1878 catchBuilder.add(catchBody); | |
| 1879 catchContinuation.body = catchBuilder._root; | |
| 1880 | |
| 1881 tryCatchBuilder.add( | |
| 1882 new ir.LetHandler(catchContinuation, tryBuilder._root)); | |
| 1883 add(new ir.LetCont(join.continuation, tryCatchBuilder._root)); | |
| 1884 environment = join.environment; | |
| 1885 } | 1969 } |
| 1886 | 1970 |
| 1887 /// Create a return statement `return value;` or `return;` if [value] is | 1971 /// Create a return statement `return value;` or `return;` if [value] is |
| 1888 /// null. | 1972 /// null. |
| 1889 void buildReturn([ir.Primitive value]) { | 1973 void buildReturn([ir.Primitive value]) { |
| 1890 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] | 1974 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] |
| 1891 // where (C', x) = Build(e, C) | 1975 // where (C', x) = Build(e, C) |
| 1892 // | 1976 // |
| 1893 // Return without a subexpression is translated as if it were return null. | 1977 // Return without a subexpression is translated as if it were return null. |
| 1894 assert(isOpen); | 1978 assert(isOpen); |
| 1895 if (value == null) { | 1979 if (value == null) { |
| 1896 value = buildNullConstant(); | 1980 value = buildNullConstant(); |
| 1897 } | 1981 } |
| 1898 add(new ir.InvokeContinuation(state.returnContinuation, [value])); | 1982 for (SubbuildFunction buildFinallyBlock in state.finallyBlocks.reversed) { |
| 1899 _current = null; | 1983 buildFinallyBlock(this); |
| 1984 if (!isOpen) break; | |
| 1985 } | |
| 1986 if (isOpen) { | |
| 1987 add(new ir.InvokeContinuation(state.returnContinuation, [value])); | |
| 1988 _current = null; | |
| 1989 } | |
| 1900 } | 1990 } |
| 1901 | 1991 |
| 1902 /// Create a blocks of [statements] by applying [build] to all reachable | 1992 /// Create a blocks of [statements] by applying [build] to all reachable |
| 1903 /// statements. The first statement is assumed to be reachable. | 1993 /// statements. The first statement is assumed to be reachable. |
| 1904 // TODO(johnniwinther): Type [statements] as `Iterable` when `NodeList` uses | 1994 // TODO(johnniwinther): Type [statements] as `Iterable` when `NodeList` uses |
| 1905 // `List` instead of `Link`. | 1995 // `List` instead of `Link`. |
| 1906 void buildBlock(var statements, BuildFunction build) { | 1996 void buildBlock(var statements, BuildFunction build) { |
| 1907 // Build(Block(stamements), C) = C' | 1997 // Build(Block(stamements), C) = C' |
| 1908 // where C' = statements.fold(Build, C) | 1998 // where C' = statements.fold(Build, C) |
| 1909 assert(isOpen); | 1999 assert(isOpen); |
| (...skipping 719 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2629 this.buildCatchBlock}); | 2719 this.buildCatchBlock}); |
| 2630 } | 2720 } |
| 2631 | 2721 |
| 2632 class SwitchCaseInfo { | 2722 class SwitchCaseInfo { |
| 2633 final List<ir.Primitive> constants = <ir.Primitive>[]; | 2723 final List<ir.Primitive> constants = <ir.Primitive>[]; |
| 2634 final SubbuildFunction buildBody; | 2724 final SubbuildFunction buildBody; |
| 2635 | 2725 |
| 2636 SwitchCaseInfo(this.buildBody); | 2726 SwitchCaseInfo(this.buildBody); |
| 2637 | 2727 |
| 2638 void addConstant(ir.Primitive constant) => constants.add(constant); | 2728 void addConstant(ir.Primitive constant) => constants.add(constant); |
| 2639 } | 2729 } |
| OLD | NEW |