package org.jf.dexlib.Code.Analysis.graphs; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.jf.dexlib.Code.Analysis.graphs.Dominators.DomEdge; import org.jgrapht.DirectedGraph; /** * This class computes the dominance frontiers for each node in a flow graph. * A flow graph is a directed graph with a unique start node, where all nodes * are reachable from this start node. A standard control flow graph is such a graph * and its also true for the inverted cfg, when the exit node is used as start node. * * The dominance frontier (DF) of a node n is a set nodes that are not strictly dominated * by n, but their predecessors are. So this are the nodes where the influence/domination * of n ends: <tt>DF(n) = { w | pred(w) is in DOM(n) and w not in SDOM(n) }</tt> * * @author Juergen Graf <juergen.graf@gmail.com> * */ public class DominanceFrontiers<V, E> { public static <V, E> DominanceFrontiers<V, E> compute(final DirectedGraph<V, E> graph, final V entry) { final Dominators<V, E> dom = Dominators.compute(graph, entry); final DominanceFrontiers<V, E> df = new DominanceFrontiers<V, E>(graph, entry, dom); df.analyze(); return df; } private final DirectedGraph<V, E> flowGraph; private final V entry; private final Dominators<V, E> dom; private final Map<V, Set<V>> frontiers = new HashMap<V, Set<V>>(); private DominanceFrontiers(final DirectedGraph<V, E> graph, final V entry, final Dominators<V, E> dom) { this.flowGraph = graph; this.entry = entry; this.dom = dom; } public Set<V> getDominanceFrontier(V node) { final Set<V> domFront = frontiers.get(node); return (domFront == null ? null : Collections.unmodifiableSet(domFront)); } private void analyze() { DomFrontWalker<DomEdge> walker = new DomFrontWalker<DomEdge>(dom.getDominationTree()); walker.traverseDFS(entry); } private final class DomFrontWalker<X> extends GraphWalker<V, X> { public DomFrontWalker(DirectedGraph<V, X> domTree) { super(domTree); } @Override public void discover(V node) { // nothing to do at discover time } @Override public void finish(V current) { final Set<V> dfCur = new HashSet<V>(); frontiers.put(current, dfCur); for (final E out : flowGraph.outgoingEdgesOf(current)) { final V succ = flowGraph.getEdgeTarget(out); if (dom.getIDom(succ) != current) { dfCur.add(succ); } } for (V succ : dom.getNodesWithIDom(current)) { for (V succFrontier : frontiers.get(succ)) { if (dom.getIDom(succFrontier) != current) { dfCur.add(succFrontier); } } } } } }