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