/** * */ package soottocfg.cfg.util; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.Map; import java.util.Queue; import java.util.Set; import java.util.TreeSet; import org.jgrapht.Graphs; import org.jgrapht.util.VertexPair; /** * @author schaef * */ public class LoopFinder<V> { private final Map<V, Set<V>> loops; private final LoopNestedTreeSet loopNestTree; public LoopFinder(Dominators<V> dom) { Set<VertexPair<V>> backEdges = findBackEdges(dom); loops = findLoops(dom, backEdges); loopNestTree = new LoopNestedTreeSet(); loopNestTree.addAll(getLoopHeaders()); } /** * Returns the set of loop headers. * @return Set of loop headers. */ public Set<V> getLoopHeaders() { return loops.keySet(); } /** * Returns the loop body for a given loop header. * @param header * @return */ public Set<V> getLoopBody(V header) { return loops.get(header); } /** * Returns a map from loop header to loop body for * each loop in the graph. * @return */ public Map<V, Set<V>> getLoops() { return new HashMap<V, Set<V>>(loops); } /** * Returns a loop-nested TreeSet where each element is a loop header * and first (lowest) elements are the inner-most loops. * This contains less information than a proper loop-nested tree but * is sufficient to iterate over the loops from inner loops to outer * loops. * @return Loop-nested TreeSet. */ public LoopNestedTreeSet getLoopNestTreeSet() { return new LoopNestedTreeSet(loopNestTree); } /** * Find the set of backEdges. A backEdge is an edge from a * vertex n to a vertex h, s.t. h dominates n. * @param dom * @return Set of back edges as vertex pairs (n,h). */ private Set<VertexPair<V>> findBackEdges(Dominators<V> dom) { Set<VertexPair<V>> backEdges = new HashSet<VertexPair<V>>(); for (V node : dom.getGraph().vertexSet()) { for (V succ : Graphs.successorListOf(dom.getGraph(), node)) { if (dom.isDominatedBy(node, succ)) { backEdges.add(new VertexPair<V>(node, succ)); } } } return backEdges; } /** * Given a set of back edges, compute a mapping from the loop headers * to the set of vertices in the loop bodies. * @param dom The dominator class of a graph. * @param backEdges Set of backEdges from a vertex n to a loop header h. * @return Map from loop header h to the set of vertices in its loop body. */ private Map<V, Set<V>> findLoops(Dominators<V> dom, Set<VertexPair<V>> backEdges) { Map<V, Set<V>> res = new HashMap<V, Set<V>>(); for (VertexPair<V> backEdge : backEdges) { if (!res.containsKey(backEdge.getSecond())) { res.put(backEdge.getSecond(), new HashSet<V>()); } res.get(backEdge.getSecond()).addAll(findNaturalLoop(dom, backEdge)); } return res; } /** * Find the natural loop for a given backEdge. * Given a back edge from a vertex n to a loop head h, the natural loop * contains all vertices x, s.t. h dominates x and there is a path from * x to n not containing h. * Note that a natural loop does contain the loop header. * @param dom The dominator class of a graph. * @param backEdge A backEdge from a vertex n to a loop header h. * @return The set of vertices included in the natural loop of backEdge. */ private Set<V> findNaturalLoop(Dominators<V> dom, VertexPair<V> backEdge) { Set<V> loopBody = new HashSet<V>(); V header = backEdge.getSecond(); Queue<V> todo = new LinkedList<V>(); todo.add(backEdge.getFirst()); while (!todo.isEmpty()) { V current = todo.poll(); loopBody.add(current); for (V pre : Graphs.predecessorListOf(dom.getGraph(), current)) { if (!todo.contains(pre) && !loopBody.contains(pre) && dom.isDominatedBy(pre, header)) { todo.add(pre); } } } return loopBody; } private class LoopNestTreeComparator implements Comparator<V> { @Override public int compare(V a, V b) { if (a.equals(b)) { return 0; } if (getLoopBody(b).contains(a)) { return -1; } return 1; //not comparable } } public class LoopNestedTreeSet extends TreeSet<V> { private static final long serialVersionUID = 5639463978704086555L; public LoopNestedTreeSet() { super(new LoopNestTreeComparator()); } public LoopNestedTreeSet(Collection<V> vertices) { super(new LoopNestTreeComparator()); addAll(vertices); } } }