/**
   * 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);
          }
        }
      }
    }
  }