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 } | |
| 177 } | 188 } |
| 178 } | 189 } |
| 179 | 190 |
| 180 /// A class to collect 'forward' jumps. | 191 /// A class to collect 'forward' jumps. |
| 181 /// | 192 /// |
| 182 /// A forward jump to a continuation in the sense of the CPS translation is | 193 /// 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 | 194 /// 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 | 195 /// continuation is translated. They have the property that continuation |
| 185 /// parameters and the environment for the translation of the body can be | 196 /// parameters and the environment for the translation of the body can be |
| 186 /// determined based on the invocations, before translating the body. A | 197 /// determined based on the invocations, before translating the body. A |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 392 final BackendConstantEnvironment constants; | 403 final BackendConstantEnvironment constants; |
| 393 | 404 |
| 394 ConstantSystem get constantSystem => constants.constantSystem; | 405 ConstantSystem get constantSystem => constants.constantSystem; |
| 395 | 406 |
| 396 /// A stack of collectors for breaks. | 407 /// A stack of collectors for breaks. |
| 397 final List<JumpCollector> breakCollectors = <JumpCollector>[]; | 408 final List<JumpCollector> breakCollectors = <JumpCollector>[]; |
| 398 | 409 |
| 399 /// A stack of collectors for continues. | 410 /// A stack of collectors for continues. |
| 400 final List<JumpCollector> continueCollectors = <JumpCollector>[]; | 411 final List<JumpCollector> continueCollectors = <JumpCollector>[]; |
| 401 | 412 |
| 413 /// A stack of enclosing finally blocks, used when translating return. | |
| 414 final List<SubbuildFunction> finallyBlocks = <SubbuildFunction>[]; | |
| 415 | |
| 402 final List<ConstDeclaration> localConstants = <ConstDeclaration>[]; | 416 final List<ConstDeclaration> localConstants = <ConstDeclaration>[]; |
| 403 | 417 |
| 404 final ExecutableElement currentElement; | 418 final ExecutableElement currentElement; |
| 405 | 419 |
| 406 final ir.Continuation returnContinuation = new ir.Continuation.retrn(); | 420 final ir.Continuation returnContinuation = new ir.Continuation.retrn(); |
| 407 ir.Parameter _thisParameter; | 421 ir.Parameter _thisParameter; |
| 408 ir.Parameter enclosingMethodThisParameter; | 422 ir.Parameter enclosingMethodThisParameter; |
| 409 | 423 |
| 410 final List<ir.Parameter> functionParameters = <ir.Parameter>[]; | 424 final List<ir.Parameter> functionParameters = <ir.Parameter>[]; |
| 411 | 425 |
| (...skipping 1312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1724 /// | 1738 /// |
| 1725 /// [tryInfo] provides information on local variables declared and boxed | 1739 /// [tryInfo] provides information on local variables declared and boxed |
| 1726 /// within this try statement. | 1740 /// within this try statement. |
| 1727 /// [buildTryBlock] builds the try block. | 1741 /// [buildTryBlock] builds the try block. |
| 1728 /// [catchClauseInfos] provides access to the catch type, exception variable, | 1742 /// [catchClauseInfos] provides access to the catch type, exception variable, |
| 1729 /// and stack trace variable, and a function for building the catch block. | 1743 /// and stack trace variable, and a function for building the catch block. |
| 1730 void buildTry( | 1744 void buildTry( |
| 1731 {TryStatementInfo tryStatementInfo, | 1745 {TryStatementInfo tryStatementInfo, |
| 1732 SubbuildFunction buildTryBlock, | 1746 SubbuildFunction buildTryBlock, |
| 1733 List<CatchClauseInfo> catchClauseInfos: const <CatchClauseInfo>[], | 1747 List<CatchClauseInfo> catchClauseInfos: const <CatchClauseInfo>[], |
| 1748 SubbuildFunction buildFinallyBlock, | |
| 1734 ClosureClassMap closureClassMap}) { | 1749 ClosureClassMap closureClassMap}) { |
| 1735 assert(isOpen); | 1750 assert(isOpen); |
| 1736 | 1751 |
| 1737 // Catch handlers are in scope for their body. The CPS translation of | 1752 // Catch handlers are in scope for their body. The CPS translation of |
| 1738 // [[try tryBlock catch (e) catchBlock; successor]] is: | 1753 // [[try tryBlock catch (e) catchBlock; successor]] is: |
| 1739 // | 1754 // |
| 1740 // let cont join(v0, v1, ...) = [[successor]] in | 1755 // let cont join(v0, v1, ...) = [[successor]] in |
| 1741 // let mutable m0 = x0 in | 1756 // let mutable m0 = x0 in |
| 1742 // let mutable m1 = x1 in | 1757 // let mutable m1 = x1 in |
| 1743 // ... | 1758 // ... |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1756 // | 1771 // |
| 1757 // In other words, both the try and catch block are in the scope of the | 1772 // 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 | 1773 // 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- | 1774 // of mutable bindings for the variables assigned in the try. The join- |
| 1760 // point continuation is not in the scope of these mutable bindings. | 1775 // 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 | 1776 // 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 | 1777 // instruction (specifically, each call) in the tryBlock is in the dynamic |
| 1763 // scope of the handler. The mutable bindings are dereferenced at the end | 1778 // 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 | 1779 // 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. | 1780 // variables are unboxed in the catch block and at the join point. |
| 1766 JumpCollector join = new ForwardJumpCollector(environment); | 1781 if (catchClauseInfos.isNotEmpty) { |
| 1767 IrBuilder tryCatchBuilder = makeDelimitedBuilder(); | 1782 JumpCollector join = new ForwardJumpCollector(environment); |
|
Kevin Millikin (Google)
2015/06/22 15:36:42
This is the code for try/catch. It is unchanged e
| |
| 1783 IrBuilder tryCatchBuilder = makeDelimitedBuilder(); | |
| 1768 | 1784 |
| 1769 // Variables treated as mutable in a try are not mutable outside of it. | 1785 // 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. | 1786 // Work with a copy of the outer builder's mutable variables. |
| 1771 tryCatchBuilder.mutableVariables = | 1787 tryCatchBuilder.mutableVariables = |
| 1772 new Map<Local, ir.MutableVariable>.from(mutableVariables); | 1788 new Map<Local, ir.MutableVariable>.from(mutableVariables); |
| 1773 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { | 1789 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { |
| 1774 assert(!tryCatchBuilder.isInMutableVariable(variable)); | 1790 assert(!tryCatchBuilder.isInMutableVariable(variable)); |
| 1775 ir.Primitive value = tryCatchBuilder.buildLocalVariableGet(variable); | 1791 ir.Primitive value = tryCatchBuilder.buildLocalVariableGet(variable); |
| 1776 tryCatchBuilder.makeMutableVariable(variable); | 1792 tryCatchBuilder.makeMutableVariable(variable); |
| 1777 tryCatchBuilder.declareLocalVariable(variable, initialValue: value); | 1793 tryCatchBuilder.declareLocalVariable(variable, initialValue: value); |
| 1794 } | |
| 1795 | |
| 1796 IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder(); | |
| 1797 | |
| 1798 void interceptJump(JumpCollector collector) { | |
| 1799 collector.enterTry(tryStatementInfo.boxedOnEntry); | |
| 1800 } | |
| 1801 void restoreJump(JumpCollector collector) { | |
| 1802 collector.leaveTry(); | |
| 1803 } | |
| 1804 tryBuilder.state.breakCollectors.forEach(interceptJump); | |
| 1805 tryBuilder.state.continueCollectors.forEach(interceptJump); | |
| 1806 buildTryBlock(tryBuilder); | |
| 1807 if (tryBuilder.isOpen) { | |
| 1808 interceptJump(join); | |
| 1809 tryBuilder.jumpTo(join); | |
| 1810 restoreJump(join); | |
| 1811 } | |
| 1812 tryBuilder.state.breakCollectors.forEach(restoreJump); | |
| 1813 tryBuilder.state.continueCollectors.forEach(restoreJump); | |
| 1814 | |
| 1815 IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder(); | |
| 1816 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { | |
| 1817 assert(catchBuilder.isInMutableVariable(variable)); | |
| 1818 ir.Primitive value = catchBuilder.buildLocalVariableGet(variable); | |
| 1819 // After this point, the variables that were boxed on entry to the try | |
| 1820 // are no longer treated as mutable. | |
| 1821 catchBuilder.removeMutableVariable(variable); | |
| 1822 catchBuilder.environment.update(variable, value); | |
| 1823 } | |
| 1824 | |
| 1825 // Handlers are always translated as having both exception and stack trace | |
| 1826 // parameters. Multiple clauses do not have to use the same names for | |
| 1827 // them. Choose the first of each as the name hint for the respective | |
| 1828 // handler parameter. | |
| 1829 ir.Parameter exceptionParameter = | |
| 1830 new ir.Parameter(catchClauseInfos.first.exceptionVariable); | |
| 1831 LocalVariableElement traceVariable; | |
| 1832 CatchClauseInfo catchAll; | |
| 1833 for (int i = 0; i < catchClauseInfos.length; ++i) { | |
| 1834 CatchClauseInfo info = catchClauseInfos[i]; | |
| 1835 if (info.type == null) { | |
| 1836 catchAll = info; | |
| 1837 catchClauseInfos.length = i; | |
| 1838 break; | |
| 1839 } | |
| 1840 if (traceVariable == null) { | |
| 1841 traceVariable = info.stackTraceVariable; | |
| 1842 } | |
| 1843 } | |
| 1844 ir.Parameter traceParameter = new ir.Parameter(traceVariable); | |
| 1845 // Expand multiple catch clauses into an explicit if/then/else. Iterate | |
| 1846 // them in reverse so the current block becomes the next else block. | |
| 1847 ir.Expression catchBody; | |
| 1848 if (catchAll == null) { | |
| 1849 catchBody = new ir.Rethrow(); | |
| 1850 } else { | |
| 1851 IrBuilder clauseBuilder = catchBuilder.makeDelimitedBuilder(); | |
| 1852 clauseBuilder.declareLocalVariable(catchAll.exceptionVariable, | |
| 1853 initialValue: exceptionParameter); | |
| 1854 if (catchAll.stackTraceVariable != null) { | |
| 1855 clauseBuilder.declareLocalVariable(catchAll.stackTraceVariable, | |
| 1856 initialValue: traceParameter); | |
| 1857 } | |
| 1858 catchAll.buildCatchBlock(clauseBuilder); | |
| 1859 if (clauseBuilder.isOpen) clauseBuilder.jumpTo(join); | |
| 1860 catchBody = clauseBuilder._root; | |
| 1861 } | |
| 1862 for (CatchClauseInfo clause in catchClauseInfos.reversed) { | |
| 1863 IrBuilder clauseBuilder = catchBuilder.makeDelimitedBuilder(); | |
| 1864 clauseBuilder.declareLocalVariable(clause.exceptionVariable, | |
| 1865 initialValue: exceptionParameter); | |
| 1866 if (clause.stackTraceVariable != null) { | |
| 1867 clauseBuilder.declareLocalVariable(clause.stackTraceVariable, | |
| 1868 initialValue: traceParameter); | |
| 1869 } | |
| 1870 clause.buildCatchBlock(clauseBuilder); | |
| 1871 if (clauseBuilder.isOpen) clauseBuilder.jumpTo(join); | |
| 1872 ir.Continuation thenContinuation = new ir.Continuation([]); | |
| 1873 thenContinuation.body = clauseBuilder._root; | |
| 1874 ir.Continuation elseContinuation = new ir.Continuation([]); | |
| 1875 elseContinuation.body = catchBody; | |
| 1876 | |
| 1877 // Build the type test guarding this clause. We can share the | |
| 1878 // environment with the nested builder because this part cannot mutate | |
| 1879 // it. | |
| 1880 IrBuilder checkBuilder = catchBuilder.makeDelimitedBuilder(environment); | |
| 1881 ir.Primitive typeMatches = | |
| 1882 checkBuilder.buildTypeOperator(exceptionParameter, | |
| 1883 clause.type, | |
| 1884 isTypeTest: true); | |
| 1885 checkBuilder.add(new ir.LetCont.many([thenContinuation, | |
| 1886 elseContinuation], | |
| 1887 new ir.Branch(new ir.IsTrue(typeMatches), | |
| 1888 thenContinuation, | |
| 1889 elseContinuation))); | |
| 1890 catchBody = checkBuilder._root; | |
| 1891 } | |
| 1892 | |
| 1893 List<ir.Parameter> catchParameters = | |
| 1894 <ir.Parameter>[exceptionParameter, traceParameter]; | |
| 1895 ir.Continuation catchContinuation = new ir.Continuation(catchParameters); | |
| 1896 catchBuilder.add(catchBody); | |
| 1897 catchContinuation.body = catchBuilder._root; | |
| 1898 | |
| 1899 tryCatchBuilder.add( | |
| 1900 new ir.LetHandler(catchContinuation, tryBuilder._root)); | |
| 1901 add(new ir.LetCont(join.continuation, tryCatchBuilder._root)); | |
| 1902 environment = join.environment; | |
| 1903 } else { | |
| 1904 // Try/finally. | |
|
Kevin Millikin (Google)
2015/06/22 15:36:42
This is the code for try/finally. There is a lot
| |
| 1905 JumpCollector join = new ForwardJumpCollector(environment); | |
| 1906 IrBuilder tryFinallyBuilder = makeDelimitedBuilder(); | |
| 1907 | |
| 1908 tryFinallyBuilder.mutableVariables = | |
| 1909 new Map<Local, ir.MutableVariable>.from(mutableVariables); | |
| 1910 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { | |
| 1911 assert(!tryFinallyBuilder.isInMutableVariable(variable)); | |
| 1912 ir.Primitive value = tryFinallyBuilder.buildLocalVariableGet(variable); | |
| 1913 tryFinallyBuilder.makeMutableVariable(variable); | |
| 1914 tryFinallyBuilder.declareLocalVariable(variable, initialValue: value); | |
| 1915 } | |
| 1916 | |
| 1917 IrBuilder tryBuilder = tryFinallyBuilder.makeDelimitedBuilder(); | |
| 1918 | |
| 1919 void interceptJump(JumpCollector collector) { | |
| 1920 collector.enterTry(tryStatementInfo.boxedOnEntry, buildFinallyBlock); | |
| 1921 } | |
| 1922 void restoreJump(JumpCollector collector) { | |
| 1923 collector.leaveTry(); | |
| 1924 } | |
| 1925 tryBuilder.state.breakCollectors.forEach(interceptJump); | |
| 1926 tryBuilder.state.continueCollectors.forEach(interceptJump); | |
| 1927 tryBuilder.state.finallyBlocks.add(buildFinallyBlock); | |
| 1928 buildTryBlock(tryBuilder); | |
| 1929 if (tryBuilder.isOpen) { | |
| 1930 // To cover control falling off the end of the try block, the finally | |
| 1931 // code is translated at the join point. This ensures that it is | |
| 1932 // correctly outside the scope of the catch handler. | |
| 1933 join.enterTry(tryStatementInfo.boxedOnEntry); | |
| 1934 tryBuilder.jumpTo(join); | |
| 1935 join.leaveTry(); | |
| 1936 } | |
| 1937 tryBuilder.state.breakCollectors.forEach(restoreJump); | |
| 1938 tryBuilder.state.continueCollectors.forEach(restoreJump); | |
| 1939 tryBuilder.state.finallyBlocks.removeLast(); | |
| 1940 | |
| 1941 IrBuilder catchBuilder = tryFinallyBuilder.makeDelimitedBuilder(); | |
| 1942 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { | |
| 1943 assert(catchBuilder.isInMutableVariable(variable)); | |
| 1944 ir.Primitive value = catchBuilder.buildLocalVariableGet(variable); | |
| 1945 catchBuilder.removeMutableVariable(variable); | |
| 1946 catchBuilder.environment.update(variable, value); | |
| 1947 } | |
| 1948 | |
| 1949 buildFinallyBlock(catchBuilder); | |
| 1950 if (catchBuilder.isOpen) { | |
| 1951 catchBuilder.add(new ir.Rethrow()); | |
| 1952 catchBuilder._current = null; | |
| 1953 } | |
| 1954 List<ir.Parameter> catchParameters = | |
| 1955 <ir.Parameter>[new ir.Parameter(null), new ir.Parameter(null)]; | |
| 1956 ir.Continuation catchContinuation = new ir.Continuation(catchParameters); | |
| 1957 catchContinuation.body = catchBuilder._root; | |
| 1958 tryFinallyBuilder.add( | |
| 1959 new ir.LetHandler(catchContinuation, tryBuilder._root)); | |
| 1960 add(new ir.LetCont(join.continuation, tryFinallyBuilder._root)); | |
| 1961 environment = join.environment; | |
| 1962 buildFinallyBlock(this); | |
| 1778 } | 1963 } |
| 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 } | 1964 } |
| 1886 | 1965 |
| 1887 /// Create a return statement `return value;` or `return;` if [value] is | 1966 /// Create a return statement `return value;` or `return;` if [value] is |
| 1888 /// null. | 1967 /// null. |
| 1889 void buildReturn([ir.Primitive value]) { | 1968 void buildReturn([ir.Primitive value]) { |
| 1890 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] | 1969 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] |
| 1891 // where (C', x) = Build(e, C) | 1970 // where (C', x) = Build(e, C) |
| 1892 // | 1971 // |
| 1893 // Return without a subexpression is translated as if it were return null. | 1972 // Return without a subexpression is translated as if it were return null. |
| 1894 assert(isOpen); | 1973 assert(isOpen); |
| 1895 if (value == null) { | 1974 if (value == null) { |
| 1896 value = buildNullConstant(); | 1975 value = buildNullConstant(); |
| 1897 } | 1976 } |
| 1898 add(new ir.InvokeContinuation(state.returnContinuation, [value])); | 1977 for (SubbuildFunction buildFinallyBlock in state.finallyBlocks.reversed) { |
| 1899 _current = null; | 1978 buildFinallyBlock(this); |
| 1979 if (!isOpen) break; | |
| 1980 } | |
| 1981 if (isOpen) { | |
| 1982 add(new ir.InvokeContinuation(state.returnContinuation, [value])); | |
| 1983 _current = null; | |
| 1984 } | |
| 1900 } | 1985 } |
| 1901 | 1986 |
| 1902 /// Create a blocks of [statements] by applying [build] to all reachable | 1987 /// Create a blocks of [statements] by applying [build] to all reachable |
| 1903 /// statements. The first statement is assumed to be reachable. | 1988 /// statements. The first statement is assumed to be reachable. |
| 1904 // TODO(johnniwinther): Type [statements] as `Iterable` when `NodeList` uses | 1989 // TODO(johnniwinther): Type [statements] as `Iterable` when `NodeList` uses |
| 1905 // `List` instead of `Link`. | 1990 // `List` instead of `Link`. |
| 1906 void buildBlock(var statements, BuildFunction build) { | 1991 void buildBlock(var statements, BuildFunction build) { |
| 1907 // Build(Block(stamements), C) = C' | 1992 // Build(Block(stamements), C) = C' |
| 1908 // where C' = statements.fold(Build, C) | 1993 // where C' = statements.fold(Build, C) |
| 1909 assert(isOpen); | 1994 assert(isOpen); |
| (...skipping 719 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2629 this.buildCatchBlock}); | 2714 this.buildCatchBlock}); |
| 2630 } | 2715 } |
| 2631 | 2716 |
| 2632 class SwitchCaseInfo { | 2717 class SwitchCaseInfo { |
| 2633 final List<ir.Primitive> constants = <ir.Primitive>[]; | 2718 final List<ir.Primitive> constants = <ir.Primitive>[]; |
| 2634 final SubbuildFunction buildBody; | 2719 final SubbuildFunction buildBody; |
| 2635 | 2720 |
| 2636 SwitchCaseInfo(this.buildBody); | 2721 SwitchCaseInfo(this.buildBody); |
| 2637 | 2722 |
| 2638 void addConstant(ir.Primitive constant) => constants.add(constant); | 2723 void addConstant(ir.Primitive constant) => constants.add(constant); |
| 2639 } | 2724 } |
| OLD | NEW |