in src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java [504:622]
private Area compareSubGraphsEx(ControlFlowGraph graph,
BasicBlock startSample,
Set<BasicBlock> catchBlocks,
BasicBlock startCatch,
int finallyType,
Map<BasicBlock, Boolean> mapLast,
boolean skippedFirst) {
class BlockStackEntry {
public final BasicBlock blockCatch;
public final BasicBlock blockSample;
// TODO: correct handling (merging) of multiple paths
public final List<int[]> lstStoreVars;
BlockStackEntry(BasicBlock blockCatch, BasicBlock blockSample, List<int[]> lstStoreVars) {
this.blockCatch = blockCatch;
this.blockSample = blockSample;
this.lstStoreVars = new ArrayList<>(lstStoreVars);
}
}
List<BlockStackEntry> stack = new LinkedList<>();
Set<BasicBlock> setSample = new HashSet<>();
Map<String, BasicBlock[]> mapNext = new HashMap<>();
stack.add(new BlockStackEntry(startCatch, startSample, new ArrayList<>()));
while (!stack.isEmpty()) {
BlockStackEntry entry = stack.remove(0);
BasicBlock blockCatch = entry.blockCatch;
BasicBlock blockSample = entry.blockSample;
boolean isFirstBlock = !skippedFirst && blockCatch == startCatch;
boolean isLastBlock = mapLast.containsKey(blockCatch);
boolean isTrueLastBlock = isLastBlock && mapLast.get(blockCatch);
int compareType = (isFirstBlock ? 1 : 0) | (isTrueLastBlock ? 2 : 0);
if (!compareBasicBlocksEx(graph, blockCatch, blockSample, compareType, finallyType, entry.lstStoreVars)) {
return null;
}
if (blockSample.getSuccessors().size() != blockCatch.getSuccessors().size()) {
return null;
}
setSample.add(blockSample);
// direct successors
for (int i = 0; i < blockCatch.getSuccessors().size(); i++) {
BasicBlock sucCatch = blockCatch.getSuccessors().get(i);
BasicBlock sucSample = blockSample.getSuccessors().get(i);
if (catchBlocks.contains(sucCatch) && !setSample.contains(sucSample)) {
stack.add(new BlockStackEntry(sucCatch, sucSample, entry.lstStoreVars));
}
}
// exception successors
if (isLastBlock && blockSample.getSeq().isEmpty()) {
// do nothing, blockSample will be removed anyway
}
else {
if (blockCatch.getSuccessorExceptions().size() == blockSample.getSuccessorExceptions().size()) {
for (int i = 0; i < blockCatch.getSuccessorExceptions().size(); i++) {
BasicBlock sucCatch = blockCatch.getSuccessorExceptions().get(i);
BasicBlock sucSample = blockSample.getSuccessorExceptions().get(i);
String excCatch = graph.getExceptionRange(sucCatch, blockCatch).getUniqueExceptionsString();
String excSample = graph.getExceptionRange(sucSample, blockSample).getUniqueExceptionsString();
// FIXME: compare handlers if possible
if (Objects.equals(excCatch, excSample)) {
if (catchBlocks.contains(sucCatch) && !setSample.contains(sucSample)) {
List<int[]> lst = entry.lstStoreVars;
if (!sucCatch.getSeq().isEmpty() && !sucSample.getSeq().isEmpty()) {
Instruction instrCatch = sucCatch.getSeq().getInstr(0);
Instruction instrSample = sucSample.getSeq().getInstr(0);
if (instrCatch.opcode == CodeConstants.opc_astore &&
instrSample.opcode == CodeConstants.opc_astore) {
lst = new ArrayList<>(lst);
lst.add(new int[]{instrCatch.operand(0), instrSample.operand(0)});
}
}
stack.add(new BlockStackEntry(sucCatch, sucSample, lst));
}
}
else {
return null;
}
}
}
else {
return null;
}
}
if (isLastBlock) {
Set<BasicBlock> successors = new HashSet<>(blockSample.getSuccessors());
successors.removeAll(setSample);
for (BlockStackEntry stackEntry : stack) {
successors.remove(stackEntry.blockSample);
}
for (BasicBlock successor : successors) {
if (graph.getLast() != successor) { // FIXME: why?
mapNext.put(blockSample.id + "#" + successor.id, new BasicBlock[]{blockSample, successor, isTrueLastBlock ? successor : null});
}
}
}
}
return new Area(startSample, setSample, getUniqueNext(graph, new HashSet<>(mapNext.values())));
}