Computes the maximum stack size of the method.
()
| 1652 | |
| 1653 | /** Computes the maximum stack size of the method. */ |
| 1654 | private void computeMaxStackAndLocal() { |
| 1655 | // Complete the control flow graph with exception handler blocks. |
| 1656 | Handler handler = firstHandler; |
| 1657 | while (handler != null) { |
| 1658 | Label handlerBlock = handler.handlerPc; |
| 1659 | Label handlerRangeBlock = handler.startPc; |
| 1660 | Label handlerRangeEnd = handler.endPc; |
| 1661 | // Add handlerBlock as a successor of all the basic blocks in the exception handler range. |
| 1662 | while (handlerRangeBlock != handlerRangeEnd) { |
| 1663 | if ((handlerRangeBlock.flags & Label.FLAG_SUBROUTINE_CALLER) == 0) { |
| 1664 | handlerRangeBlock.outgoingEdges = |
| 1665 | new Edge(Edge.EXCEPTION, handlerBlock, handlerRangeBlock.outgoingEdges); |
| 1666 | } else { |
| 1667 | // If handlerRangeBlock is a JSR block, add handlerBlock after the first two outgoing |
| 1668 | // edges to preserve the hypothesis about JSR block successors order (see |
| 1669 | // {@link #visitJumpInsn}). |
| 1670 | handlerRangeBlock.outgoingEdges.nextEdge.nextEdge = |
| 1671 | new Edge( |
| 1672 | Edge.EXCEPTION, handlerBlock, handlerRangeBlock.outgoingEdges.nextEdge.nextEdge); |
| 1673 | } |
| 1674 | handlerRangeBlock = handlerRangeBlock.nextBasicBlock; |
| 1675 | } |
| 1676 | handler = handler.nextHandler; |
| 1677 | } |
| 1678 | |
| 1679 | // Complete the control flow graph with the successor blocks of subroutines, if needed. |
| 1680 | if (hasSubroutines) { |
| 1681 | // First step: find the subroutines. This step determines, for each basic block, to which |
| 1682 | // subroutine(s) it belongs. Start with the main "subroutine": |
| 1683 | short numSubroutines = 1; |
| 1684 | firstBasicBlock.markSubroutine(numSubroutines); |
| 1685 | // Then, mark the subroutines called by the main subroutine, then the subroutines called by |
| 1686 | // those called by the main subroutine, etc. |
| 1687 | for (short currentSubroutine = 1; currentSubroutine <= numSubroutines; ++currentSubroutine) { |
| 1688 | Label basicBlock = firstBasicBlock; |
| 1689 | while (basicBlock != null) { |
| 1690 | if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0 |
| 1691 | && basicBlock.subroutineId == currentSubroutine) { |
| 1692 | Label jsrTarget = basicBlock.outgoingEdges.nextEdge.successor; |
| 1693 | if (jsrTarget.subroutineId == 0) { |
| 1694 | // If this subroutine has not been marked yet, find its basic blocks. |
| 1695 | jsrTarget.markSubroutine(++numSubroutines); |
| 1696 | } |
| 1697 | } |
| 1698 | basicBlock = basicBlock.nextBasicBlock; |
| 1699 | } |
| 1700 | } |
| 1701 | // Second step: find the successors in the control flow graph of each subroutine basic block |
| 1702 | // 'r' ending with a RET instruction. These successors are the virtual successors of the basic |
| 1703 | // blocks ending with JSR instructions (see {@link #visitJumpInsn)} that can reach 'r'. |
| 1704 | Label basicBlock = firstBasicBlock; |
| 1705 | while (basicBlock != null) { |
| 1706 | if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) { |
| 1707 | // By construction, jsr targets are stored in the second outgoing edge of basic blocks |
| 1708 | // that ends with a jsr instruction (see {@link #FLAG_SUBROUTINE_CALLER}). |
| 1709 | Label subroutine = basicBlock.outgoingEdges.nextEdge.successor; |
| 1710 | subroutine.addSubroutineRetSuccessors(basicBlock); |
| 1711 | } |
no test coverage detected