in src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/ExceptionDeobfuscator.java [407:500]
public static void duplicateMergedMatchedExceptionCatchBlocks(@NotNull ControlFlowGraph graph, @NotNull StructClass cl) {
if (!cl.hasRecordPatternSupport()) {
return;
}
Map<BasicBlock, Set<ExceptionRangeCFG>> mapRanges = new HashMap<>();
for (ExceptionRangeCFG range : graph.getExceptions()) {
mapRanges.computeIfAbsent(range.getHandler(), k -> new HashSet<>()).add(range);
}
for (Entry<BasicBlock, Set<ExceptionRangeCFG>> ent : mapRanges.entrySet()) {
BasicBlock handler = ent.getKey();
Set<ExceptionRangeCFG> ranges = ent.getValue();
if (ranges.size() == 1) {
continue;
}
if (handler.getLastInstruction().opcode != CodeConstants.opc_athrow) {
continue;
}
InstructionSequence seq = handler.getSeq();
boolean found = false;
for (int i = 0; i < seq.length(); i++) {
Instruction instr = seq.getInstr(i);
if (instr.opcode == CodeConstants.opc_new && instr.operandsCount() >= 1) {
if (found) {
found = false;
break;
}
PooledConstant constant = cl.getPool().getConstant(instr.operand(0));
if (constant instanceof PrimitiveConstant primitiveConstant &&
"java/lang/MatchException".equals(primitiveConstant.value)) {
found = true;
}
}
}
if (!found) {
continue;
}
Set<String> exceptions = ranges.stream()
.map(t -> t.getExceptionTypes())
.flatMap(t -> t != null ? t.stream() : Stream.empty())
.collect(Collectors.toSet());
List<BasicBlock> successors = handler.getSuccessors();
if (successors != null && successors.size() == 1 && successors.get(0).getSuccessors().isEmpty() &&
successors.get(0).getSuccessorExceptions().isEmpty() &&
//exceptions contain only one type of exceptions, and it is not null, because null defines `finally` blocks
exceptions.size() == 1 && !exceptions.contains(null)) {
for (ExceptionRangeCFG range : ranges) {
BasicBlock newHandler = handler.clone(++graph.last_id);
graph.getBlocks().addWithKey(newHandler, newHandler.id);
// only exception predecessors from this range considered
List<BasicBlock> lstPredExceptions = new ArrayList<>(handler.getPredecessorExceptions());
lstPredExceptions.retainAll(range.getProtectedRange());
// replace predecessors
for (BasicBlock pred : lstPredExceptions) {
ExceptionRangeCFG previousEdge = graph.getExceptionRange(handler, pred);
pred.replaceSuccessor(handler, newHandler);
if (previousEdge != null) {
previousEdge.setHandler(newHandler);
}
}
// replace successors
List<BasicBlock> scExceptions = new ArrayList<>(handler.getSuccessorExceptions());
for (BasicBlock nextException : scExceptions) {
ExceptionRangeCFG nextEdge = graph.getExceptionRange(nextException, handler);
newHandler.addSuccessorException(nextException);
nextEdge.getProtectedRange().add(newHandler);
}
//add fast exit
newHandler.addSuccessor(successors.get(0));
for (BasicBlock successorException : handler.getSuccessorExceptions()) {
newHandler.addSuccessorException(successorException);
ExceptionRangeCFG previousEdge = graph.getExceptionRange(successorException, handler);
if (previousEdge != null) {
ArrayList<BasicBlock> newRanges = new ArrayList<>();
newRanges.add(newHandler);
ExceptionRangeCFG subRange = new ExceptionRangeCFG(newRanges, successorException, previousEdge.getExceptionTypes());
graph.getExceptions().add(subRange);
successorException.addPredecessorException(newHandler);
}
}
range.setHandler(newHandler);
}
for (BasicBlock successorException : handler.getSuccessorExceptions()) {
successorException.removePredecessorException(handler);
if (successorException.getPredecessorExceptions().isEmpty()) {
graph.removeBlock(successorException);
}
}
graph.removeBlock(handler);
}
}
}