/**
  * 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));
       }
     }
   }
 }
  /**
   * Find subroutines in the method. Create an object SubRoutine for each one. Add the edges.
   *
   * @param numBlocks an array containing the number of basic block for each instruction.
   * @param insts the instructions
   * @param bbs the basic blocks
   */
  public void findSubRoutines(short[] numBlocks, final Instruction[] insts, BasicBlock[] bbs) {
    for (int i = 0; i < bbs.length; ++i) {
      Instruction lastInst = insts[bbs[i].getEnd()];
      if (lastInst.getOpcode() == ClassfileConstants2.opc_jsr) {
        JumpInstruction jumpInst = (JumpInstruction) lastInst;
        BasicBlock subroutineCall = bbs[i];

        BasicBlock subroutineReturn = bbs[i + 1];
        final BasicBlock startSubroutine =
            bbs[numBlocks[getInstructionLine(insts, jumpInst.getTarget())]];
        SubRoutine sub = (SubRoutine) subroutines.get(startSubroutine);
        if (sub == null) {
          startSubroutine.setFirstBlockSubroutine(true);
          // we have to create the SubRoutine object
          // so we research the end block of the subroutine
          // we follow a path from start block until we find the ret
          final Map subs = subroutines;
          final BasicBlock currentBB = startSubroutine;
          // the search will not enter into nested subroutine
          // because there is an edge after a block with
          // a jsr and its next block.
          graph.visitGraphFromNode(
              currentBB,
              new NodeVisitor() {
                public boolean visit(Node n) {
                  BasicBlock bb = (BasicBlock) n;
                  Instruction last = insts[bb.getEnd()];
                  if (last.getOpcode() == ClassfileConstants2.opc_ret) {
                    // we found the end of the subroutine
                    SubRoutine s = new SubRoutine(startSubroutine, currentBB);
                    subs.put(startSubroutine, s);
                    return false;
                  }
                  return true;
                }
              });
          if ((sub = (SubRoutine) subroutines.get(startSubroutine)) == null) {
            // error
            throw new RuntimeException("NO RETURN TO SUBROUTINE");
          }
        }
        // add edges
        Edge edgeCall = subroutineCall.addSubRoutineCallNextBlock(startSubroutine);
        jumpInst.setTarget(new EdgeLabel(edgeCall));

        Edge edgeReturn = sub.getEnd().addSubRoutineReturnNextBlock(subroutineReturn);

        sub.addCall(edgeCall, edgeReturn);
      }
    }
    // remove all edges from basic blocks which end by jsr with
    // its next block.
    for (int i = 0; i < bbs.length; ++i) {
      Instruction lastInst = insts[bbs[i].getEnd()];
      if (lastInst.getOpcode() == ClassfileConstants2.opc_jsr) {
        BasicBlock subroutineCall = bbs[i];
        BasicBlock subroutineReturn = bbs[i + 1];
        subroutineCall.removeSuccessor(subroutineReturn);
      }
    }
  }