public static void extendSynchronizedRangeToMonitorExit()

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;
      }
    }
  }