in src/main/java/org/apache/bcel/generic/MethodGen.java [139:204]
public static int getMaxStack(final ConstantPoolGen cp, final InstructionList il, final CodeExceptionGen[] et) {
final BranchStack branchTargets = new BranchStack();
/*
* Initially, populate the branch stack with the exception handlers, because these aren't (necessarily) branched to
* explicitly. in each case, the stack will have depth 1, containing the exception object.
*/
for (final CodeExceptionGen element : et) {
final InstructionHandle handlerPc = element.getHandlerPC();
if (handlerPc != null) {
branchTargets.push(handlerPc, 1);
}
}
int stackDepth = 0;
int maxStackDepth = 0;
InstructionHandle ih = il.getStart();
while (ih != null) {
final Instruction instruction = ih.getInstruction();
final short opcode = instruction.getOpcode();
final int delta = instruction.produceStack(cp) - instruction.consumeStack(cp);
stackDepth += delta;
if (stackDepth > maxStackDepth) {
maxStackDepth = stackDepth;
}
// choose the next instruction based on whether current is a branch.
if (instruction instanceof BranchInstruction) {
final BranchInstruction branch = (BranchInstruction) instruction;
if (instruction instanceof Select) {
// explore all of the select's targets. the default target is handled below.
final Select select = (Select) branch;
final InstructionHandle[] targets = select.getTargets();
for (final InstructionHandle target : targets) {
branchTargets.push(target, stackDepth);
}
// nothing to fall through to.
ih = null;
} else if (!(branch instanceof IfInstruction)) {
// if an instruction that comes back to following PC,
// push next instruction, with stack depth reduced by 1.
if (opcode == Const.JSR || opcode == Const.JSR_W) {
branchTargets.push(ih.getNext(), stackDepth - 1);
}
ih = null;
}
// for all branches, the target of the branch is pushed on the branch stack.
// conditional branches have a fall through case, selects don't, and
// jsr/jsr_w return to the next instruction.
branchTargets.push(branch.getTarget(), stackDepth);
} else // check for instructions that terminate the method.
if (opcode == Const.ATHROW || opcode == Const.RET || opcode >= Const.IRETURN && opcode <= Const.RETURN) {
ih = null;
}
// normal case, go to the next instruction.
if (ih != null) {
ih = ih.getNext();
}
// if we have no more instructions, see if there are any deferred branches to explore.
if (ih == null) {
final BranchTarget bt = branchTargets.pop();
if (bt != null) {
ih = bt.target;
stackDepth = bt.stackDepth;
}
}
}
return maxStackDepth;
}