in src/org/jetbrains/java/decompiler/modules/code/DeadCodeHelper.java [248:368]
public static void extendSynchronizedRangeToMonitorExit(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;
}
}
}