package jqian.sootex.dependency.pdg.builder;
import java.util.*;
import jqian.Global;
import jqian.sootex.CFGProvider;
import jqian.sootex.ConservativelyHandledEntities;
import jqian.sootex.dependency.pdg.PDG;
import jqian.sootex.dependency.pdg.DepGraphOptions;
import jqian.sootex.dependency.pdg.SDG;
import jqian.sootex.du.IGlobalDUQuery;
import jqian.sootex.du.IReachingDUQuery;
import jqian.sootex.location.HeapAbstraction;
import jqian.sootex.location.Location;
import jqian.sootex.ptsto.IPtsToQuery;
import jqian.sootex.sideeffect.ISideEffectAnalysis;
import jqian.sootex.util.SootUtils;
import jqian.sootex.util.callgraph.CallGraphHelper;
import jqian.util.Utils;
import soot.*;
import soot.jimple.toolkits.callgraph.CallGraph;
import soot.jimple.toolkits.callgraph.ReachableMethods;
import soot.toolkits.graph.UnitGraph;
/**
*/
public class SDGBuilder {
protected SDG _sdg;
private boolean _verbose;
//--------------------- temporals --------------------------//
@SuppressWarnings("rawtypes")
private Collection _entries;
private DepGraphOptions _dgOptions;
protected IPtsToQuery _ptsto;
protected IGlobalDUQuery _gbRdQuery;
protected ISideEffectAnalysis _sideEffect;
protected CFGProvider _cfgProvider;
protected int _javaLibDepth;
protected CallGraph _restrictedCallGraph;
protected HeapAbstraction _heapAbstraction;
/** Build a context-insensitive SDG constructor.
* @param options A set of options for PDG construction
* @param rd The Reaching Definition query should cover all methods reachable from the specified entries
* Or else there may be runtime exceptions.
* @param javaLibDepth Analysis depth for Java library methods
*/
public SDGBuilder(Collection<?> entries,DepGraphOptions options,
CFGProvider cfgProvider, IPtsToQuery ptsTo, HeapAbstraction heapAbstraction,
IGlobalDUQuery rd,ISideEffectAnalysis sideEffect,boolean verbose, int javaLibDepth){
this._entries = entries;
this._verbose = verbose;
this._dgOptions = options;
this._ptsto = ptsTo;
this._gbRdQuery = rd;
this._sideEffect = sideEffect;
this._cfgProvider = cfgProvider;
this._javaLibDepth = javaLibDepth;
this._heapAbstraction = heapAbstraction;
this._sdg = new SDG();
}
public SDG getSDG(){
return _sdg;
}
public Collection<Location> getTgtUsedHeapLocs(SootMethod callee){
return _sideEffect.getUseHeapLocs(callee);
}
public Collection<Location> getTgtUsedGlobals(SootMethod callee){
return _sideEffect.getUseGlobals(callee);
}
public Collection<Location> getTgtModHeapLocs(SootMethod callee){
return _sideEffect.getModHeapLocs(callee);
}
public Collection<Location> getTgtModGlobals(SootMethod callee){
return _sideEffect.getModGlobals(callee);
}
public void buildMethodPDG(SootMethod m){
Date startTime=null;
if(_verbose){
startTime=new Date();
}
int edgeCount[] = new int[5];
int nodeCount = buildForMethod(0, m,edgeCount);
Date endTime=null;
if(_verbose){
endTime=new Date();
Global.v().out.println("[Method PDG build] Complete in "+ Utils.getTimeConsumed(startTime,endTime));
Global.v().out.println("[Dependence Count] nodes "+nodeCount+", "+PDG.statisticsToString(edgeCount));
}
}
/** This method should be called before buidling any dependence graph fragment. */
public void preBuild(){
}
private int buildForMethod(int id, SootMethod m,int edgeCount[]){
if( !m.isConcrete() || !m.hasActiveBody())
return 0;
Date startTime=null;
if(_verbose){
startTime=new Date();
}
PDGBuilder builder;
CallGraph cg = Scene.v().getCallGraph();
if(ConservativelyHandledEntities.isConservativelyHandledMethod(m) ||
ConservativelyHandledEntities.isConservativelyHandledClass(m.getDeclaringClass())){
builder = new PDGInterfaceBuilder(m,_dgOptions, this);
}
else if(_javaLibDepth>=0 && !_restrictedCallGraph.edgesOutOf(m).hasNext() && cg.edgesOutOf(m).hasNext()){
builder = new PDGInterfaceBuilder(m,_dgOptions, this);
}
else{
UnitGraph cfg = _cfgProvider.getCFG(m);
IReachingDUQuery rd = _gbRdQuery.getRDQuery(m);
builder = new PDGBuilder(m,cfg,_dgOptions, _ptsto, _heapAbstraction, rd,this);
}
builder.build();
PDG pdg = builder.getPDG();
pdg.compact();
_sdg.addPDG(m, pdg);
PDG.updateStatistic(edgeCount,pdg);
int nodeCount = pdg.getNodes().size();
//Release rd query
_gbRdQuery.releaseQuery(m);
Date endTime=null;
if(_verbose){
endTime=new Date();
Global.v().out.println("[PDG] " + id + ": " + m + " -- " + Utils.getTimeConsumed(startTime,endTime) + ", " + nodeCount +" nodes");
//Global.v().out.println("[Dependence Count] nodes "+nodeCount+", "+PDG.statisticsToString(edgeCount));
}
return nodeCount;
}
@SuppressWarnings("unchecked")
public void buildAll(){
Date startTime=null;
if(_verbose){
startTime=new Date();
}
int edgeCount[] = new int[5];
int nodeCount = 0;
ReachableMethods reachables = null;
if(_javaLibDepth<0){
// no restriction on library methods
reachables = SootUtils.getReachableMethods(_entries);
}
else{
// only limited depth of library methods are considered
CallGraph cg = CallGraphHelper.tailorLibMethods(Scene.v().getCallGraph(),_entries, _javaLibDepth);
reachables = new ReachableMethods(cg,_entries);
reachables.update();
_restrictedCallGraph = cg;
}
int i = 0;
for(Iterator<?> it = reachables.listener();it.hasNext(); i++){
SootMethod m =(SootMethod) it.next();
nodeCount += buildForMethod(i, m,edgeCount);
}
Date endTime=null;
if(_verbose){
endTime=new Date();
Global.v().out.println("[Context-insensitive SDG] "+ reachables.size() +" methods analyzed in "+
Utils.getTimeConsumed(startTime,endTime));
Global.v().out.println("[Dependence count] nodes "+ nodeCount+", "+PDG.statisticsToString(edgeCount));
}
}
/** This method should be called after the whole building to release resources. */
public void postBuild(){
_restrictedCallGraph = null;
//clear temporals to save space
_entries = null;
_dgOptions = null;
_ptsto = null;
_gbRdQuery = null;
_sideEffect = null;
}
}