Mercurial > hg > graal-compiler
comparison graal/GraalCompiler/src/com/sun/c1x/alloc/LinearScan.java @ 2707:7ed72769d51a
exception handling related changes:
* changed blockPredecessors to list of Instructions, instead of Blocks
* removed explicit predecessor management in BlockBegin, now using predecessors from Graph structure
* replaced generated LIR exception entries with exception dispatch chains in IR
* added Unwind and ExceptionDispatch instructions
* removed ExceptionEntry flag in BlockBegin and all code depending on it
* removed exceptionHandler list from Instruction, replaced by exception Edge on Invoke and Throw
* replaced list of ExceptionHandlers with single exception edge in debug info
misc:
* changed GraphvizPrinter layout (smaller ports on large nodes)
* removed defunct run config
author | Lukas Stadler <lukas.stadler@jku.at> |
---|---|
date | Wed, 18 May 2011 18:09:20 +0200 |
parents | 6ab73784566a |
children | 4272b7af2d17 |
comparison
equal
deleted
inserted
replaced
2677:0ea5f12e873a | 2707:7ed72769d51a |
---|---|
26 import static java.lang.reflect.Modifier.*; | 26 import static java.lang.reflect.Modifier.*; |
27 | 27 |
28 import java.util.*; | 28 import java.util.*; |
29 | 29 |
30 import com.sun.c1x.*; | 30 import com.sun.c1x.*; |
31 import com.sun.c1x.alloc.Interval.*; | 31 import com.sun.c1x.alloc.Interval.RegisterBinding; |
32 import com.sun.c1x.alloc.Interval.RegisterPriority; | |
33 import com.sun.c1x.alloc.Interval.SpillState; | |
32 import com.sun.c1x.debug.*; | 34 import com.sun.c1x.debug.*; |
33 import com.sun.c1x.gen.*; | 35 import com.sun.c1x.gen.*; |
34 import com.sun.c1x.graph.*; | 36 import com.sun.c1x.graph.*; |
35 import com.sun.c1x.ir.*; | 37 import com.sun.c1x.ir.*; |
36 import com.sun.c1x.ir.BlockBegin.BlockFlag; | |
37 import com.sun.c1x.lir.*; | 38 import com.sun.c1x.lir.*; |
38 import com.sun.c1x.lir.LIRInstruction.OperandMode; | 39 import com.sun.c1x.lir.LIRInstruction.OperandMode; |
39 import com.sun.c1x.observer.*; | 40 import com.sun.c1x.observer.*; |
40 import com.sun.c1x.util.*; | 41 import com.sun.c1x.util.*; |
41 import com.sun.c1x.value.*; | 42 import com.sun.c1x.value.*; |
42 import com.sun.c1x.value.FrameState.PhiProcedure; | |
43 import com.sun.c1x.value.FrameState.ValueProcedure; | 43 import com.sun.c1x.value.FrameState.ValueProcedure; |
44 import com.sun.cri.ci.*; | 44 import com.sun.cri.ci.*; |
45 import com.sun.cri.ri.*; | 45 import com.sun.cri.ri.*; |
46 | 46 |
47 /** | 47 /** |
596 // iterate all blocks | 596 // iterate all blocks |
597 for (int i = 0; i < numBlocks; i++) { | 597 for (int i = 0; i < numBlocks; i++) { |
598 BlockBegin block = blockAt(i); | 598 BlockBegin block = blockAt(i); |
599 final CiBitMap liveGen = new CiBitMap(liveSize); | 599 final CiBitMap liveGen = new CiBitMap(liveSize); |
600 final CiBitMap liveKill = new CiBitMap(liveSize); | 600 final CiBitMap liveKill = new CiBitMap(liveSize); |
601 | |
602 if (block.isExceptionEntry()) { | |
603 // Phi functions at the begin of an exception handler are | |
604 // implicitly defined (= killed) at the beginning of the block. | |
605 block.stateBefore().forEachLivePhi(block, new PhiProcedure() { | |
606 public boolean doPhi(Phi phi) { | |
607 liveKill.set(operandNumber(phi.operand())); | |
608 return true; | |
609 } | |
610 }); | |
611 } | |
612 | 601 |
613 List<LIRInstruction> instructions = block.lir().instructionsList(); | 602 List<LIRInstruction> instructions = block.lir().instructionsList(); |
614 int numInst = instructions.size(); | 603 int numInst = instructions.size(); |
615 | 604 |
616 // iterate all instructions of the block. skip the first because it is always a label | 605 // iterate all instructions of the block. skip the first because it is always a label |
771 | 760 |
772 changeOccurredInBlock = false; | 761 changeOccurredInBlock = false; |
773 | 762 |
774 // liveOut(block) is the union of liveIn(sux), for successors sux of block | 763 // liveOut(block) is the union of liveIn(sux), for successors sux of block |
775 int n = block.numberOfSux(); | 764 int n = block.numberOfSux(); |
776 int e = block.numberOfExceptionHandlers(); | 765 if (n > 0) { |
777 if (n + e > 0) { | |
778 // block has successors | 766 // block has successors |
779 if (n > 0) { | 767 if (n > 0) { |
780 liveOut.setFrom(block.suxAt(0).lirBlock.liveIn); | 768 liveOut.setFrom(block.suxAt(0).lirBlock.liveIn); |
781 for (int j = 1; j < n; j++) { | 769 for (int j = 1; j < n; j++) { |
782 liveOut.setUnion(block.suxAt(j).lirBlock.liveIn); | 770 liveOut.setUnion(block.suxAt(j).lirBlock.liveIn); |
783 } | 771 } |
784 } else { | 772 } else { |
785 liveOut.clearAll(); | 773 liveOut.clearAll(); |
786 } | |
787 for (int j = 0; j < e; j++) { | |
788 liveOut.setUnion(block.exceptionHandlerAt(j).lirBlock.liveIn); | |
789 } | 774 } |
790 | 775 |
791 if (!lirBlock.liveOut.isSame(liveOut)) { | 776 if (!lirBlock.liveOut.isSame(liveOut)) { |
792 // A change occurred. Swap the old and new live out sets to avoid copying. | 777 // A change occurred. Swap the old and new live out sets to avoid copying. |
793 CiBitMap temp = lirBlock.liveOut; | 778 CiBitMap temp = lirBlock.liveOut; |
1280 addRegisterHints(op); | 1265 addRegisterHints(op); |
1281 | 1266 |
1282 } // end of instruction iteration | 1267 } // end of instruction iteration |
1283 | 1268 |
1284 // (tw) Make sure that no spill store optimization is applied for phi instructions that flow into exception handlers. | 1269 // (tw) Make sure that no spill store optimization is applied for phi instructions that flow into exception handlers. |
1285 if (block.isExceptionEntry()) { | 1270 // if (block.isExceptionEntry()) { |
1286 FrameState stateBefore = block.stateBefore(); | 1271 // FrameState stateBefore = block.stateBefore(); |
1287 stateBefore.forEachLivePhi(block, new PhiProcedure() { | 1272 // stateBefore.forEachLivePhi(block, new PhiProcedure() { |
1288 @Override | 1273 // @Override |
1289 public boolean doPhi(Phi phi) { | 1274 // public boolean doPhi(Phi phi) { |
1290 Interval interval = intervalFor(phi.operand()); | 1275 // Interval interval = intervalFor(phi.operand()); |
1291 if (interval != null) { | 1276 // if (interval != null) { |
1292 interval.setSpillState(SpillState.NoOptimization); | 1277 // interval.setSpillState(SpillState.NoOptimization); |
1293 } | 1278 // } |
1294 return true; | 1279 // return true; |
1295 } | 1280 // } |
1296 }); | 1281 // }); |
1297 } | 1282 // } |
1298 | 1283 |
1299 } // end of block iteration | 1284 } // end of block iteration |
1300 | 1285 |
1301 // add the range [0, 1] to all fixed intervals. | 1286 // add the range [0, 1] to all fixed intervals. |
1302 // the register allocator need not handle unhandled fixed intervals | 1287 // the register allocator need not handle unhandled fixed intervals |
1594 // because the number of predecessor edges matches the number of | 1579 // because the number of predecessor edges matches the number of |
1595 // successor edges, blocks which are reached by switch statements | 1580 // successor edges, blocks which are reached by switch statements |
1596 // may have be more than one predecessor but it will be guaranteed | 1581 // may have be more than one predecessor but it will be guaranteed |
1597 // that all predecessors will be the same. | 1582 // that all predecessors will be the same. |
1598 for (int i = 0; i < toBlock.numberOfPreds(); i++) { | 1583 for (int i = 0; i < toBlock.numberOfPreds(); i++) { |
1599 assert fromBlock == toBlock.predAt(i).begin() : "all critical edges must be broken"; | 1584 assert fromBlock == toBlock.predAt(i).block() : "all critical edges must be broken"; |
1600 } | 1585 } |
1601 } | 1586 } |
1602 | 1587 |
1603 moveResolver.setInsertPosition(toBlock.lir(), 0); | 1588 moveResolver.setInsertPosition(toBlock.lir(), 0); |
1604 } | 1589 } |
1617 int i; | 1602 int i; |
1618 for (i = 0; i < numBlocks; i++) { | 1603 for (i = 0; i < numBlocks; i++) { |
1619 BlockBegin block = blockAt(i); | 1604 BlockBegin block = blockAt(i); |
1620 | 1605 |
1621 // check if block has only one predecessor and only one successor | 1606 // check if block has only one predecessor and only one successor |
1622 if (block.numberOfPreds() == 1 && block.numberOfSux() == 1 && block.numberOfExceptionHandlers() == 0 && !block.isExceptionEntry()) { | 1607 if (block.numberOfPreds() == 1 && block.numberOfSux() == 1) { |
1623 List<LIRInstruction> instructions = block.lir().instructionsList(); | 1608 List<LIRInstruction> instructions = block.lir().instructionsList(); |
1624 assert instructions.get(0).code == LIROpcode.Label : "block must start with label"; | 1609 assert instructions.get(0).code == LIROpcode.Label : "block must start with label"; |
1625 assert instructions.get(instructions.size() - 1).code == LIROpcode.Branch : "block with successors must end with branch"; | 1610 assert instructions.get(instructions.size() - 1).code == LIROpcode.Branch : "block with successors must end with branch"; |
1626 assert ((LIRBranch) instructions.get(instructions.size() - 1)).cond() == Condition.TRUE : "block with successor must end with unconditional branch"; | 1611 assert ((LIRBranch) instructions.get(instructions.size() - 1)).cond() == Condition.TRUE : "block with successor must end with unconditional branch"; |
1627 | 1612 |
1628 // check if block is empty (only label and branch) | 1613 // check if block is empty (only label and branch) |
1629 if (instructions.size() == 2) { | 1614 if (instructions.size() == 2) { |
1630 BlockBegin pred = block.predAt(0).begin(); | 1615 BlockBegin pred = block.predAt(0).block(); |
1631 BlockBegin sux = block.suxAt(0); | 1616 BlockBegin sux = block.suxAt(0); |
1632 | 1617 |
1633 // prevent optimization of two consecutive blocks | 1618 // prevent optimization of two consecutive blocks |
1634 if (!blockCompleted.get(pred.linearScanNumber()) && !blockCompleted.get(sux.linearScanNumber())) { | 1619 if (!blockCompleted.get(pred.linearScanNumber()) && !blockCompleted.get(sux.linearScanNumber())) { |
1635 if (C1XOptions.TraceLinearScanLevel >= 3) { | 1620 if (C1XOptions.TraceLinearScanLevel >= 3) { |
1669 if (moveResolver.hasMappings()) { | 1654 if (moveResolver.hasMappings()) { |
1670 resolveFindInsertPos(fromBlock, toBlock, moveResolver); | 1655 resolveFindInsertPos(fromBlock, toBlock, moveResolver); |
1671 moveResolver.resolveAndAppendMoves(); | 1656 moveResolver.resolveAndAppendMoves(); |
1672 } | 1657 } |
1673 } | 1658 } |
1674 } | |
1675 } | |
1676 } | |
1677 } | |
1678 | |
1679 void resolveExceptionEntry(BlockBegin block, CiValue operand, MoveResolver moveResolver) { | |
1680 if (intervalFor(operand) == null) { | |
1681 // if a phi function is never used, no interval is created . ignore this | |
1682 return; | |
1683 } | |
1684 | |
1685 Interval interval = intervalAtBlockBegin(block, operand); | |
1686 CiValue location = interval.location(); | |
1687 | |
1688 if (location.isRegister() && interval.alwaysInMemory()) { | |
1689 // the interval is split to get a short range that is located on the stack | |
1690 // in the following two cases: | |
1691 // * the interval started in memory (e.g. method parameter), but is currently in a register | |
1692 // this is an optimization for exception handling that reduces the number of moves that | |
1693 // are necessary for resolving the states when an exception uses this exception handler | |
1694 // * the interval would be on the fpu stack at the begin of the exception handler | |
1695 // this is not allowed because of the complicated fpu stack handling on Intel | |
1696 | |
1697 // range that will be spilled to memory | |
1698 int fromOpId = block.firstLirInstructionId(); | |
1699 int toOpId = fromOpId + 1; // short live range of length 1 | |
1700 assert interval.from() <= fromOpId && interval.to() >= toOpId : "no split allowed between exception entry and first instruction"; | |
1701 | |
1702 if (interval.from() != fromOpId) { | |
1703 // the part before fromOpId is unchanged | |
1704 interval = interval.split(fromOpId, this); | |
1705 interval.assignLocation(location); | |
1706 } | |
1707 assert interval.from() == fromOpId : "must be true now"; | |
1708 | |
1709 Interval spilledPart = interval; | |
1710 if (interval.to() != toOpId) { | |
1711 // the part after toOpId is unchanged | |
1712 spilledPart = interval.splitFromStart(toOpId, this); | |
1713 moveResolver.addMapping(spilledPart, interval); | |
1714 } | |
1715 assignSpillSlot(spilledPart); | |
1716 | |
1717 assert spilledPart.from() == fromOpId && spilledPart.to() == toOpId : "just checking"; | |
1718 } | |
1719 } | |
1720 | |
1721 void resolveExceptionEntry(final BlockBegin block, final MoveResolver moveResolver) { | |
1722 assert block.checkBlockFlag(BlockBegin.BlockFlag.ExceptionEntry) : "should not call otherwise"; | |
1723 assert moveResolver.checkEmpty(); | |
1724 | |
1725 // visit all registers where the liveIn bit is set | |
1726 for (int operandNum = block.lirBlock.liveIn.nextSetBit(0); operandNum >= 0; operandNum = block.lirBlock.liveIn.nextSetBit(operandNum + 1)) { | |
1727 resolveExceptionEntry(block, operands.operandFor(operandNum), moveResolver); | |
1728 } | |
1729 | |
1730 // the liveIn bits are not set for phi functions of the xhandler entry, so iterate them separately | |
1731 block.stateBefore().forEachLivePhi(block, new PhiProcedure() { | |
1732 public boolean doPhi(Phi phi) { | |
1733 resolveExceptionEntry(block, phi.operand(), moveResolver); | |
1734 return true; | |
1735 } | |
1736 }); | |
1737 | |
1738 if (moveResolver.hasMappings()) { | |
1739 // insert moves after first instruction | |
1740 moveResolver.setInsertPosition(block.lir(), 0); | |
1741 moveResolver.resolveAndAppendMoves(); | |
1742 } | |
1743 } | |
1744 | |
1745 void resolveExceptionEdge(ExceptionHandler handler, int throwingOpId, CiValue operand, Phi phi, MoveResolver moveResolver) { | |
1746 if (intervalFor(operand) == null) { | |
1747 // if a phi function is never used, no interval is created . ignore this | |
1748 return; | |
1749 } | |
1750 | |
1751 // the computation of toInterval is equal to resolveCollectMappings, | |
1752 // but fromInterval is more complicated because of phi functions | |
1753 BlockBegin toBlock = handler.entryBlock(); | |
1754 Interval toInterval = intervalAtBlockBegin(toBlock, operand); | |
1755 | |
1756 if (phi != null) { | |
1757 // phi function of the exception entry block | |
1758 // no moves are created for this phi function in the LIRGenerator, so the | |
1759 // interval at the throwing instruction must be searched using the operands | |
1760 // of the phi function | |
1761 Value fromValue = phi.inputAt(handler.phiOperand()); | |
1762 Constant con = null; | |
1763 if (fromValue instanceof Constant) { | |
1764 con = (Constant) fromValue; | |
1765 } | |
1766 if (con != null && (con.operand().isIllegal() || con.operand().isConstant())) { | |
1767 // unpinned constants may have no register, so add mapping from constant to interval | |
1768 moveResolver.addMapping(con.asConstant(), toInterval); | |
1769 } else { | |
1770 // search split child at the throwing opId | |
1771 Interval fromInterval = intervalAtOpId(fromValue.operand(), throwingOpId); | |
1772 if (fromInterval != toInterval) { | |
1773 moveResolver.addMapping(fromInterval, toInterval); | |
1774 // with phi functions it can happen that the same fromValue is used in | |
1775 // multiple mappings, so notify move-resolver that this is allowed | |
1776 moveResolver.setMultipleReadsAllowed(); | |
1777 } | |
1778 } | |
1779 } else { | |
1780 // no phi function, so use regNum also for fromInterval | |
1781 // search split child at the throwing opId | |
1782 Interval fromInterval = intervalAtOpId(operand, throwingOpId); | |
1783 if (fromInterval != toInterval) { | |
1784 // optimization to reduce number of moves: when toInterval is on stack and | |
1785 // the stack slot is known to be always correct, then no move is necessary | |
1786 if (!fromInterval.alwaysInMemory() || fromInterval.spillSlot() != toInterval.location()) { | |
1787 moveResolver.addMapping(fromInterval, toInterval); | |
1788 } | |
1789 } | |
1790 } | |
1791 } | |
1792 | |
1793 void resolveExceptionEdge(final ExceptionHandler handler, final int throwingOpId, final MoveResolver moveResolver) { | |
1794 if (C1XOptions.TraceLinearScanLevel >= 4) { | |
1795 TTY.println("resolving exception handler B%d: throwingOpId=%d", handler.entryBlock().blockID, throwingOpId); | |
1796 } | |
1797 | |
1798 assert moveResolver.checkEmpty(); | |
1799 assert handler.lirOpId() == -1 : "already processed this xhandler"; | |
1800 handler.setLirOpId(throwingOpId); | |
1801 assert handler.entryCode() == null : "code already present"; | |
1802 | |
1803 // visit all registers where the liveIn bit is set | |
1804 BlockBegin block = handler.entryBlock(); | |
1805 for (int operandNum = block.lirBlock.liveIn.nextSetBit(0); operandNum >= 0; operandNum = block.lirBlock.liveIn.nextSetBit(operandNum + 1)) { | |
1806 resolveExceptionEdge(handler, throwingOpId, operands.operandFor(operandNum), null, moveResolver); | |
1807 } | |
1808 | |
1809 // the liveIn bits are not set for phi functions of the xhandler entry, so iterate them separately | |
1810 block.stateBefore().forEachLivePhi(block, new PhiProcedure() { | |
1811 public boolean doPhi(Phi phi) { | |
1812 resolveExceptionEdge(handler, throwingOpId, phi.operand(), phi, moveResolver); | |
1813 return true; | |
1814 } | |
1815 }); | |
1816 | |
1817 if (moveResolver.hasMappings()) { | |
1818 LIRList entryCode = new LIRList(gen); | |
1819 moveResolver.setInsertPosition(entryCode, 0); | |
1820 moveResolver.resolveAndAppendMoves(); | |
1821 | |
1822 entryCode.jump(handler.entryBlock()); | |
1823 handler.setEntryCode(entryCode); | |
1824 } | |
1825 } | |
1826 | |
1827 void resolveExceptionHandlers() { | |
1828 MoveResolver moveResolver = new MoveResolver(this); | |
1829 //LIRVisitState visitor = new LIRVisitState(); | |
1830 int numBlocks = blockCount(); | |
1831 | |
1832 int i; | |
1833 for (i = 0; i < numBlocks; i++) { | |
1834 BlockBegin block = blockAt(i); | |
1835 if (block.checkBlockFlag(BlockFlag.ExceptionEntry)) { | |
1836 resolveExceptionEntry(block, moveResolver); | |
1837 } | |
1838 } | |
1839 | |
1840 for (i = 0; i < numBlocks; i++) { | |
1841 BlockBegin block = blockAt(i); | |
1842 LIRList ops = block.lir(); | |
1843 int numOps = ops.length(); | |
1844 | |
1845 // iterate all instructions of the block. skip the first because it is always a label | |
1846 assert !ops.at(0).hasOperands() : "first operation must always be a label"; | |
1847 for (int j = 1; j < numOps; j++) { | |
1848 LIRInstruction op = ops.at(j); | |
1849 int opId = op.id; | |
1850 | |
1851 if (opId != -1 && op.info != null) { | |
1852 // visit operation to collect all operands | |
1853 for (ExceptionHandler handler : op.exceptionEdges()) { | |
1854 resolveExceptionEdge(handler, opId, moveResolver); | |
1855 } | |
1856 | |
1857 } else if (C1XOptions.DetailedAsserts) { | |
1858 assert op.exceptionEdges().size() == 0 : "missed exception handler"; | |
1859 } | 1659 } |
1860 } | 1660 } |
1861 } | 1661 } |
1862 } | 1662 } |
1863 | 1663 |
2170 } | 1970 } |
2171 } | 1971 } |
2172 | 1972 |
2173 if (op.info != null) { | 1973 if (op.info != null) { |
2174 // exception handling | 1974 // exception handling |
2175 if (compilation.hasExceptionHandlers()) { | 1975 // if (compilation.hasExceptionHandlers()) { |
2176 for (ExceptionHandler handler : op.exceptionEdges()) { | 1976 // if (op.exceptionEdge() != null && op.exceptionEdge().lir() != null) { |
2177 if (handler.entryCode() != null) { | 1977 // assignLocations(op.exceptionEdge().lir().instructionsList(), iw); |
2178 assignLocations(handler.entryCode().instructionsList(), null); | 1978 // } |
2179 } | 1979 // } |
2180 } | |
2181 } | |
2182 | 1980 |
2183 // compute reference map and debug information | 1981 // compute reference map and debug information |
2184 computeDebugInfo(iw, op); | 1982 computeDebugInfo(iw, op); |
2185 } | 1983 } |
2186 | 1984 |
2250 C1XTimers.LINEAR_SCAN.stop(); | 2048 C1XTimers.LINEAR_SCAN.stop(); |
2251 C1XTimers.RESOLUTION.start(); | 2049 C1XTimers.RESOLUTION.start(); |
2252 } | 2050 } |
2253 | 2051 |
2254 resolveDataFlow(); | 2052 resolveDataFlow(); |
2255 if (compilation.hasExceptionHandlers()) { | |
2256 resolveExceptionHandlers(); | |
2257 } | |
2258 | 2053 |
2259 if (C1XOptions.PrintTimers) { | 2054 if (C1XOptions.PrintTimers) { |
2260 C1XTimers.RESOLUTION.stop(); | 2055 C1XTimers.RESOLUTION.stop(); |
2261 C1XTimers.DEBUG_INFO.start(); | 2056 C1XTimers.DEBUG_INFO.start(); |
2262 } | 2057 } |