package jqian.sootex.sideeffect;
import java.util.*;
import jqian.Global;
import jqian.sootex.location.AccessPath;
import jqian.sootex.location.Location;
import jqian.sootex.location.HeapAbstraction;
import jqian.sootex.ptsto.IPtsToQuery;
import jqian.sootex.ptsto.PtsToHelper;
import jqian.sootex.util.SootUtils;
import jqian.sootex.util.callgraph.Callers;
import jqian.util.Utils;
import soot.*;
import soot.jimple.toolkits.callgraph.*;
import soot.toolkits.graph.DirectedGraph;
import soot.toolkits.graph.PseudoTopologicalOrderer;
/**
* TODO incorrect implementation, dropped!
* @deprecated
* Collect the locations that are accessed outside each method.
* Use this information to filter side-effect sets
*/
@SuppressWarnings({"rawtypes","unchecked"})
class OutsideAccessAnalysis{
private Collection _entries;
private IPtsToQuery _ptsto;
HeapAbstraction _heapAbstraction;
private Set<Location>[] _method2Access;
private Set<Location>[] _method2OutsideAccess;
public OutsideAccessAnalysis(IPtsToQuery ptsto,Collection entries, HeapAbstraction heapMemAbstraction){
this._entries = entries;
this._ptsto = ptsto;
this._heapAbstraction = heapMemAbstraction;
}
/**Get outer abstract locations that can be modified by a method.*/
public Set<Location> getOutsideAccess(SootMethod m){
return _method2OutsideAccess[m.getNumber()];
}
Set<Location> getOutsideAccess(int id){
return _method2OutsideAccess[id];
}
void clearMethod(int id){
_method2OutsideAccess[id] = null;
}
public void build(){
Date startBuild = new Date();
int methodNum = SootUtils.getMethodCount();
_method2Access = new Set[methodNum];
_method2OutsideAccess = new Set[methodNum];
//1. get the collapse call graph, each strong connected component into a single graph node
CallGraph cg = Scene.v().getCallGraph();
DirectedGraph graph = SootUtils.getSCCGraph(cg,_entries);
//2. topological sort
PseudoTopologicalOrderer pto = new PseudoTopologicalOrderer();
List order = pto.newList(graph,false);
//3. top-down phase to find read/write on globals
methodNum = 0;
for(Iterator it=order.iterator();it.hasNext();){
Collection node = (Collection) it.next();
methodNum += node.size();
findAccessForComponent(node, cg);
}
//3. bottom-up phase to find read/write on instance fields
for(Iterator it=order.iterator();it.hasNext();){
Collection node = (Collection) it.next();
findOutsideAccessForComponent(node, cg);
}
//free memories
_entries = null;
_ptsto = null;
_method2Access = null;
Date endBuild = new Date();
Global.v().out.println("[OutsideAccess]"+methodNum+" methods complete in "+
Utils.getTimeConsumed(startBuild,endBuild)+".");
}
private void findAccessForComponent(Collection methods, CallGraph cg){
Set access = new HashSet();
for(Iterator it = methods.iterator();it.hasNext();){
SootMethod m = (SootMethod)it.next();
SideEffectHelper.collectRWStaticFields(m,access,access);
collectRWInstanceFields(m, access);
}
for(Iterator it = methods.iterator();it.hasNext();){
SootMethod m=(SootMethod)it.next();
int id = m.getNumber();
_method2Access[id] = access;
}
}
private void findOutsideAccessForComponent(Collection methods, CallGraph cg){
Set<SootMethod> callers = new HashSet<SootMethod>();
for (Iterator it = methods.iterator();it.hasNext();) {
SootMethod m = (SootMethod)it.next();
Callers c = new Callers(cg, m);
for (MethodOrMethodContext tgt : c.all()) {
if (!methods.contains(tgt)) {
callers.add(tgt.method());
}
}
}
Set outsideAccess = new HashSet();
for(SootMethod m: callers){
int id = m.getNumber();
Set<Location> access = _method2Access[id];
if(access!=null){
outsideAccess.addAll(access);
outsideAccess.addAll(_method2OutsideAccess[id]);
}
}
if(methods.size()>1){
SootMethod m = (SootMethod)methods.iterator().next();
outsideAccess.addAll(_method2Access[m.getNumber()]);
}
for(Iterator it = methods.iterator();it.hasNext();){
SootMethod m=(SootMethod)it.next();
int id = m.getNumber();
_method2OutsideAccess[id] = outsideAccess;
}
}
void collectRWInstanceFields(SootMethod m, Set<Location> out) {
Set<AccessPath> aps = new HashSet<AccessPath>();
SideEffectHelper.collectRWAccessPaths(m, null, aps, aps);
for(AccessPath ap: aps){
Set<Location> locs = PtsToHelper.getAccessedLocations(_ptsto, _heapAbstraction, null, ap);
out.addAll(locs);
}
}
}