/**
  * Create the edges in the control flow graph with the basic blocks.
  *
  * @param insts the instructions
  * @param numBlocks an array containing the number of basic block for each instruction.
  * @param bbs the basic blocks
  */
 private void findCFGEdges(Instruction[] insts, short[] numBlocks, BasicBlock[] bbs) {
   for (int i = 0; i < bbs.length; ++i) {
     BasicBlock bb = bbs[i];
     Instruction lastInst = insts[bb.getEnd()];
     if (lastInst.canComplete() && i != bbs.length - 1) {
       // the next block is accessible
       bb.addDefaultNextBlock(bbs[i + 1]);
     }
     if (lastInst instanceof JumpInstruction) {
       // goto, jsr are distincts than other jump instructions.
       Edge edge;
       JumpInstruction jumpInst = (JumpInstruction) lastInst;
       if (lastInst.getOpcode() == ClassfileConstants2.opc_goto) {
         edge =
             bb.addDefaultNextBlock(
                 bbs[numBlocks[getInstructionLine(insts, jumpInst.getTarget())]]);
         jumpInst.setTarget(new EdgeLabel(edge));
       } else if (lastInst.getOpcode() == ClassfileConstants2.opc_jsr) {
         // do nothing here
         // see method findSubRoutines
       } else {
         edge =
             bb.addConditionNextBlock(
                 bbs[numBlocks[getInstructionLine(insts, jumpInst.getTarget())]]);
         jumpInst.setTarget(new EdgeLabel(edge));
       }
     }
     if (lastInst instanceof SwitchInstruction) {
       SwitchInstruction si = (SwitchInstruction) lastInst;
       for (int k = -1; k < si.getSwitchCount(); k++) {
         Edge edge =
             bb.addSwitchNextBlock(bbs[numBlocks[getInstructionLine(insts, si.getTarget(k))]]);
         si.setTarget(k, new EdgeLabel(edge));
       }
     }
   }
 }
  /**
   * Remove critical edges. A critical edge is an edge from a block with more than one successor to
   * a block with more than one predecessor. Critical edges can hinder code motion and should be
   * removed.
   */
  private void removeCriticalEdges() {
    LinkedList list = new LinkedList();
    for (BasicBlock bb = firstBB; bb != null; bb = bb.getNext()) {
      if (bb.getOutEdgesNumber() > 1) {
        Iterator outEdges = bb.getOutEdges();
        while (outEdges.hasNext()) {
          Edge outEdge = (Edge) outEdges.next();
          BasicBlock succ = (BasicBlock) outEdge.getTarget();
          if (succ.getInEdgesNumber() > 1
              && !succ.isFirstBlockSubroutine()
              && !succ.isCatchBlock()) {

            list.addLast(outEdge);
          }
        }
      }
    }

    while (!list.isEmpty()) {
      Edge edge = (Edge) list.removeFirst();
      BasicBlock source = (BasicBlock) edge.getSource();
      BasicBlock target = (BasicBlock) edge.getTarget();
      if (source.getOutEdgesNumber() > 1 && target.getInEdgesNumber() > 1) {

        // insert a new block in the CFG between source and target
        BasicBlock insert = new BasicBlock(graph);
        edge.getSource().changeEdgeTarget(edge, insert);
        insert.addDefaultNextBlock(target);

        // insert the new block before target in the trace
        target.insertBefore(insert);

        for (int i = 0; i < exceptionHandlers.length; ++i) {
          if (exceptionHandlers[i].contains(target)) {
            exceptionHandlers[i].addProtectedBlock(insert);
            insert.addExceptionNextBlock(target);
          }
        }
      }
    }
  }
  /**
   * Find the blocks protected by each ExceptionHandler. Add "exception edges" in the control flow
   * graph. Add a basic block before the block which catch the exception. This last block store the
   * exception in a variable.
   *
   * <p>Modification 02/04/2002 : add an exception edge between the blocks before the first block
   * protected and the catch block.
   *
   * @param numBlocks an array containing the number of basic block for each instruction.
   * @param insts the instructions
   * @param bbs the basic blocks
   */
  private void findExceptionBlocks(short[] numBlocks, Instruction[] insts, BasicBlock[] bbs) {
    // shows if we had ever add a block for the catch block
    boolean[] marqued = new boolean[bbs.length];
    for (int i = 0; i < exceptionHandlers.length; ++i) {
      ExceptionHandler handle = exceptionHandlers[i];
      int numBlock = numBlocks[handle.getHandle()];
      BasicBlock catchBlock = bbs[numBlock];
      if (!marqued[numBlock]) {
        // add a new block

        // if the first instruction is the saving of the
        // exception put this instruction in the
        // new block else this saving will be added during
        // the 3-adress code generation
        BasicBlock newBlock;
        Instruction first = insts[catchBlock.getStart()];
        if (first instanceof LocalVarInstruction && ((LocalVarInstruction) first).isStore()) {
          int instructionLine = catchBlock.getStart();
          newBlock = new BasicBlock(instructionLine, instructionLine, graph);
          // remove this instruction from the next block
          catchBlock.setStart(instructionLine + 1);
        } else {
          newBlock = new BasicBlock(graph);
        }
        newBlock.setCatchBlock(true);
        catchBlock.insertBefore(newBlock);
        newBlock.addDefaultNextBlock(catchBlock);
        bbs[numBlock] = newBlock;
        catchBlock = newBlock;
        marqued[numBlock] = true;
      }
      handle.setHandlerBlock(catchBlock);
    }
    for (int i = 0; i < exceptionHandlers.length; ++i) {
      ExceptionHandler handle = exceptionHandlers[i];
      BasicBlock catchBlock = handle.getHandlerBlock();
      int numInst = handle.getStart();
      int instEnd = handle.getEnd();
      int numBlock = -1;

      // MODIFICATION 02/04/2002
      if (numInst <= instEnd) {
        BasicBlock first = bbs[numBlocks[numInst]];
        if (catchBlock != first) { // this is possible !
          Iterator preds = first.getPredecessors();
          while (preds.hasNext()) {
            BasicBlock pred = (BasicBlock) preds.next();
            pred.addExceptionNextBlock(catchBlock);
          }
        }
      }
      // END MODIFICATION 02/04/2002

      numBlock = -1;
      for (; numInst <= instEnd; ++numInst) {
        if (numBlocks[numInst] != numBlock) {
          numBlock = numBlocks[numInst];
          // add blocks in exception handler.
          BasicBlock bb = bbs[numBlock];
          handle.addProtectedBlock(bb);
          // add exception edges
          bb.addExceptionNextBlock(catchBlock);

          // if it's a catch block add also the next block
          if (marqued[numBlock]) {
            BasicBlock next = bb.getNext();
            handle.addProtectedBlock(next);
            next.addExceptionNextBlock(catchBlock);
          }
        }
      }
    }
  }