Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(350)

Side by Side Diff: pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart

Issue 1201983002: Implement try/finally by inlining the finally code. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Do not translate any more finally blocks after one exits. Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart » ('j') | pkg/pkg.status » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart » ('j') | pkg/pkg.status » ('J')

Powered by Google App Engine
This is Rietveld 408576698