in src/main/java/com/amazon/corretto/hotpatch/org/objectweb/asm/MethodWriter.java [1660:1764]
private void computeMaxStackAndLocal() {
// Complete the control flow graph with exception handler blocks.
Handler handler = firstHandler;
while (handler != null) {
Label handlerBlock = handler.handlerPc;
Label handlerRangeBlock = handler.startPc;
Label handlerRangeEnd = handler.endPc;
// Add handlerBlock as a successor of all the basic blocks in the exception handler range.
while (handlerRangeBlock != handlerRangeEnd) {
if ((handlerRangeBlock.flags & Label.FLAG_SUBROUTINE_CALLER) == 0) {
handlerRangeBlock.outgoingEdges =
new Edge(Edge.EXCEPTION, handlerBlock, handlerRangeBlock.outgoingEdges);
} else {
// If handlerRangeBlock is a JSR block, add handlerBlock after the first two outgoing
// edges to preserve the hypothesis about JSR block successors order (see
// {@link #visitJumpInsn}).
handlerRangeBlock.outgoingEdges.nextEdge.nextEdge =
new Edge(
Edge.EXCEPTION, handlerBlock, handlerRangeBlock.outgoingEdges.nextEdge.nextEdge);
}
handlerRangeBlock = handlerRangeBlock.nextBasicBlock;
}
handler = handler.nextHandler;
}
// Complete the control flow graph with the successor blocks of subroutines, if needed.
if (hasSubroutines) {
// First step: find the subroutines. This step determines, for each basic block, to which
// subroutine(s) it belongs. Start with the main "subroutine":
short numSubroutines = 1;
firstBasicBlock.markSubroutine(numSubroutines);
// Then, mark the subroutines called by the main subroutine, then the subroutines called by
// those called by the main subroutine, etc.
for (short currentSubroutine = 1; currentSubroutine <= numSubroutines; ++currentSubroutine) {
Label basicBlock = firstBasicBlock;
while (basicBlock != null) {
if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0
&& basicBlock.subroutineId == currentSubroutine) {
Label jsrTarget = basicBlock.outgoingEdges.nextEdge.successor;
if (jsrTarget.subroutineId == 0) {
// If this subroutine has not been marked yet, find its basic blocks.
jsrTarget.markSubroutine(++numSubroutines);
}
}
basicBlock = basicBlock.nextBasicBlock;
}
}
// Second step: find the successors in the control flow graph of each subroutine basic block
// 'r' ending with a RET instruction. These successors are the virtual successors of the basic
// blocks ending with JSR instructions (see {@link #visitJumpInsn)} that can reach 'r'.
Label basicBlock = firstBasicBlock;
while (basicBlock != null) {
if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) {
// By construction, jsr targets are stored in the second outgoing edge of basic blocks
// that ends with a jsr instruction (see {@link #FLAG_SUBROUTINE_CALLER}).
Label subroutine = basicBlock.outgoingEdges.nextEdge.successor;
subroutine.addSubroutineRetSuccessors(basicBlock);
}
basicBlock = basicBlock.nextBasicBlock;
}
}
// Data flow algorithm: put the first basic block in a list of blocks to process (i.e. blocks
// whose input stack size has changed) and, while there are blocks to process, remove one
// from the list, update the input stack size of its successor blocks in the control flow
// graph, and add these blocks to the list of blocks to process (if not already done).
Label listOfBlocksToProcess = firstBasicBlock;
listOfBlocksToProcess.nextListElement = Label.EMPTY_LIST;
int maxStackSize = maxStack;
while (listOfBlocksToProcess != Label.EMPTY_LIST) {
// Remove a basic block from the list of blocks to process. Note that we don't reset
// basicBlock.nextListElement to null on purpose, to make sure we don't reprocess already
// processed basic blocks.
Label basicBlock = listOfBlocksToProcess;
listOfBlocksToProcess = listOfBlocksToProcess.nextListElement;
// Compute the (absolute) input stack size and maximum stack size of this block.
int inputStackTop = basicBlock.inputStackSize;
int maxBlockStackSize = inputStackTop + basicBlock.outputStackMax;
// Update the absolute maximum stack size of the method.
if (maxBlockStackSize > maxStackSize) {
maxStackSize = maxBlockStackSize;
}
// Update the input stack size of the successor blocks of basicBlock in the control flow
// graph, and add these blocks to the list of blocks to process, if not already done.
Edge outgoingEdge = basicBlock.outgoingEdges;
if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) {
// Ignore the first outgoing edge of the basic blocks ending with a jsr: these are virtual
// edges which lead to the instruction just after the jsr, and do not correspond to a
// possible execution path (see {@link #visitJumpInsn} and
// {@link Label#FLAG_SUBROUTINE_CALLER}).
outgoingEdge = outgoingEdge.nextEdge;
}
while (outgoingEdge != null) {
Label successorBlock = outgoingEdge.successor;
if (successorBlock.nextListElement == null) {
successorBlock.inputStackSize =
(short) (outgoingEdge.info == Edge.EXCEPTION ? 1 : inputStackTop + outgoingEdge.info);
successorBlock.nextListElement = listOfBlocksToProcess;
listOfBlocksToProcess = successorBlock;
}
outgoingEdge = outgoingEdge.nextEdge;
}
}
this.maxStack = maxStackSize;
}