void (ControlFlowGraph graph) { while(true) { boolean rangeExtended = false; for (ExceptionRangeCFG range : graph.getExceptions()) { Set<BasicBlock> predecessors = new HashSet<>(); for (BasicBlock block : range.getProtectedRange()) { predecessors.addAll(block.getPredecessors()); } for (BasicBlock basicBlock : range.getProtectedRange()) { predecessors.remove(basicBlock); } if (predecessors.size() != 1) { continue; // multiple predecessors -> obfuscated range } BasicBlock predecessor = predecessors.iterator().next(); InstructionSequence predecessorSeq = predecessor.getSeq(); if (predecessorSeq.isEmpty() || predecessorSeq.getLastInstr().opcode != CodeConstants.opc_monitorenter) { continue; // not a synchronized range } boolean monitorExitInRange = false; Set<BasicBlock> setProtectedBlocks = new HashSet<>(range.getProtectedRange()); setProtectedBlocks.add(range.getHandler()); for (BasicBlock block : setProtectedBlocks) { InstructionSequence blockSeq = block.getSeq(); for (int i = 0; i < blockSeq.length(); i++) { if (blockSeq.getInstr(i).opcode == CodeConstants.opc_monitorexit) { monitorExitInRange = true; break; } } if (monitorExitInRange) { break; } } if (monitorExitInRange) { continue; // the protected range already contains MonitorExit } Set<BasicBlock> successors = new HashSet<>(); for (BasicBlock block : range.getProtectedRange()) { successors.addAll(block.getSuccessors()); } for (BasicBlock basicBlock : range.getProtectedRange()) { successors.remove(basicBlock); } if (successors.size() != 1) { continue; // non-unique successor } BasicBlock successor = successors.iterator().next(); InstructionSequence successorSeq = successor.getSeq(); int successorMonitorExitIndex = findMonitorExitIndex(successorSeq); if (successorMonitorExitIndex < 0) { continue; // no MonitorExit found in the single successor block } BasicBlock handlerBlock = range.getHandler(); if (handlerBlock.getSuccessors().size() != 1) { continue; // non-unique handler successor } BasicBlock successorHandler = handlerBlock.getSuccessors().get(0); InstructionSequence successorHandlerSeq = successorHandler.getSeq(); if (successorHandlerSeq.isEmpty() || successorHandlerSeq.getLastInstr().opcode != CodeConstants.opc_athrow) { continue; // not a standard synchronized range } int handlerMonitorExitIndex = findMonitorExitIndex(successorHandlerSeq); if (handlerMonitorExitIndex < 0) { continue; // no MonitorExit found in the handler successor block } // checks successful, prerequisites satisfied, now extend the range if (successorMonitorExitIndex < successorSeq.length() - 1) { // split block SimpleInstructionSequence seq = new SimpleInstructionSequence(); for(int counter = 0; counter < successorMonitorExitIndex; counter++) { seq.addInstruction(successorSeq.getInstr(0), -1); successorSeq.removeInstruction(0); } // build a separate block BasicBlock newBlock = new BasicBlock(++graph.last_id, seq); // insert new block for (BasicBlock block : successor.getPredecessors()) { block.replaceSuccessor(successor, newBlock); } newBlock.addSuccessor(successor); graph.getBlocks().addWithKey(newBlock, newBlock.id); successor = newBlock; } // copy exception edges and extend protected ranges (successor block) BasicBlock rangeExitBlock = successor.getPredecessors().get(0); FinallyProcessor.copyExceptionEdges(graph, rangeExitBlock, successor); // copy instructions (handler successor block) InstructionSequence handlerSeq = handlerBlock.getSeq(); for(int counter = 0; counter < handlerMonitorExitIndex; counter++) { handlerSeq.addInstruction(successorHandlerSeq.getInstr(0), -1); successorHandlerSeq.removeInstruction(0); } rangeExtended = true; break; } if (!rangeExtended) { break; } } }