in src/main/java/com/amazon/corretto/hotpatch/org/objectweb/asm/MethodWriter.java [1558:1657]
private void computeAllFrames() {
// Complete the control flow graph with exception handler blocks.
Handler handler = firstHandler;
while (handler != null) {
String catchTypeDescriptor =
handler.catchTypeDescriptor == null ? "java/lang/Throwable" : handler.catchTypeDescriptor;
int catchType = Frame.getAbstractTypeFromInternalName(symbolTable, catchTypeDescriptor);
// Mark handlerBlock as an exception handler.
Label handlerBlock = handler.handlerPc.getCanonicalInstance();
handlerBlock.flags |= Label.FLAG_JUMP_TARGET;
// Add handlerBlock as a successor of all the basic blocks in the exception handler range.
Label handlerRangeBlock = handler.startPc.getCanonicalInstance();
Label handlerRangeEnd = handler.endPc.getCanonicalInstance();
while (handlerRangeBlock != handlerRangeEnd) {
handlerRangeBlock.outgoingEdges =
new Edge(catchType, handlerBlock, handlerRangeBlock.outgoingEdges);
handlerRangeBlock = handlerRangeBlock.nextBasicBlock;
}
handler = handler.nextHandler;
}
// Create and visit the first (implicit) frame.
Frame firstFrame = firstBasicBlock.frame;
firstFrame.setInputFrameFromDescriptor(symbolTable, accessFlags, descriptor, this.maxLocals);
firstFrame.accept(this);
// Fix point algorithm: add the first basic block to a list of blocks to process (i.e. blocks
// whose stack map frame has changed) and, while there are blocks to process, remove one from
// the list and update the stack map frames of its successor blocks in the control flow graph
// (which might change them, in which case these blocks must be processed too, and are thus
// added to the list of blocks to process). Also compute the maximum stack size of the method,
// as a by-product.
Label listOfBlocksToProcess = firstBasicBlock;
listOfBlocksToProcess.nextListElement = Label.EMPTY_LIST;
int maxStackSize = 0;
while (listOfBlocksToProcess != Label.EMPTY_LIST) {
// Remove a basic block from the list of blocks to process.
Label basicBlock = listOfBlocksToProcess;
listOfBlocksToProcess = listOfBlocksToProcess.nextListElement;
basicBlock.nextListElement = null;
// By definition, basicBlock is reachable.
basicBlock.flags |= Label.FLAG_REACHABLE;
// Update the (absolute) maximum stack size.
int maxBlockStackSize = basicBlock.frame.getInputStackSize() + basicBlock.outputStackMax;
if (maxBlockStackSize > maxStackSize) {
maxStackSize = maxBlockStackSize;
}
// Update the successor blocks of basicBlock in the control flow graph.
Edge outgoingEdge = basicBlock.outgoingEdges;
while (outgoingEdge != null) {
Label successorBlock = outgoingEdge.successor.getCanonicalInstance();
boolean successorBlockChanged =
basicBlock.frame.merge(symbolTable, successorBlock.frame, outgoingEdge.info);
if (successorBlockChanged && successorBlock.nextListElement == null) {
// If successorBlock has changed it must be processed. Thus, if it is not already in the
// list of blocks to process, add it to this list.
successorBlock.nextListElement = listOfBlocksToProcess;
listOfBlocksToProcess = successorBlock;
}
outgoingEdge = outgoingEdge.nextEdge;
}
}
// Loop over all the basic blocks and visit the stack map frames that must be stored in the
// StackMapTable attribute. Also replace unreachable code with NOP* ATHROW, and remove it from
// exception handler ranges.
Label basicBlock = firstBasicBlock;
while (basicBlock != null) {
if ((basicBlock.flags & (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE))
== (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE)) {
basicBlock.frame.accept(this);
}
if ((basicBlock.flags & Label.FLAG_REACHABLE) == 0) {
// Find the start and end bytecode offsets of this unreachable block.
Label nextBasicBlock = basicBlock.nextBasicBlock;
int startOffset = basicBlock.bytecodeOffset;
int endOffset = (nextBasicBlock == null ? code.length : nextBasicBlock.bytecodeOffset) - 1;
if (endOffset >= startOffset) {
// Replace its instructions with NOP ... NOP ATHROW.
for (int i = startOffset; i < endOffset; ++i) {
code.data[i] = Opcodes.NOP;
}
code.data[endOffset] = (byte) Opcodes.ATHROW;
// Emit a frame for this unreachable block, with no local and a Throwable on the stack
// (so that the ATHROW could consume this Throwable if it were reachable).
int frameIndex = visitFrameStart(startOffset, /* numLocal = */ 0, /* numStack = */ 1);
currentFrame[frameIndex] =
Frame.getAbstractTypeFromInternalName(symbolTable, "java/lang/Throwable");
visitFrameEnd();
// Remove this unreachable basic block from the exception handler ranges.
firstHandler = Handler.removeRange(firstHandler, basicBlock, nextBasicBlock);
// The maximum stack size is now at least one, because of the Throwable declared above.
maxStackSize = Math.max(maxStackSize, 1);
}
}
basicBlock = basicBlock.nextBasicBlock;
}
this.maxStack = maxStackSize;
}