package jqian.sootex.ptsto;
import java.util.*;
import soot.ArrayType;
import soot.Immediate;
import soot.RefLikeType;
import soot.RefType;
import soot.SootField;
import soot.Type;
import soot.Unit;
import soot.Value;
import soot.jimple.ArrayRef;
import soot.jimple.InstanceFieldRef;
import jqian.sootex.location.AccessPath;
import jqian.sootex.location.ArraySpace;
import jqian.sootex.location.CommonInstObject;
import jqian.sootex.location.HeapField;
import jqian.sootex.location.HeapLocation;
import jqian.sootex.location.InstanceObject;
import jqian.sootex.location.Location;
import jqian.sootex.location.HeapAbstraction;
import jqian.util.CollectionUtils;
@SuppressWarnings({ "rawtypes", "unchecked" })
public class PtsToHelper {
public static IPtsToQuery createPointsToQuery(PointsToAnalysisType type) {
IPtsToQuery ptsto = null;
switch (type) {
case SPARK:
ptsto = new SparkPtsToQuery();
break;
case TYPE_BASED:
ptsto = new TypeBasedPtsToQuery(false);
break;
case NAIVE:
ptsto = new NaivePtsToQuery();
break;
default:
throw new RuntimeException("pointer analysis - " + type + " - unsupported.");
}
return ptsto;
}
static Set<Location> getField(Set<InstanceObject> objects, SootField field) {
Set<Location> hset = new HashSet<Location>();
for (InstanceObject o: objects) {
if (!(o instanceof CommonInstObject))
continue;
CommonInstObject hobj = (CommonInstObject)o;
HeapField f = hobj.getField(field);
// Heap field can be null, if the object is considered as an atomic type
if (f != null)
hset.add(f);
}
return hset;
}
static Set<Location> getArrayElement(Set<InstanceObject> objects) {
Set<Location> hset = new HashSet<Location>();
for (InstanceObject o: objects) {
if (!(o instanceof ArraySpace))
continue;
ArraySpace hobj = (ArraySpace) o;
Location p = hobj.getElement();
hset.add(p);
}
return hset;
}
public static boolean mayAlias(IPtsToQuery ptsto, Location ptr1, Location ptr2){
if(ptr1==ptr2){
return true;
}
//firstly check the type
Type t1 = ptr1.getType();
Type t2 = ptr2.getType();
if(!(t1 instanceof RefLikeType) || !(t2 instanceof RefLikeType)){
return false;
}
else if(t1 instanceof ArrayType && !(t2 instanceof ArrayType)){
return false;
}
else if(t1 instanceof RefType && !(t2 instanceof RefType)){
return false;
}
//check points-to sets
Set pt1 = ptsto.getPointTos(null, null, ptr1);
Set pt2 = ptsto.getPointTos(null, null, ptr2);
return CollectionUtils.hasInterset(pt1, pt2);
}
/**Get all abstract locations that may alias with 'ap' in 'stmt'*/
private static Set<Location> getAliasedLocations(Unit stmt,AccessPath ap,IPtsToQuery query){
Set cur = new HashSet(40);
cur.add(ap.getRoot());
for(Object ac: ap.getAccessors()){
Set<InstanceObject> heaps;
if(cur.size()==1){
heaps = query.getPointTos(null, stmt, (Location)cur.iterator().next());
}
else{
heaps = new HashSet<InstanceObject>(100);
for(Object p: cur){
Set s = query.getPointTos(null, stmt,(Location)p);
heaps.addAll(s);
}
}
if(ac instanceof SootField){
cur = getField(heaps, (SootField)ac);
}else{
cur = getArrayElement(heaps);
}
}
return cur;
}
//TODO performance
public static Set<Location> getAccessedLocations(IPtsToQuery ptsto,
HeapAbstraction heapAbstraction, Unit stmt, AccessPath ap){
if(heapAbstraction==HeapAbstraction.FIELD_SENSITIVE){
Set<Location> locs = PtsToHelper.getAliasedLocations(null, ap, ptsto);
return locs;
}
Set<Location> locs = new HashSet<Location>();
if(heapAbstraction==HeapAbstraction.FIELD_BASED){
if(ap.withArrayElmtAccess()){
//locs.add(Location.getUnknownArrayElmt());
// distinguish elements of different arrays
Location base = ap.getRoot();
Set<InstanceObject> heaps = ptsto.getPointTos(null, stmt,base);
Set<Type> types = new HashSet<Type>();
for(InstanceObject o: heaps){
Type t = ((ArraySpace)o).getType();
types.add(t);
}
for(Type t: types){
ArraySpace o = (ArraySpace)InstanceObject.typeToObject(t);
locs.add(o.getElement());
}
}
else{
SootField f = ap.getLastAccessedField();
locs.add(Location.getHeapFieldLocation(f));
}
}
else if(heapAbstraction==HeapAbstraction.TYPE_BASED){
/*Type rootType;
if(ap.withArrayElmtAccess()){
Type elmtType = ap.getDeclareType();
rootType = elmtType.makeArrayType();
}
else{
SootField f = ap.getLastAccessedField();
rootType = f.getDeclaringClass().getType();
}
Set<Type> concreteSubTypes = TypeBasedPointsToAnalysis.v(false).reachingObjects(rootType);
for(Type t: concreteSubTypes){
HeapLocation loc = Location.getLocationForType(t);
out.add(loc);
}*/
Location base = ap.getRoot();
Set<InstanceObject> heaps = ptsto.getPointTos(null, stmt,base);
for(InstanceObject o: heaps){
Type t = null;
if(o instanceof ArraySpace){
t = ((ArraySpace)o).getType();
}
else if(o instanceof CommonInstObject){
t = ((CommonInstObject)o).getType();
}
else{
throw new RuntimeException("");
}
HeapLocation loc = Location.getLocationForType(t);
locs.add(loc);
}
}
// naive, no distinguishment
else{
Location loc = null;
if(ap.withArrayElmtAccess()){
loc = Location.getUnknownArrayElmt();
}
else{
loc = Location.getUnknownHeapField();
}
locs.add(loc);
}
return locs;
}
protected static final Set<Location> getAliasedLocations(Unit stmt,Value ref,IPtsToQuery query){
if(ref instanceof InstanceFieldRef){
InstanceFieldRef iref = (InstanceFieldRef)ref;
Location base = Location.valueToLocation(iref.getBase());
Set<InstanceObject> heaps = query.getPointTos(null, stmt,base);
Set out = getField(heaps, iref.getField());
return out;
}
else if(ref instanceof ArrayRef){
ArrayRef aref = (ArrayRef)ref;
Location base = Location.valueToLocation(aref.getBase());
Set<InstanceObject> heaps = query.getPointTos(null, stmt,base);
Set out = getArrayElement(heaps);
return out;
}
else if(ref instanceof Immediate){
Location base = Location.valueToLocation(ref);
Set out = new HashSet(1);
out.add(base);
return out;
}
else{
throw new RuntimeException();
}
}
}