void (ControlFlowGraph graph, int bytecode_version) { 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; } for (ExceptionRangeCFG range : ranges) { // add some dummy instructions to prevent optimizing away the empty block SimpleInstructionSequence seq = new SimpleInstructionSequence(); seq.addInstruction(Instruction.create(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{0}), -1); seq.addInstruction(Instruction.create(CodeConstants.opc_pop, false, CodeConstants.GROUP_GENERAL, bytecode_version, null), -1); BasicBlock dummyBlock = new BasicBlock(++graph.last_id, seq); graph.getBlocks().addWithKey(dummyBlock, dummyBlock.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, dummyBlock); if (previousEdge != null) { previousEdge.setHandler(dummyBlock); } } // replace handler range.setHandler(dummyBlock); // add common exception edges Set<BasicBlock> commonHandlers = new HashSet<>(handler.getSuccessorExceptions()); for (BasicBlock pred : lstPredExceptions) { commonHandlers.retainAll(pred.getSuccessorExceptions()); } // TODO: more sanity checks? for (BasicBlock commonHandler : commonHandlers) { ExceptionRangeCFG commonRange = graph.getExceptionRange(commonHandler, handler); dummyBlock.addSuccessorException(commonHandler); commonRange.getProtectedRange().add(dummyBlock); } dummyBlock.addSuccessor(handler); } } }