void (@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; } 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); } } }