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

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

Issue 1207703002: dart2js CPS: Support try/catch/finally. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Merge, and fix a test expectation. 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') | no next file with comments »
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 1603 matching lines...) Expand 10 before | Expand all | Expand 10 after
1614 environment = join.environment; 1614 environment = join.environment;
1615 } else if (casesBuilder._root != null) { 1615 } else if (casesBuilder._root != null) {
1616 add(casesBuilder._root); 1616 add(casesBuilder._root);
1617 _current = casesBuilder._current; 1617 _current = casesBuilder._current;
1618 environment = casesBuilder.environment; 1618 environment = casesBuilder.environment;
1619 } else { 1619 } else {
1620 // The translation of the cases did not emit any code. 1620 // The translation of the cases did not emit any code.
1621 } 1621 }
1622 } 1622 }
1623 1623
1624 /// Creates a try-statement. 1624 /// Utility function to translate try/catch into the IR.
1625 /// 1625 ///
1626 /// [tryInfo] provides information on local variables declared and boxed 1626 /// The translation treats try/finally and try/catch/finally as if they
1627 /// within this try statement. 1627 /// were macro-expanded into try/catch. This utility function generates
1628 /// that try/catch. The function is parameterized over a list of variables
1629 /// that should be boxed on entry to the try, and over functions to emit
1630 /// code for entering the try, building the try body, leaving the try body,
1631 /// building the catch body, and leaving the entire try/catch.
1632 ///
1633 /// Please see the function's implementation for where these functions are
1634 /// called.
1635 void _helpBuildTryCatch(TryStatementInfo variables,
1636 void enterTry(IrBuilder builder),
1637 SubbuildFunction buildTryBlock,
1638 void leaveTry(IrBuilder builder),
1639 List<ir.Parameter> buildCatch(IrBuilder builder, JumpCollector join),
1640 void leaveTryCatch(IrBuilder builder, JumpCollector join,
1641 ir.Expression body)) {
1642 JumpCollector join = new ForwardJumpCollector(environment);
1643 IrBuilder tryCatchBuilder = makeDelimitedBuilder();
1644
1645 // Variables treated as mutable in a try are not mutable outside of it.
1646 // Work with a copy of the outer builder's mutable variables.
1647 tryCatchBuilder.mutableVariables =
1648 new Map<Local, ir.MutableVariable>.from(mutableVariables);
1649 for (LocalVariableElement variable in variables.boxedOnEntry) {
1650 assert(!tryCatchBuilder.isInMutableVariable(variable));
1651 ir.Primitive value = tryCatchBuilder.buildLocalVariableGet(variable);
1652 tryCatchBuilder.makeMutableVariable(variable);
1653 tryCatchBuilder.declareLocalVariable(variable, initialValue: value);
1654 }
1655
1656 IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder();
1657 enterTry(tryBuilder);
1658 buildTryBlock(tryBuilder);
1659 if (tryBuilder.isOpen) {
1660 join.enterTry(variables.boxedOnEntry);
1661 tryBuilder.jumpTo(join);
1662 join.leaveTry();
1663 }
1664 leaveTry(tryBuilder);
1665
1666 IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder();
1667 for (LocalVariableElement variable in variables.boxedOnEntry) {
1668 assert(catchBuilder.isInMutableVariable(variable));
1669 ir.Primitive value = catchBuilder.buildLocalVariableGet(variable);
1670 // After this point, the variables that were boxed on entry to the try
1671 // are no longer treated as mutable.
1672 catchBuilder.removeMutableVariable(variable);
1673 catchBuilder.environment.update(variable, value);
1674 }
1675
1676 List<ir.Parameter> catchParameters = buildCatch(catchBuilder, join);
1677 ir.Continuation catchContinuation = new ir.Continuation(catchParameters);
1678 catchContinuation.body = catchBuilder._root;
1679 tryCatchBuilder.add(
1680 new ir.LetHandler(catchContinuation, tryBuilder._root));
1681
1682 leaveTryCatch(this, join, tryCatchBuilder._root);
1683 }
1684
1685 /// Translates a try/catch.
1686 ///
1687 /// [variables] provides information on local variables declared and boxed
1688 /// within the try body.
1628 /// [buildTryBlock] builds the try block. 1689 /// [buildTryBlock] builds the try block.
1629 /// [catchClauseInfos] provides access to the catch type, exception variable, 1690 /// [catchClauseInfos] provides access to the catch type, exception variable,
1630 /// and stack trace variable, and a function for building the catch block. 1691 /// and stack trace variable, and a function for building the catch block.
1631 void buildTry( 1692 void buildTryCatch(TryStatementInfo variables,
1632 {TryStatementInfo tryStatementInfo, 1693 SubbuildFunction buildTryBlock,
1633 SubbuildFunction buildTryBlock, 1694 List<CatchClauseInfo> catchClauseInfos) {
1634 List<CatchClauseInfo> catchClauseInfos: const <CatchClauseInfo>[],
1635 SubbuildFunction buildFinallyBlock,
1636 ClosureClassMap closureClassMap}) {
1637 assert(isOpen); 1695 assert(isOpen);
1638
1639 // Catch handlers are in scope for their body. The CPS translation of 1696 // Catch handlers are in scope for their body. The CPS translation of
1640 // [[try tryBlock catch (e) catchBlock; successor]] is: 1697 // [[try tryBlock catch (ex, st) catchBlock; successor]] is:
1641 // 1698 //
1642 // let cont join(v0, v1, ...) = [[successor]] in 1699 // let cont join(v0, v1, ...) = [[successor]] in
1643 // let mutable m0 = x0 in 1700 // let mutable m0 = x0 in
1644 // let mutable m1 = x1 in 1701 // let mutable m1 = x1 in
1645 // ... 1702 // ...
1646 // let handler catch_(e) = 1703 // let handler catch_(ex, st) =
1647 // let prim p0 = GetMutable(m0) in 1704 // let prim p0 = GetMutable(m0) in
1648 // let prim p1 = GetMutable(m1) in 1705 // let prim p1 = GetMutable(m1) in
1649 // ... 1706 // ...
1650 // [[catchBlock]] 1707 // [[catchBlock]]
1651 // join(p0, p1, ...) 1708 // join(p0, p1, ...)
1652 // in 1709 // in
1653 // [[tryBlock]] 1710 // [[tryBlock]]
1654 // let prim p0' = GetMutable(m0) in 1711 // let prim p0' = GetMutable(m0) in
1655 // let prim p1' = GetMutable(m1) in 1712 // let prim p1' = GetMutable(m1) in
1656 // ... 1713 // ...
1657 // join(p0', p1', ...) 1714 // join(p0', p1', ...)
1658 // 1715 //
1659 // In other words, both the try and catch block are in the scope of the 1716 // In other words, both the try and catch block are in the scope of the
1660 // join-point continuation, and they are both in the scope of a sequence 1717 // join-point continuation, and they are both in the scope of a sequence
1661 // of mutable bindings for the variables assigned in the try. The join- 1718 // of mutable bindings for the variables assigned in the try. The join-
1662 // point continuation is not in the scope of these mutable bindings. 1719 // point continuation is not in the scope of these mutable bindings.
1663 // The tryBlock is in the scope of a binding for the catch handler. Each 1720 // The tryBlock is in the scope of a binding for the catch handler. Each
1664 // instruction (specifically, each call) in the tryBlock is in the dynamic 1721 // instruction (specifically, each call) in the tryBlock is in the dynamic
1665 // scope of the handler. The mutable bindings are dereferenced at the end 1722 // scope of the handler. The mutable bindings are dereferenced at the end
1666 // of the try block and at the beginning of the catch block, so the 1723 // of the try block and at the beginning of the catch block, so the
1667 // variables are unboxed in the catch block and at the join point. 1724 // variables are unboxed in the catch block and at the join point.
1668 if (catchClauseInfos.isNotEmpty) {
1669 JumpCollector join = new ForwardJumpCollector(environment);
1670 IrBuilder tryCatchBuilder = makeDelimitedBuilder();
1671 1725
1672 // Variables treated as mutable in a try are not mutable outside of it. 1726 void enterTry(IrBuilder builder) {
1673 // Work with a copy of the outer builder's mutable variables. 1727 // On entry to try of try/catch, update the builder's state to reflect the
1674 tryCatchBuilder.mutableVariables = 1728 // variables that have been boxed.
1675 new Map<Local, ir.MutableVariable>.from(mutableVariables); 1729 void interceptJump(JumpCollector collector) {
1676 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { 1730 collector.enterTry(variables.boxedOnEntry);
1677 assert(!tryCatchBuilder.isInMutableVariable(variable));
1678 ir.Primitive value = tryCatchBuilder.buildLocalVariableGet(variable);
1679 tryCatchBuilder.makeMutableVariable(variable);
1680 tryCatchBuilder.declareLocalVariable(variable, initialValue: value);
1681 } 1731 }
1732 builder.state.breakCollectors.forEach(interceptJump);
1733 builder.state.continueCollectors.forEach(interceptJump);
1734 }
1682 1735
1683 IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder(); 1736 void leaveTry(IrBuilder builder) {
1684 1737 // On exit from try of try/catch, update the builder's state to reflect
1685 void interceptJump(JumpCollector collector) { 1738 // the variables that are no longer boxed.
1686 collector.enterTry(tryStatementInfo.boxedOnEntry);
1687 }
1688 void restoreJump(JumpCollector collector) { 1739 void restoreJump(JumpCollector collector) {
1689 collector.leaveTry(); 1740 collector.leaveTry();
1690 } 1741 }
1691 tryBuilder.state.breakCollectors.forEach(interceptJump); 1742 builder.state.breakCollectors.forEach(restoreJump);
1692 tryBuilder.state.continueCollectors.forEach(interceptJump); 1743 builder.state.continueCollectors.forEach(restoreJump);
1693 buildTryBlock(tryBuilder); 1744 }
1694 if (tryBuilder.isOpen) {
1695 interceptJump(join);
1696 tryBuilder.jumpTo(join);
1697 restoreJump(join);
1698 }
1699 tryBuilder.state.breakCollectors.forEach(restoreJump);
1700 tryBuilder.state.continueCollectors.forEach(restoreJump);
1701 1745
1702 IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder(); 1746 List<ir.Parameter> buildCatch(IrBuilder builder,
1703 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { 1747 JumpCollector join) {
1704 assert(catchBuilder.isInMutableVariable(variable)); 1748 // Translate the catch clauses. Multiple clauses are translated as if
1705 ir.Primitive value = catchBuilder.buildLocalVariableGet(variable); 1749 // they were explicitly cascaded if/else type tests.
1706 // After this point, the variables that were boxed on entry to the try
1707 // are no longer treated as mutable.
1708 catchBuilder.removeMutableVariable(variable);
1709 catchBuilder.environment.update(variable, value);
1710 }
1711 1750
1712 // Handlers are always translated as having both exception and stack trace 1751 // Handlers are always translated as having both exception and stack trace
1713 // parameters. Multiple clauses do not have to use the same names for 1752 // parameters. Multiple clauses do not have to use the same names for
1714 // them. Choose the first of each as the name hint for the respective 1753 // them. Choose the first of each as the name hint for the respective
1715 // handler parameter. 1754 // handler parameter.
1716 ir.Parameter exceptionParameter = 1755 ir.Parameter exceptionParameter =
1717 new ir.Parameter(catchClauseInfos.first.exceptionVariable); 1756 new ir.Parameter(catchClauseInfos.first.exceptionVariable);
1718 LocalVariableElement traceVariable; 1757 LocalVariableElement traceVariable;
1719 CatchClauseInfo catchAll; 1758 CatchClauseInfo catchAll;
1720 for (int i = 0; i < catchClauseInfos.length; ++i) { 1759 for (int i = 0; i < catchClauseInfos.length; ++i) {
1721 CatchClauseInfo info = catchClauseInfos[i]; 1760 CatchClauseInfo info = catchClauseInfos[i];
1722 if (info.type == null) { 1761 if (info.type == null) {
1723 catchAll = info; 1762 catchAll = info;
1724 catchClauseInfos.length = i; 1763 catchClauseInfos.length = i;
1725 break; 1764 break;
1726 } 1765 }
1727 if (traceVariable == null) { 1766 if (traceVariable == null) {
1728 traceVariable = info.stackTraceVariable; 1767 traceVariable = info.stackTraceVariable;
1729 } 1768 }
1730 } 1769 }
1731 ir.Parameter traceParameter = new ir.Parameter(traceVariable); 1770 ir.Parameter traceParameter = new ir.Parameter(traceVariable);
1732 // Expand multiple catch clauses into an explicit if/then/else. Iterate 1771
1733 // them in reverse so the current block becomes the next else block. 1772 ir.Expression buildCatchClause(CatchClauseInfo clause) {
1734 ir.Expression catchBody; 1773 IrBuilder clauseBuilder = builder.makeDelimitedBuilder();
1735 if (catchAll == null) {
1736 catchBody = new ir.Rethrow();
1737 } else {
1738 IrBuilder clauseBuilder = catchBuilder.makeDelimitedBuilder();
1739 clauseBuilder.declareLocalVariable(catchAll.exceptionVariable,
1740 initialValue: exceptionParameter);
1741 if (catchAll.stackTraceVariable != null) {
1742 clauseBuilder.declareLocalVariable(catchAll.stackTraceVariable,
1743 initialValue: traceParameter);
1744 }
1745 catchAll.buildCatchBlock(clauseBuilder);
1746 if (clauseBuilder.isOpen) clauseBuilder.jumpTo(join);
1747 catchBody = clauseBuilder._root;
1748 }
1749 for (CatchClauseInfo clause in catchClauseInfos.reversed) {
1750 IrBuilder clauseBuilder = catchBuilder.makeDelimitedBuilder();
1751 clauseBuilder.declareLocalVariable(clause.exceptionVariable, 1774 clauseBuilder.declareLocalVariable(clause.exceptionVariable,
1752 initialValue: exceptionParameter); 1775 initialValue: exceptionParameter);
1753 if (clause.stackTraceVariable != null) { 1776 if (clause.stackTraceVariable != null) {
1754 clauseBuilder.declareLocalVariable(clause.stackTraceVariable, 1777 clauseBuilder.declareLocalVariable(clause.stackTraceVariable,
1755 initialValue: traceParameter); 1778 initialValue: traceParameter);
1756 } 1779 }
1757 clause.buildCatchBlock(clauseBuilder); 1780 clause.buildCatchBlock(clauseBuilder);
1758 if (clauseBuilder.isOpen) clauseBuilder.jumpTo(join); 1781 if (clauseBuilder.isOpen) clauseBuilder.jumpTo(join);
1782 return clauseBuilder._root;
1783 }
1784
1785 // Expand multiple catch clauses into an explicit if/then/else. Iterate
1786 // them in reverse so the current block becomes the next else block.
1787 ir.Expression catchBody = (catchAll == null)
1788 ? new ir.Rethrow()
1789 : buildCatchClause(catchAll);
1790 for (CatchClauseInfo clause in catchClauseInfos.reversed) {
1759 ir.Continuation thenContinuation = new ir.Continuation([]); 1791 ir.Continuation thenContinuation = new ir.Continuation([]);
1760 thenContinuation.body = clauseBuilder._root;
1761 ir.Continuation elseContinuation = new ir.Continuation([]); 1792 ir.Continuation elseContinuation = new ir.Continuation([]);
1793 thenContinuation.body = buildCatchClause(clause);
1762 elseContinuation.body = catchBody; 1794 elseContinuation.body = catchBody;
1763 1795
1764 // Build the type test guarding this clause. We can share the 1796 // Build the type test guarding this clause. We can share the
1765 // environment with the nested builder because this part cannot mutate 1797 // environment with the nested builder because this part cannot mutate
1766 // it. 1798 // it.
1767 IrBuilder checkBuilder = catchBuilder.makeDelimitedBuilder(environment); 1799 IrBuilder checkBuilder = builder.makeDelimitedBuilder(environment);
1768 ir.Primitive typeMatches = 1800 ir.Primitive typeMatches =
1769 checkBuilder.buildTypeOperator(exceptionParameter, 1801 checkBuilder.buildTypeOperator(exceptionParameter,
1770 clause.type, 1802 clause.type,
1771 isTypeTest: true); 1803 isTypeTest: true);
1772 checkBuilder.add(new ir.LetCont.many([thenContinuation, 1804 checkBuilder.add(new ir.LetCont.many([thenContinuation,
1773 elseContinuation], 1805 elseContinuation],
1774 new ir.Branch(new ir.IsTrue(typeMatches), 1806 new ir.Branch(new ir.IsTrue(typeMatches),
1775 thenContinuation, 1807 thenContinuation,
1776 elseContinuation))); 1808 elseContinuation)));
1777 catchBody = checkBuilder._root; 1809 catchBody = checkBuilder._root;
1778 } 1810 }
1811 builder.add(catchBody);
1779 1812
1780 List<ir.Parameter> catchParameters = 1813 return <ir.Parameter>[exceptionParameter, traceParameter];
1781 <ir.Parameter>[exceptionParameter, traceParameter]; 1814 }
1782 ir.Continuation catchContinuation = new ir.Continuation(catchParameters);
1783 catchBuilder.add(catchBody);
1784 catchContinuation.body = catchBuilder._root;
1785 1815
1786 tryCatchBuilder.add( 1816 void leaveTryCatch(IrBuilder builder, JumpCollector join,
1787 new ir.LetHandler(catchContinuation, tryBuilder._root)); 1817 ir.Expression body) {
1788 add(new ir.LetCont(join.continuation, tryCatchBuilder._root)); 1818 // Add the binding for the join-point continuation and continue the
1789 environment = join.environment; 1819 // translation in its body.
1790 } else { 1820 builder.add(new ir.LetCont(join.continuation, body));
1791 // Try/finally. 1821 builder.environment = join.environment;
1792 JumpCollector join = new ForwardJumpCollector(environment); 1822 }
1793 IrBuilder tryFinallyBuilder = makeDelimitedBuilder();
1794 1823
1795 tryFinallyBuilder.mutableVariables = 1824 _helpBuildTryCatch(variables, enterTry, buildTryBlock, leaveTry,
1796 new Map<Local, ir.MutableVariable>.from(mutableVariables); 1825 buildCatch, leaveTryCatch);
1797 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { 1826 }
1798 assert(!tryFinallyBuilder.isInMutableVariable(variable));
1799 ir.Primitive value = tryFinallyBuilder.buildLocalVariableGet(variable);
1800 tryFinallyBuilder.makeMutableVariable(variable);
1801 tryFinallyBuilder.declareLocalVariable(variable, initialValue: value);
1802 }
1803 1827
1804 IrBuilder tryBuilder = tryFinallyBuilder.makeDelimitedBuilder(); 1828 /// Translates a try/finally.
1829 ///
1830 /// [variables] provides information on local variables declared and boxed
1831 /// within the try body.
1832 /// [buildTryBlock] builds the try block.
1833 /// [buildFinallyBlock] builds the finally block.
1834 void buildTryFinally(TryStatementInfo variables,
1835 SubbuildFunction buildTryBlock,
1836 SubbuildFunction buildFinallyBlock) {
1837 assert(isOpen);
1838 // Try/finally is implemented in terms of try/catch and by duplicating the
1839 // code for finally at all exits. The encoding is:
1840 //
1841 // try tryBlock finally finallyBlock
1842 // ==>
1843 // try tryBlock catch (ex, st) { finallyBlock; rethrow } finallyBlock
1844 //
1845 // Where in tryBlock, all of the break, continue, and return exits are
1846 // translated as jumps to continuations (bound outside the catch handler)
1847 // that include the finally code followed by a break, continue, or
1848 // return respectively.
1805 1849
1850 List<JumpCollector> savedBreaks, newBreaks, savedContinues, newContinues;
1851 JumpCollector savedReturn, newReturn;
1852 void enterTry(IrBuilder builder) {
1853 // On entry to the try of try/finally, update the builder's state to
1854 // relfect the variables that have been boxed. Then intercept all break,
1855 // continue, and return jumps out of the try so that they can go to
1856 // continuations that include the finally code.
1806 JumpCollector interceptJump(JumpCollector collector) { 1857 JumpCollector interceptJump(JumpCollector collector) {
1807 JumpCollector result = 1858 JumpCollector result =
1808 new ForwardJumpCollector(environment, target: collector.target); 1859 new ForwardJumpCollector(environment, target: collector.target);
1809 result.enterTry(tryStatementInfo.boxedOnEntry); 1860 result.enterTry(variables.boxedOnEntry);
1810 return result; 1861 return result;
1811 } 1862 }
1863 savedBreaks = builder.state.breakCollectors;
1864 savedContinues = builder.state.continueCollectors;
1865 savedReturn = builder.state.returnCollector;
1866
1867 builder.state.breakCollectors = newBreaks =
1868 savedBreaks.map(interceptJump).toList();
1869 builder.state.continueCollectors = newContinues =
1870 savedContinues.map(interceptJump).toList();
1871 builder.state.returnCollector = newReturn =
1872 new ForwardJumpCollector(environment, hasExtraArgument: true)
1873 ..enterTry(variables.boxedOnEntry);
1874 }
1875
1876 void leaveTry(IrBuilder builder) {
1877 // On exit from the try of try/finally, update the builder's state to
1878 // reflect the variables that are no longer boxed and restore the
1879 // original, unintercepted break, continue, and return targets.
1812 void restoreJump(JumpCollector collector) { 1880 void restoreJump(JumpCollector collector) {
1813 collector.leaveTry(); 1881 collector.leaveTry();
1814 } 1882 }
1815 List<JumpCollector> savedBreaks = tryBuilder.state.breakCollectors;
1816 List<JumpCollector> savedContinues = tryBuilder.state.continueCollectors;
1817 JumpCollector savedReturn = tryBuilder.state.returnCollector;
1818
1819 List<JumpCollector> newBreaks = tryBuilder.state.breakCollectors =
1820 savedBreaks.map(interceptJump).toList();
1821 List<JumpCollector> newContinues = tryBuilder.state.continueCollectors =
1822 savedContinues.map(interceptJump).toList();
1823 JumpCollector newReturn = tryBuilder.state.returnCollector =
1824 new ForwardJumpCollector(environment, hasExtraArgument: true);
1825 newReturn.enterTry(tryStatementInfo.boxedOnEntry);
1826 buildTryBlock(tryBuilder);
1827 if (tryBuilder.isOpen) {
1828 // To cover control falling off the end of the try block, the finally
1829 // code is translated at the join point. This ensures that it is
1830 // correctly outside the scope of the catch handler.
1831 join.enterTry(tryStatementInfo.boxedOnEntry);
1832 tryBuilder.jumpTo(join);
1833 join.leaveTry();
1834 }
1835 newBreaks.forEach(restoreJump); 1883 newBreaks.forEach(restoreJump);
1836 newContinues.forEach(restoreJump); 1884 newContinues.forEach(restoreJump);
1837 newReturn.leaveTry(); 1885 newReturn.leaveTry();
1838 tryBuilder.state.breakCollectors = savedBreaks; 1886 builder.state.breakCollectors = savedBreaks;
1839 tryBuilder.state.continueCollectors = savedContinues; 1887 builder.state.continueCollectors = savedContinues;
1840 tryBuilder.state.returnCollector = savedReturn; 1888 builder.state.returnCollector = savedReturn;
1889 }
1841 1890
1842 IrBuilder catchBuilder = tryFinallyBuilder.makeDelimitedBuilder(); 1891 List<ir.Parameter> buildCatch(IrBuilder builder,
1843 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { 1892 JumpCollector join) {
1844 assert(catchBuilder.isInMutableVariable(variable)); 1893 // The catch block of the try/catch used for try/finally is the finally
1845 ir.Primitive value = catchBuilder.buildLocalVariableGet(variable); 1894 // code followed by a rethrow.
1846 catchBuilder.removeMutableVariable(variable); 1895 buildFinallyBlock(builder);
1847 catchBuilder.environment.update(variable, value); 1896 if (builder.isOpen) {
1897 builder.add(new ir.Rethrow());
1898 builder._current = null;
1848 } 1899 }
1900 return <ir.Parameter>[new ir.Parameter(null), new ir.Parameter(null)];
1901 }
1849 1902
1850 buildFinallyBlock(catchBuilder); 1903 void leaveTryCatch(IrBuilder builder, JumpCollector join,
1851 if (catchBuilder.isOpen) { 1904 ir.Expression body) {
1852 catchBuilder.add(new ir.Rethrow());
1853 catchBuilder._current = null;
1854 }
1855 List<ir.Parameter> catchParameters =
1856 <ir.Parameter>[new ir.Parameter(null), new ir.Parameter(null)];
1857 ir.Continuation catchContinuation = new ir.Continuation(catchParameters);
1858 catchContinuation.body = catchBuilder._root;
1859 tryFinallyBuilder.add(
1860 new ir.LetHandler(catchContinuation, tryBuilder._root));
1861
1862 // Build a list of continuations for jumps from the try block and 1905 // Build a list of continuations for jumps from the try block and
1863 // duplicate the finally code before jumping to the actual target. 1906 // duplicate the finally code before jumping to the actual target.
1864 List<ir.Continuation> exits = <ir.Continuation>[join.continuation]; 1907 List<ir.Continuation> exits = <ir.Continuation>[join.continuation];
1865 void addJump(JumpCollector newCollector, 1908 void addJump(JumpCollector newCollector,
1866 JumpCollector originalCollector) { 1909 JumpCollector originalCollector) {
1867 if (newCollector.isEmpty) return; 1910 if (newCollector.isEmpty) return;
1868 IrBuilder builder = makeDelimitedBuilder(newCollector.environment); 1911 IrBuilder builder = makeDelimitedBuilder(newCollector.environment);
1869 buildFinallyBlock(builder); 1912 buildFinallyBlock(builder);
1870 if (builder.isOpen) builder.jumpTo(originalCollector); 1913 if (builder.isOpen) builder.jumpTo(originalCollector);
1871 newCollector.continuation.body = builder._root; 1914 newCollector.continuation.body = builder._root;
1872 exits.add(newCollector.continuation); 1915 exits.add(newCollector.continuation);
1873 } 1916 }
1874 for (int i = 0; i < newBreaks.length; ++i) { 1917 for (int i = 0; i < newBreaks.length; ++i) {
1875 addJump(newBreaks[i], savedBreaks[i]); 1918 addJump(newBreaks[i], savedBreaks[i]);
1876 } 1919 }
1877 for (int i = 0; i < newContinues.length; ++i) { 1920 for (int i = 0; i < newContinues.length; ++i) {
1878 addJump(newContinues[i], savedContinues[i]); 1921 addJump(newContinues[i], savedContinues[i]);
1879 } 1922 }
1880 if (!newReturn.isEmpty) { 1923 if (!newReturn.isEmpty) {
1881 IrBuilder builder = makeDelimitedBuilder(newReturn.environment); 1924 IrBuilder builder = makeDelimitedBuilder(newReturn.environment);
1882 ir.Primitive value = builder.environment.discard(1); 1925 ir.Primitive value = builder.environment.discard(1);
1883 buildFinallyBlock(builder); 1926 buildFinallyBlock(builder);
1884 if (builder.isOpen) builder.buildReturn(value); 1927 if (builder.isOpen) builder.buildReturn(value);
1885 newReturn.continuation.body = builder._root; 1928 newReturn.continuation.body = builder._root;
1886 exits.add(newReturn.continuation); 1929 exits.add(newReturn.continuation);
1887 } 1930 }
1888 add(new ir.LetCont.many(exits, tryFinallyBuilder._root)); 1931 builder.add(new ir.LetCont.many(exits, body));
1889 environment = join.environment; 1932 builder.environment = join.environment;
1890 buildFinallyBlock(this); 1933 buildFinallyBlock(builder);
1891 } 1934 }
1935
1936 _helpBuildTryCatch(variables, enterTry, buildTryBlock, leaveTry,
1937 buildCatch, leaveTryCatch);
1892 } 1938 }
1893 1939
1894 /// Create a return statement `return value;` or `return;` if [value] is 1940 /// Create a return statement `return value;` or `return;` if [value] is
1895 /// null. 1941 /// null.
1896 void buildReturn([ir.Primitive value]) { 1942 void buildReturn([ir.Primitive value]) {
1897 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] 1943 // Build(Return(e), C) = C'[InvokeContinuation(return, x)]
1898 // where (C', x) = Build(e, C) 1944 // where (C', x) = Build(e, C)
1899 // 1945 //
1900 // Return without a subexpression is translated as if it were return null. 1946 // Return without a subexpression is translated as if it were return null.
1901 assert(isOpen); 1947 assert(isOpen);
(...skipping 729 matching lines...) Expand 10 before | Expand all | Expand 10 after
2631 } 2677 }
2632 2678
2633 class SwitchCaseInfo { 2679 class SwitchCaseInfo {
2634 final List<ir.Primitive> constants = <ir.Primitive>[]; 2680 final List<ir.Primitive> constants = <ir.Primitive>[];
2635 final SubbuildFunction buildBody; 2681 final SubbuildFunction buildBody;
2636 2682
2637 SwitchCaseInfo(this.buildBody); 2683 SwitchCaseInfo(this.buildBody);
2638 2684
2639 void addConstant(ir.Primitive constant) => constants.add(constant); 2685 void addConstant(ir.Primitive constant) => constants.add(constant);
2640 } 2686 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698