package jqian.sootex.du;
import java.util.*;
import jqian.sootex.location.AccessPath;
import jqian.sootex.location.HeapAbstraction;
import jqian.sootex.location.Location;
import jqian.sootex.ptsto.IPtsToQuery;
import jqian.sootex.ptsto.PtsToHelper;
import jqian.sootex.sideeffect.ISideEffectAnalysis;
import jqian.sootex.util.CFGEntry;
import jqian.sootex.util.CFGExit;
import jqian.sootex.util.callgraph.Callees;
import soot.*;
import soot.jimple.ArrayRef;
import soot.jimple.FieldRef;
import soot.jimple.IdentityStmt;
import soot.jimple.InstanceInvokeExpr;
import soot.jimple.InvokeExpr;
import soot.jimple.Stmt;
import soot.jimple.toolkits.callgraph.CallGraph;
import soot.toolkits.graph.*;
/**
* A reaching use analysis implemented with bit vectors.
*/
public class RUAnalysis extends DUAnalysis{
protected IPtsToQuery _pt2Query;
protected HeapAbstraction _heapAbstraction;
public RUAnalysis(MethodOrMethodContext mc,DirectedGraph<Unit> graph,IPtsToQuery pt2Query,
HeapAbstraction heapAbstraction, ISideEffectAnalysis sideEffect,boolean verbose){
super(mc, graph, sideEffect, verbose);
this._pt2Query = pt2Query;
this._heapAbstraction = heapAbstraction;
}
public void build(){
super.build();
_pt2Query = null;
}
/** ID name of the analysis */
protected String getAnalysisName(){
return "RU";
}
/** USE set at the method entry. */
protected Collection<ReachingDU> getEntryDU(){
Collection<ReachingDU> entrySet = new ArrayList<ReachingDU>();
// TODO: What should be the reaching uses at the method entry?
/*Unit entry = CFGEntry.v();
* Collection<Location> params = collectParams(); for(Location loc:
* params){ AccessPath ap = AccessPath.getByRoot(loc); entrySet.add(new
* ReachingDU(entry,ap,loc)); }
*
* Collection<Location> use = _sideEffect.getUseHeapLocs(_method);
* if(use.size()>0){ entrySet.add(new ReachingDU(entry,null,use)); }
*/
return entrySet;
}
protected Collection<ReachingDU> collectInvokeUses(Unit invokeStmt){
Collection<ReachingDU> ruSet = new ArrayList<ReachingDU>();
CallGraph cg = Scene.v().getCallGraph();
//for all use to global location
Set<Location> useGlobals = new HashSet<Location>();
Callees callees = new Callees(cg, invokeStmt);
for(SootMethod tgt: callees.all()){
if (!tgt.isConcrete())
continue;
Collection<Location> use = _sideEffect.getUseGlobals(tgt);
useGlobals.addAll(use);
}
for(Location gb: useGlobals){
AccessPath ap = AccessPath.getByRoot(gb);
ReachingDU use = new ReachingDU(invokeStmt,ap,gb);
ruSet.add(use);
}
// for heap use
if(callees.all().size()==1){
SootMethod tgt = callees.all().iterator().next();
Collection<Location> useHeaps;
if (tgt.isConcrete()){
useHeaps = _sideEffect.getUseHeapLocs(tgt);
}
else{
useHeaps = getNativeCallUse(invokeStmt, tgt);
}
if(!useHeaps.isEmpty()){
ReachingDU use = new ReachingDU(invokeStmt,null,useHeaps);
ruSet.add(use);
}
}
else{
Set<Location> useLocs = new HashSet<Location>();
for(SootMethod tgt: callees.all()) {
Collection<Location> calleeUses;
if (tgt.isConcrete()){
calleeUses = _sideEffect.getUseHeapLocs(tgt);
}
else{
calleeUses = getNativeCallUse(invokeStmt, tgt);
}
useLocs.addAll(calleeUses);
}
if (!useLocs.isEmpty()) {
ReachingDU use = new ReachingDU(invokeStmt, null, useLocs);
ruSet.add(use);
}
}
return ruSet;
}
@SuppressWarnings("unchecked")
private Collection<Location> getNativeCallUse(Unit u, SootMethod tgt){
InvokeExpr invoke = ((Stmt)u).getInvokeExpr();
Value receiver = null;
if(!invoke.getMethod().isStatic()){
InstanceInvokeExpr iie = (InstanceInvokeExpr)invoke;
receiver = iie.getBase();
}
Collection<AccessPath> use = NativeMethodDUHelper.v().getUse(tgt, receiver, invoke.getArgs());
if(use.size()==0){
return Collections.emptyList();
}
else if(use.size()==1){
AccessPath d = use.iterator().next();
Collection<Location> useLocs = PtsToHelper.getAccessedLocations(_pt2Query, _heapAbstraction, u, d);
return useLocs;
}
else{
Collection<Location> locs = new HashSet<Location>();
for(AccessPath d: use){
Collection<Location> useLocs = PtsToHelper.getAccessedLocations(_pt2Query, _heapAbstraction, u, d);
locs.addAll(useLocs);
}
return locs;
}
}
/** Collect RU of each statement */
protected Collection<ReachingDU> collectStmtDU(Unit stmt){
if(stmt==CFGEntry.v()){
return getEntryDU();
}
if(stmt==CFGExit.v() || stmt instanceof IdentityStmt){
return Collections.emptyList();
}
Collection<ReachingDU> ruSet = new ArrayList<ReachingDU>();
Set<Value> uses = new HashSet<Value>();
for(ValueBox box: stmt.getUseBoxes()){
Value v = box.getValue();
uses.add(v);
}
for(Value v: uses){
if(v instanceof Local){
Location root = Location.valueToLocation((Local)v);
AccessPath ap = AccessPath.getByRoot(root);
ReachingDU ru = new ReachingDU(stmt,ap,root);
ruSet.add(ru);
}
else if((v instanceof FieldRef) || (v instanceof ArrayRef)){
AccessPath ap = AccessPath.valueToAccessPath(_method, stmt, v);
Collection<Location> duLocs = PtsToHelper.getAccessedLocations(_pt2Query, _heapAbstraction, stmt, ap);
ReachingDU ru = new ReachingDU(stmt,ap,duLocs);
ruSet.add(ru);
}
else if(v instanceof InvokeExpr){
Collection<ReachingDU> rds = collectInvokeUses(stmt);
ruSet.addAll(rds);
}
}
return ruSet;
}
}