/* Soot - a J*va Optimization Framework
* Copyright (C) 2003 Navindra Umanee <navindra@cs.mcgill.ca>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
package soot.toolkits.graph;
import java.util.*;
import soot.toolkits.scalar.*;
/**
* Wrapper class for a simple dominators analysis based on a simple
* flow analysis algorithm. Works with any DirectedGraph with a
* single head.
*
* @author Navindra Umanee
**/
public class SimpleDominatorsFinder implements DominatorsFinder
{
protected DirectedGraph graph;
protected Map<Object, FlowSet> nodeToDominators;
/**
* Compute dominators for provided singled-headed directed graph.
**/
public SimpleDominatorsFinder(DirectedGraph graph)
{
//if(Options.v().verbose())
//G.v().out.println("[" + graph.getBody().getMethod().getName() +
//"] Finding Dominators...");
this.graph = graph;
SimpleDominatorsAnalysis analysis = new SimpleDominatorsAnalysis(graph);
// build node to dominators map
{
nodeToDominators = new HashMap<Object, FlowSet>(graph.size() * 2 + 1, 0.7f);
for(Iterator nodeIt = graph.iterator(); nodeIt.hasNext();) {
Object node = nodeIt.next();
FlowSet set = (FlowSet) analysis.getFlowAfter(node);
nodeToDominators.put(node, set);
}
}
}
public DirectedGraph getGraph()
{
return graph;
}
public List getDominators(Object node)
{
// non-backed list since FlowSet is an ArrayPackedFlowSet
return nodeToDominators.get(node).toList();
}
public Object getImmediateDominator(Object node)
{
// root node
if(getGraph().getHeads().contains(node))
return null;
// could be memoised, I guess
List dominatorsList = getDominators(node);
dominatorsList.remove(node);
Iterator dominatorsIt = dominatorsList.iterator();
Object immediateDominator = null;
while((immediateDominator == null) && dominatorsIt.hasNext()){
Object dominator = dominatorsIt.next();
if(isDominatedByAll(dominator, dominatorsList))
immediateDominator = dominator;
}
if(immediateDominator == null)
throw new RuntimeException("Assertion failed.");
return immediateDominator;
}
public boolean isDominatedBy(Object node, Object dominator)
{
return getDominators(node).contains(dominator);
}
public boolean isDominatedByAll(Object node, Collection dominators)
{
return getDominators(node).containsAll(dominators);
}
}
/**
* Calculate dominators for basic blocks.
* <p> Uses the algorithm contained in Dragon book, pg. 670-1.
* <pre>
* D(n0) := { n0 }
* for n in N - { n0 } do D(n) := N;
* while changes to any D(n) occur do
* for n in N - {n0} do
* D(n) := {n} U (intersect of D(p) over all predecessors p of n)
* </pre>
**/
class SimpleDominatorsAnalysis extends ForwardFlowAnalysis
{
FlowSet emptySet;
Map<Object, FlowSet> nodeToGenerateSet;
SimpleDominatorsAnalysis(DirectedGraph graph)
{
super(graph);
// define empty set, with proper universe for complementation
{
List nodes = new ArrayList();
for(Iterator nodesIt = graph.iterator(); nodesIt.hasNext();)
nodes.add(nodesIt.next());
FlowUniverse nodeUniverse = new CollectionFlowUniverse(nodes);
emptySet = new ArrayPackedSet(nodeUniverse);
}
// pre-compute generate sets
{
nodeToGenerateSet = new HashMap<Object, FlowSet>(graph.size() * 2 + 1, 0.7f);
for(Iterator nodeIt = graph.iterator(); nodeIt.hasNext();){
Object s = nodeIt.next();
FlowSet genSet = emptySet.clone();
genSet.add(s, genSet);
nodeToGenerateSet.put(s, genSet);
}
}
doAnalysis();
}
/**
* All OUTs are initialized to the full set of definitions
* OUT(Start) is tweaked in customizeInitialFlowGraph.
**/
protected Object newInitialFlow()
{
BoundedFlowSet initSet = (BoundedFlowSet) emptySet.clone();
initSet.complement();
return initSet;
}
/**
* OUT(Start) contains only Start at initialization time.
**/
protected Object entryInitialFlow()
{
List heads = graph.getHeads();
if(heads.size() != 1)
throw new RuntimeException("Assertion failed: Only one head expected.");
BoundedFlowSet initSet = (BoundedFlowSet) emptySet.clone();
initSet.add(heads.get(0));
return initSet;
}
/**
* We compute out straightforwardly.
**/
protected void flowThrough(Object inValue, Object block, Object outValue)
{
FlowSet in = (FlowSet) inValue, out = (FlowSet) outValue;
// Perform generation
in.union(nodeToGenerateSet.get(block), out);
}
/**
* All paths == Intersection.
**/
protected void merge(Object in1, Object in2, Object out)
{
FlowSet inSet1 = (FlowSet) in1,
inSet2 = (FlowSet) in2;
FlowSet outSet = (FlowSet) out;
inSet1.intersection(inSet2, outSet);
}
protected void copy(Object source, Object dest)
{
FlowSet sourceSet = (FlowSet) source,
destSet = (FlowSet) dest;
sourceSet.copy(destSet);
}
}