package jqian.sootex.du;
import java.util.*;
import jqian.Global;
import jqian.sootex.location.AccessPath;
import jqian.sootex.location.Location;
import jqian.sootex.sideeffect.ISideEffectAnalysis;
import jqian.sootex.util.CFGEntry;
import jqian.sootex.util.CFGExit;
import jqian.sootex.util.SootUtils;
import jqian.util.CollectionUtils;
import jqian.util.Utils;
import soot.*;
import soot.jimple.IdentityStmt;
import soot.jimple.StaticFieldRef;
import soot.jimple.Stmt;
import soot.toolkits.graph.*;
import soot.toolkits.scalar.*;
/**
* A reaching DEF or USE analysis
*/
public abstract class DUAnalysis extends ForwardFlowAnalysis<Unit,FlowSet> implements IReachingDUQuery{
protected SootMethod _method;
protected boolean _verbose;
protected ISideEffectAnalysis _sideEffect;
protected FlowSet _fullSet;
protected Map<Unit,Object> _unit2Gen;
private Map<Unit,FlowSet> _unit2KillSet;
public DUAnalysis(MethodOrMethodContext mc,DirectedGraph<Unit> graph, ISideEffectAnalysis sideEffect,boolean verbose){
super(graph);
this._method = mc.method();
this._sideEffect = sideEffect;
this._verbose = verbose;
}
/** ID name of the analysis */
protected abstract String getAnalysisName();
/** DEF/USE set at the method entry. */
protected abstract Collection<ReachingDU> getEntryDU();
/** Collect DU of each statement */
protected abstract Collection<ReachingDU> collectStmtDU(Unit stmt);
private static class FinalizedFlowSet extends ArraySparseSet{
public FinalizedFlowSet(FlowSet set){
maxElements = numElements = set.size();
elements = new Object[numElements];
int i=0;
for(Iterator<?> it = set.iterator();it.hasNext(); i++){
elements[i] = it.next();
}
}
@SuppressWarnings("rawtypes")
@Override
public final List toList(){
return Arrays.asList(elements);
}
}
protected void finalizeFlowSets(){
for(Map.Entry<Unit, FlowSet> e: this.unitToBeforeFlow.entrySet()){
FlowSet v = e.getValue();
FlowSet vf = new FinalizedFlowSet(v);
e.setValue(vf);
}
}
public void build(){
if(_verbose){
Global.v().out.print("["+getAnalysisName()+"] ");
}
Date startTime = new Date();
FlowUniverse<ReachingDU> universe = collectUniverseFlowSet();
initKillSet(universe);
universe = null;
doAnalysis();
finalizeFlowSets();
clean();
Date endTime=new Date();
if(_verbose){
System.out.println(_method+" -- in "+ Utils.getTimeConsumed(startTime,endTime));
}
}
/** clean temporal data */
protected void clean(){
unitToAfterFlow = null;
filterUnitToAfterFlow = null;
filterUnitToBeforeFlow = null;
graph = null;
_sideEffect = null;
_unit2KillSet = null;
}
public Collection<Location> getDULocations(Unit u){
FlowSet gen = (FlowSet)_unit2Gen.get(u);
if(gen==null){
throw new RuntimeException("Statement " + SootUtils.getStmtString(u)+" may not in the CFG of " + _method);
}
Collection<Location> duLocations = new HashSet<Location>();
for(Iterator<?> it=gen.iterator(); it.hasNext(); ){
ReachingDU rdu = (ReachingDU)it.next();
duLocations.addAll(rdu.getLocations());
}
return duLocations;
}
/** Get the location killed by a statement. */
protected AccessPath getKilledAccessPath(Unit u){
if(u==CFGEntry.v() || u==CFGExit.v() ||
u instanceof IdentityStmt || !(u instanceof Stmt))
return null;
Stmt s = (Stmt)u;
if(s.getDefBoxes().size()!=1){
return null;
}
Value defValue = ((ValueBox)s.getDefBoxes().iterator().next()).getValue();
if(defValue instanceof Local || defValue instanceof StaticFieldRef){
AccessPath def = AccessPath.valueToAccessPath(null, s, defValue);
return def;
}
return null;
}
private void initKillSet(FlowUniverse<ReachingDU> universe){
_unit2KillSet=new HashMap<Unit,FlowSet>(graph.size()*2+1,0.7f);
for(Iterator<Unit> it=graph.iterator(); it.hasNext();){
Unit stmt = it.next();
FlowSet killedSet = _fullSet.clone();
_unit2KillSet.put(stmt,killedSet);
AccessPath killedAp = getKilledAccessPath(stmt);
if(killedAp==null){
continue;
}
for (Iterator<?> duIt = universe.iterator(); duIt.hasNext();) {
ReachingDU rd = (ReachingDU) duIt.next();
if (rd.getAccessPath()== killedAp)
killedSet.add(rd);
}
}
}
/** Get the universe reaching definition set. */
@SuppressWarnings({ "rawtypes", "unchecked" })
protected FlowUniverse<ReachingDU> collectUniverseFlowSet(){
//collect the def/use of each statement
_unit2Gen = new HashMap<Unit,Object>(graph.size()*2+1,0.7f);
List<ReachingDU> allDU = new ArrayList<ReachingDU>();
for(Iterator<?> it=graph.iterator();it.hasNext();){
Unit s = (Unit)it.next();
Collection<ReachingDU> duSet = collectStmtDU(s);
allDU.addAll(duSet);
_unit2Gen.put(s, duSet);
}
//build the empty set
FlowUniverse<ReachingDU> universe = new ArrayFlowUniverse(allDU.toArray());
// XXX: new ArrayPackedSet(FlowUniverse) consume large memory, use clone() instead
_fullSet = new ArrayPackedSet(universe);
//change the sparse representation to packed representation
for(Iterator<?> it=graph.iterator();it.hasNext();){
Unit s=(Unit)it.next();
Collection<ReachingDU> fset = (Collection<ReachingDU>)_unit2Gen.get(s);
FlowSet packedSet = _fullSet.clone();
for(ReachingDU d: fset){
packedSet.add(d);
}
_unit2Gen.put(s,packedSet);
}
return universe;
}
////////////////////// FowardFlowAnalysis ///////////////////////////
protected FlowSet newInitialFlow() {
return _fullSet.clone();
}
//TODO ���쳣���Ҳ���ܻ��������ڳ�ʼ����Ŀǰ�ļ������������������
protected FlowSet entryInitialFlow(){
return _fullSet.clone();
}
protected void merge(FlowSet in1, FlowSet in2, FlowSet out) {
in1.union(in2, out);
}
protected void copy(FlowSet source, FlowSet dest) {
source.copy(dest);
}
protected void flowThrough(FlowSet in, Unit s, FlowSet out) {
FlowSet gen = (FlowSet)_unit2Gen.get(s);
FlowSet kill = _unit2KillSet.get(s);
in.difference(kill,out);
out.union(gen);
}
/////////////////////// IReachingDUQuery /////////////////////////////
public Collection<Unit> getReachingDUSites(Unit stmt, AccessPath ap, Location loc){
Set<Unit> froms = new HashSet<Unit>();
FlowSet before = getFlowBefore(stmt);
for(Iterator<?> it=before.iterator(); it.hasNext(); ){
ReachingDU rd = (ReachingDU)it.next();
Collection<Location> duLocs = rd.getLocations();
if(duLocs.contains(loc)){
froms.add(rd.getStmt());
}
}
return froms;
}
public Collection<Unit> getReachingDUSites(Unit stmt, AccessPath ap, Collection<Location> locs){
Set<Unit> froms = new HashSet<Unit>();
FlowSet before = getFlowBefore(stmt);
findDUInFlowSet(locs,before.iterator(),froms);
return froms;
}
/**Find the possible definitions to locations in collection <code>find</code>.
* The result is added to 'froms' set */
//TODO ����ط����ڱȽϴ����������, ����Ӧ������Field���г�������
private void findDUInFlowSet(Collection<Location> find,Iterator<?> flowSetIt,Set<Unit> froms){
if(find.isEmpty()){
return;
}
for(Iterator<?> it=flowSetIt;it.hasNext();){
ReachingDU rd = (ReachingDU)it.next();
Collection<Location> duLocs = rd.getLocations();
boolean hasIntersection = false;
if(duLocs instanceof List){
for(Location loc: duLocs){
if(find.contains(loc)){
hasIntersection = true;
}
}
}
else if(!(find instanceof Set)){
for(Location loc: find){
if(duLocs.contains(loc)){
hasIntersection = true;
}
}
}
//else if(duLocs instanceof SortedArraySet || find instanceof HashSet){
//}
else{
hasIntersection = CollectionUtils.hasInterset((Set<Location>)duLocs, (Set<Location>)find);
}
if(hasIntersection){
froms.add(rd.getStmt());
}
}
}
/** Collect parameter locations, including the formals, this pointer and the accessed globals. */
protected Collection<Location> collectParams(){
Set<Location> locs = new HashSet<Location>();
Body body = _method.getActiveBody();
int argNum = _method.getParameterCount();
for(int i=0;i<argNum;i++){
Local p = body.getParameterLocal(i);
Location param = Location.valueToLocation(p);
locs.add(param);
}
if(!_method.isStatic()){
locs.add(Location.getThisPointer(_method));
}
locs.addAll(_sideEffect.getModGlobals(_method));
locs.addAll(_sideEffect.getUseGlobals(_method));
return locs;
}
}