package cdg;
import graphutils.AbstractTwoWayGraph;
import graphutils.Edge;
import graphutils.PostorderIterator;
import java.util.Collection;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
public class DominatorTree<V>
{
private HashMap<V, V> dominators;
private HashMap<V, Set<V>> dominanceFrontiers;
private HashMap<V, Integer> postorderEnumeration;
private DominatorTree()
{
dominators = new HashMap<V, V>();
dominanceFrontiers = new HashMap<V, Set<V>>();
postorderEnumeration = new HashMap<V, Integer>();
}
public static <V, E extends Edge<V>> DominatorTree<V> newInstance(
AbstractTwoWayGraph<V, E> graph, V startNode)
{
return new DominatorTreeCreator<V, E>(graph, startNode).create();
}
public Collection<V> getVertices()
{
return dominators.keySet();
}
public V getDominator(V vertex)
{
return dominators.get(vertex);
}
public Set<V> dominanceFrontier(V vertex)
{
return dominanceFrontiers.get(vertex);
}
private V commonDominator(List<V> vertices)
{
Deque<V> stack = new LinkedList<V>();
for (V vertex : vertices)
{
if (hasDominator(vertex))
{
stack.push(vertex);
}
}
if (stack.isEmpty())
{
return null;
}
while (stack.size() > 1)
{
stack.push(commonDominator(stack.pop(), stack.pop()));
}
return stack.pop();
}
private V commonDominator(V vertex1, V vertex2)
{
V finger1 = vertex1;
V finger2 = vertex2;
while (!finger1.equals(finger2))
{
while (postorderEnumeration.get(finger1) < postorderEnumeration
.get(finger2))
{
finger1 = getDominator(finger1);
}
while (postorderEnumeration.get(finger2) < postorderEnumeration
.get(finger1))
{
finger2 = getDominator(finger2);
}
}
assert finger1.equals(finger2) : "fingers do not match";
return finger1;
}
private boolean addVertex(V vertex)
{
if (!contains(vertex))
{
dominators.put(vertex, null);
return true;
}
return false;
}
private boolean setDominator(V vertex, V dominator)
{
boolean changed = false;
if (contains(vertex))
{
V currentDominator = dominators.get(vertex);
if (currentDominator == null && dominator != null)
{
dominators.put(vertex, dominator);
changed = true;
}
else if (!currentDominator.equals(dominator))
{
dominators.put(vertex, dominator);
changed = true;
}
else
{
changed = false;
}
}
return changed;
}
private boolean contains(V vertex)
{
return dominators.containsKey(vertex);
}
private boolean hasDominator(V vertex)
{
return dominators.get(vertex) != null;
}
private static class DominatorTreeCreator<V, E extends Edge<V>>
{
private DominatorTree<V> dominatorTree;
private AbstractTwoWayGraph<V, E> graph;
private List<V> orderedVertices;
private V startNode;
public DominatorTreeCreator(AbstractTwoWayGraph<V, E> graph, V startNode)
{
this.dominatorTree = new DominatorTree<V>();
this.graph = graph;
this.orderedVertices = new LinkedList<V>();
this.startNode = startNode;
}
public DominatorTree<V> create()
{
enumerateVertices();
initializeDominatorTree();
buildDominatorTree();
determineDominanceFrontiers();
return dominatorTree;
}
private void determineDominanceFrontiers()
{
for (V currentNode : orderedVertices)
{
if (graph.inDegree(currentNode) > 1)
{
V runner;
for (Edge<V> edge : graph.ingoingEdges(currentNode))
{
V predecessor = edge.getSource();
if (!orderedVertices.contains(predecessor))
{
continue;
}
runner = predecessor;
while (!runner.equals(dominatorTree
.getDominator(currentNode)))
{
if (!dominatorTree.dominanceFrontiers
.containsKey(runner))
{
dominatorTree.dominanceFrontiers.put(runner,
new HashSet<V>());
}
dominatorTree.dominanceFrontiers.get(runner).add(
currentNode);
runner = dominatorTree.getDominator(runner);
}
}
}
}
}
private void buildDominatorTree()
{
boolean changed = true;
while (changed)
{
changed = false;
ListIterator<V> reverseVertexIterator = orderedVertices
.listIterator(orderedVertices.size());
// Skip the root
reverseVertexIterator.previous();
while (reverseVertexIterator.hasPrevious())
{
V currentNode = reverseVertexIterator.previous();
List<V> list = new LinkedList<V>();
for (Edge<V> edge : graph.ingoingEdges(currentNode))
{
list.add(edge.getSource());
}
V newIdom = dominatorTree.commonDominator(list);
dominatorTree.addVertex(currentNode);
if (dominatorTree.setDominator(currentNode, newIdom))
{
changed = true;
}
}
}
}
private void enumerateVertices()
{
int counter = 0;
Iterator<V> postorderIterator = new PostorderIterator<V, E>(graph,
startNode);
while (postorderIterator.hasNext())
{
V vertex = postorderIterator.next();
orderedVertices.add(vertex);
dominatorTree.postorderEnumeration.put(vertex, counter++);
}
if (orderedVertices.size() < graph.size())
{
System.out.println("warning: incomplete control flow graph");
}
}
private void initializeDominatorTree()
{
dominatorTree.addVertex(startNode);
dominatorTree.setDominator(startNode, startNode);
}
}
}