package jqian.sootex.dependency;
import java.util.*;
import jqian.sootex.util.CFGExit;
import soot.Unit;
import soot.toolkits.graph.DirectedGraph;
import soot.toolkits.graph.DominatorNode;
import soot.toolkits.graph.DominatorTree;
import soot.toolkits.graph.InverseGraph;
import soot.toolkits.graph.MHGDominatorsFinder;
import soot.toolkits.graph.MHGPostDominatorsFinder;
import soot.toolkits.graph.StronglyConnectedComponents;
public class DependencyHelper {
static class PatchedGraph<N> implements DirectedGraph<N> {
final DirectedGraph<N> g;
final HashMap<N, HashSet<N>> node2preds = new HashMap<N, HashSet<N>>();
final HashMap<N, HashSet<N>> node2succs = new HashMap<N, HashSet<N>>();
public PatchedGraph(DirectedGraph<N> g) {
this.g = g;
}
private void addPredInternal(N n, N pred){
HashSet<N> preds = node2preds.get(n);
if(preds==null){
preds = new HashSet<N>();
node2preds.put(n, preds);
}
preds.add(pred);
}
public void addSuccInternal(N n, N succ){
HashSet<N> succs = node2succs.get(n);
if(succs==null){
succs = new HashSet<N>();
node2succs.put(n, succs);
}
succs.add(succ);
}
public void addPred(N n, N pred){
addPredInternal(n, pred);
addSuccInternal(pred, n);
}
public void addSucc(N n, N succ){
addSuccInternal(n, succ);
addPredInternal(succ, n);
}
public List<N> getPredsOf(N s) {
HashSet<N> preds = node2preds.get(s);
if(preds!=null){
List<N> out = new ArrayList<N>(g.getPredsOf(s));
out.addAll(preds);
return out;
}
else{
return g.getPredsOf(s);
}
}
public List<N> getSuccsOf(N s) {
HashSet<N> succs = node2succs.get(s);
if(succs!=null){
List<N> out = new ArrayList<N>(g.getSuccsOf(s));
out.addAll(succs);
return out;
}
else{
return g.getSuccsOf(s);
}
}
public List<N> getHeads() {
return g.getHeads();
}
public List<N> getTails() {
return g.getTails();
}
public Iterator<N> iterator() {
return g.iterator();
}
public int size() {
return g.size();
}
}
@SuppressWarnings({"rawtypes", "unchecked" })
static DirectedGraph<Unit> patchCFG(DirectedGraph<Unit> graph){
// XXX if there are infinite loops, patch edges to the graph so that the algorithm can work
// StronglyConnectedComponentsFast<N> scc = new StronglyConnectedComponentsFast<N>(graph);
StronglyConnectedComponents scc = new StronglyConnectedComponents(graph);
List<List> components = scc.getComponents();
Collection<Unit> tails = graph.getTails();
PatchedGraph<Unit> pgraph = new PatchedGraph<Unit>(graph);
for (List<?> c : components) {
HashSet s = new HashSet(c);
boolean withSuccs = false;
boolean containTails = false;
for (Object n : c) {
if (withSuccs) {
break;
}
if (tails.contains(n)) {
containTails = true;
break;
}
List<Unit> succs = graph.getSuccsOf((Unit) n);
for (Unit p : succs) {
if (!s.contains(p)) {
withSuccs = true;
break;
}
}
}
// infinite loop if the condition is satisfied
if (!withSuccs && !containTails) {
Unit nodeWithPred = null;
for (Object n : c) {
if (nodeWithPred != null) {
break;
}
List<Unit> preds = graph.getPredsOf((Unit) n);
for (Unit p : preds) {
if (!s.contains(p)) {
nodeWithPred = (Unit) n;
break;
}
}
}
pgraph.addSucc(nodeWithPred, tails.iterator().next());
}
}
return pgraph;
}
/**
* Compute the control flow dependences for each statement.
* Using the algorithm from:
* Ferrantet et al. The Program Dependence Graph and Its Use in Optimization. TOPLAS, 1987.
* @note previous algorithm using INFL set seems incorrect.
* @note Currently only handle hammock graph
*
* TODO: ������һ����Ȩ�ص�Worklist�㷨�����к���ؾ��ڵ�������ܸ���һЩ.
* Ŀǰ�İ汾δ���ǵ���˳��, ����Ч�ʿ��ܲ���
*/
public static Map<Unit,Collection<Unit>> calcCtrlDependences(DirectedGraph<Unit> cfg){
int size = cfg.size();
Map<Unit,Collection<Unit>> node2depend = new HashMap<Unit,Collection<Unit>>(size*2+1,0.7f);
// find post dominators and build post dominator tree
//MHGPostDominatorsFinder postdomFinder = new MHGPostDominatorsFinder(cfg);
CFGDominatorsFinder<Unit> postdomFinder = new CFGDominatorsFinder<Unit>(new InverseGraph<Unit>(cfg));
while(postdomFinder.containInfiniteLoops()){
cfg = patchCFG(cfg);
postdomFinder = new CFGDominatorsFinder<Unit>(new InverseGraph<Unit>(cfg));
}
DominatorTree postdomTree = new DominatorTree(postdomFinder);
// process each conditional edge to find the control dependence relationships
// a. a virtual edge from ENTRY -> START
Unit exit = CFGExit.v();
for(Unit head: cfg.getHeads()){
DominatorNode startNode = postdomTree.getDode(head);
DominatorNode endNode = postdomTree.getDode(exit);
Collection<DominatorNode> ancestors = findAncestors(postdomTree, startNode, endNode, true);
Collection<Unit> dependby = dominatorsToUnits(ancestors);
addCtrlDep(node2depend, head, dependby);
}
// b. other conditional edges
for(Iterator<Unit> it=cfg.iterator(); it.hasNext(); ){
Unit u = it.next();
List<Unit> succs = cfg.getSuccsOf(u);
// conditional edges
if(succs.size()>1){
DominatorNode srcNode = postdomTree.getDode(u);
for(Unit tgt: succs){
// skip edge to dominators
if(postdomFinder.isDominatedBy(u, tgt)){
continue;
}
DominatorNode tgtNode = postdomTree.getDode(tgt);
DominatorNode commonAncestor = findCommonAncestors(postdomTree, srcNode, tgtNode);
Collection<DominatorNode> ancestors;
if(commonAncestor==srcNode){
//Case: L = A. All nodes in the post-dominator tree on the path from A to B,
//including A and B, should be made control dependent on A.
//XXX: exclude A to avoid loop dependence
ancestors = findAncestors(postdomTree, tgtNode, srcNode, false);
ancestors.add(tgtNode);
}
else{
//Case. L = parent of A. All nodes in the post-dominator tree on the path
//from L to B, including B but not L, should be made control dependent on A.
ancestors = findAncestors(postdomTree, tgtNode, commonAncestor, false);
ancestors.add(tgtNode);
}
Collection<Unit> dependby = dominatorsToUnits(ancestors);
addCtrlDep(node2depend, u, dependby);
}
}
}
return node2depend;
}
private static Set<DominatorNode> findAncestors(DominatorTree postdomTree,
DominatorNode start, DominatorNode end, boolean includeEnd){
Set<DominatorNode> ancestors = new HashSet<DominatorNode>();
DominatorNode parent = start.getParent();
while(parent!=null && parent!=end){
ancestors.add(parent);
parent = parent.getParent();
}
if(parent!=null && includeEnd){
ancestors.add(parent);
}
return ancestors;
}
private static DominatorNode findCommonAncestors(DominatorTree postdomTree, DominatorNode n1, DominatorNode n2){
Collection<DominatorNode> ancestors2 = findAncestors(postdomTree, n2, null, true);
ancestors2.add(n2);
DominatorNode parent = n1;
while(parent!=null){
if(ancestors2.contains(parent)){
return parent;
}
parent = parent.getParent();
}
return null;
}
private static Collection<Unit> dominatorsToUnits(Collection<DominatorNode> dominators) {
Collection<Unit> dependby = new ArrayList<Unit>(dominators.size());
for (DominatorNode d : dominators) {
Unit u = (Unit) d.getGode();
dependby.add(u);
}
return dependby;
}
private static void addCtrlDep(Map<Unit, Collection<Unit>> node2depend, Unit n, Collection<Unit> dependby) {
for (Unit dependbyUnit : dependby) {
Collection<Unit> depend = node2depend.get(dependbyUnit);
if (depend == null) {
depend = new ArrayList<Unit>();
node2depend.put(dependbyUnit, depend);
}
depend.add(n);
}
}
}