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 1603 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 } |
OLD | NEW |