in asm-analysis/src/main/java/org/objectweb/asm/tree/analysis/Analyzer.java [405:474]
private void findSubroutine(
final int insnIndex, final Subroutine subroutine, final List<AbstractInsnNode> jsrInsns)
throws AnalyzerException {
ArrayList<Integer> instructionIndicesToProcess = new ArrayList<>();
instructionIndicesToProcess.add(insnIndex);
while (!instructionIndicesToProcess.isEmpty()) {
int currentInsnIndex =
instructionIndicesToProcess.remove(instructionIndicesToProcess.size() - 1);
if (currentInsnIndex < 0 || currentInsnIndex >= insnListSize) {
throw new AnalyzerException(null, "Execution can fall off the end of the code");
}
if (subroutines[currentInsnIndex] != null) {
continue;
}
subroutines[currentInsnIndex] = new Subroutine(subroutine);
AbstractInsnNode currentInsn = insnList.get(currentInsnIndex);
// Push the normal successors of currentInsn onto instructionIndicesToProcess.
if (currentInsn instanceof JumpInsnNode) {
if (currentInsn.getOpcode() == JSR) {
// Do not follow a jsr, it leads to another subroutine!
jsrInsns.add(currentInsn);
} else {
JumpInsnNode jumpInsn = (JumpInsnNode) currentInsn;
instructionIndicesToProcess.add(insnList.indexOf(jumpInsn.label));
}
} else if (currentInsn instanceof TableSwitchInsnNode) {
TableSwitchInsnNode tableSwitchInsn = (TableSwitchInsnNode) currentInsn;
findSubroutine(insnList.indexOf(tableSwitchInsn.dflt), subroutine, jsrInsns);
for (int i = tableSwitchInsn.labels.size() - 1; i >= 0; --i) {
LabelNode labelNode = tableSwitchInsn.labels.get(i);
instructionIndicesToProcess.add(insnList.indexOf(labelNode));
}
} else if (currentInsn instanceof LookupSwitchInsnNode) {
LookupSwitchInsnNode lookupSwitchInsn = (LookupSwitchInsnNode) currentInsn;
findSubroutine(insnList.indexOf(lookupSwitchInsn.dflt), subroutine, jsrInsns);
for (int i = lookupSwitchInsn.labels.size() - 1; i >= 0; --i) {
LabelNode labelNode = lookupSwitchInsn.labels.get(i);
instructionIndicesToProcess.add(insnList.indexOf(labelNode));
}
}
// Push the exception handler successors of currentInsn onto instructionIndicesToProcess.
List<TryCatchBlockNode> insnHandlers = handlers[currentInsnIndex];
if (insnHandlers != null) {
for (TryCatchBlockNode tryCatchBlock : insnHandlers) {
instructionIndicesToProcess.add(insnList.indexOf(tryCatchBlock.handler));
}
}
// Push the next instruction, if the control flow can go from currentInsn to the next.
switch (currentInsn.getOpcode()) {
case GOTO:
case RET:
case TABLESWITCH:
case LOOKUPSWITCH:
case IRETURN:
case LRETURN:
case FRETURN:
case DRETURN:
case ARETURN:
case RETURN:
case ATHROW:
break;
default:
instructionIndicesToProcess.add(currentInsnIndex + 1);
break;
}
}
}