/** * */ package soottocfg.cfg.util; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.jgrapht.DirectedGraph; import org.jgrapht.Graphs; import com.google.common.base.Preconditions; import com.google.common.base.Verify; /** * @author schaef * */ public abstract class AbstractDominators<V> { private final DirectedGraph<V, ?> graph; protected Map<V, Set<V>> dominators; protected Map<V, V> iDominators; protected Tree<V> dominatorTree; public AbstractDominators(DirectedGraph<V, ?> g) { graph = g; } /** * Get the directed graph for which the dominators are computed. * @return */ public DirectedGraph<V, ?> getGraph() { return graph; } /** * Check if node is dominated by dominator * @param node * @param dominator * @return */ public boolean isDominatedBy(V node, V dominator) { if (!dominators.containsKey(node)) { throw new IllegalArgumentException("Node is not part of the graph: "+node); } if (!dominators.containsKey(dominator)) { throw new IllegalArgumentException("Node is not part of the graph: "+node); } return dominators.get(node).contains(dominator); } /** * Check if node is strictly dominated by dominator * (i.e., node!=dominator and dominator dominates node) * @param node * @param dominator * @return */ public boolean isStrictlyDominatedBy(V node, V dominator) { if (node.equals(dominator)) { return false; } return isDominatedBy(node, dominator); } /** * Returns true if there exists an element in dominators that * strictly dominates node. * @param node * @param dominators * @return */ public boolean isStrictlyDominatedByAny(V node, Collection<V> dominators) { for (V dom : dominators) { if (isStrictlyDominatedBy(node, dom)) { return true; } } return false; } /** * Get the immediate dominator for node * @param node * @return The immediate dominator of node, or null if node has no dominator. */ public V getImmediateDominator(V node) { if (!iDominators.containsKey(node)) { throw new IllegalArgumentException("Node is not part of the graph: "+node); } return iDominators.get(node); } /** * Get the dominators for node * @param node * @return */ public Set<V> getDominators(V node) { if (!dominators.containsKey(node)) { throw new IllegalArgumentException("Node is not part of the graph: "+node); } return new HashSet<V>(dominators.get(node)); } /** * Get the mapping from vertex to its set of dominators * @param node * @return */ public Map<V, Set<V>> getDominators() { return new HashMap<V, Set<V>>(dominators); } /** * Get the dominator tree of the graph. * @return */ public Tree<V> getDominatorTree() { return dominatorTree; } /** * Compute the immediate (post)dominator for each vertex. * @param dom Mapping from each vertex to its set of (post)dominators. * @return Map from vertex to its immediate (post)dominator, or null if * the vertex does not have an immediate (post)dominator */ protected Map<V, V> computeImmediateDominators(Map<V, Set<V>> dom) { Map<V, V> idominators = new HashMap<V, V>(); for (Entry<V, Set<V>> entry : dom.entrySet()) { V idom = null; for (V dominator : entry.getValue()) { Set<V> dominatorDiff = new HashSet<V>(entry.getValue()); dominatorDiff.removeAll(dom.get(dominator)); if (dominatorDiff.size() == 1 && dominatorDiff.iterator().next() == entry.getKey()) { idom = dominator; break; } } idominators.put(entry.getKey(), idom); } return idominators; } /** * Computes the (post)dominators for all vertices in a graph * starting from the given source. * * @param source * The source vertex to start from (should be either source or * sink) * @param forward * true, for computing dominators; false, for computing * post-dominators * @return */ protected Map<V, Set<V>> computeDominators(V source, boolean forward) { Preconditions.checkArgument(graph.containsVertex(source)); Set<V> vertices = graph.vertexSet(); Map<V, Set<V>> dominators = new LinkedHashMap<V, Set<V>>(vertices.size()); // Initialize the set for (V b : vertices) { if (b.equals(source)) { // The Source node only dominates itself Set<V> tmp = new LinkedHashSet<V>(); tmp.add(b); dominators.put(b, tmp); } else { // All other nodes are initialized to be the full graph. They // will shrink later Set<V> tmp = new LinkedHashSet<V>(vertices); dominators.put(b, tmp); } } boolean changed; do { changed = false; for (V b : vertices) { // Source node is always only dominated by itself. if (!b.equals(source)) { Set<V> newDom = new HashSet<V>(vertices); // This is a bit ugly way to handle the initialization // of the intersection problem // but it should work if (forward) { Verify.verify(graph.inDegreeOf(b) != 0, "Unexpected indegree of 0 for " + b); for (V inBlock : Graphs.predecessorListOf(graph, b)) { newDom.retainAll(dominators.get(inBlock)); } } else { Verify.verify(graph.outDegreeOf(b) != 0, "Unexpected outdegree of 0 for "+b); for (V inBlock : Graphs.successorListOf(graph, b)) { newDom.retainAll(dominators.get(inBlock)); } } // every node dominates itself newDom.add(b); if (!newDom.equals(dominators.get(b))) { dominators.put(b, newDom); changed = true; } } } } while (changed); return dominators; } /** * Creates a (post)dominator tree from a given map. * @param immediateDominators Mapping from vertex to its immediate (post)dominator. * @return A (post)dominator tree. */ protected Tree<V> computeDominatorTree(Map<V, V> immediateDominators) { Tree<V> dominatorTree = new Tree<V>(); for (Entry<V,V> entry : immediateDominators.entrySet()) { if (entry.getValue()!=null) { dominatorTree.addEdge(entry.getValue(), entry.getKey()); } } return dominatorTree; } }