package xsched.analysis.wala.escape;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import xsched.analysis.wala.WalaConstants;
import xsched.analysis.wala.WalaScheduleAnalysisDriver;
import com.ibm.wala.classLoader.ArrayClass;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IField;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ipa.callgraph.propagation.HeapModel;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis;
import com.ibm.wala.ipa.callgraph.propagation.PointerKey;
import com.ibm.wala.ipa.cha.ClassHierarchy;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.util.CancelException;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.intset.OrdinalSet;
public class TaskEscapeAnalysis {
private final WalaScheduleAnalysisDriver driver;
/**
* The two input parameters define the program to analyze: the jars of .class files and the main class to start from.
*/
public TaskEscapeAnalysis(WalaScheduleAnalysisDriver driver) {
this.driver = driver;
}
/**
* The heart of the analysis.
* @throws CancelException
* @throws IllegalArgumentException
*/
public Set<InstanceKey> collectEscapingInstanceKeys() {
ClassHierarchy classHierarchy = driver.classHierarchy();
//
// extract data for analysis
//
CallGraph cg = driver.callGraph();
PointerAnalysis pa = driver.pointerAnalysis();
//
// collect all places where objects can escape their creating task:
// 1) all static fields
// 2) arguments to task schedule sites
//
Set<PointerKey> escapeAnalysisRoots = HashSetFactory.make();
HeapModel heapModel = pa.getHeapModel();
// 1) static fields
for (IClass cls : classHierarchy) {
Collection<IField> staticFields = cls.getDeclaredStaticFields();
for (Iterator<IField> sfs = staticFields.iterator(); sfs.hasNext();) {
IField sf = sfs.next();
if (sf.getFieldTypeReference().isReferenceType()) {
escapeAnalysisRoots.add(heapModel.getPointerKeyForStaticField(sf));
}
}
}
// 2) parameters to task methods
for(IMethod taskMethod : driver.taskMethods()) {
IR ir = driver.irForMethod(taskMethod);
Set<CGNode> nodes = cg.getNodes(taskMethod.getReference());
for(CGNode node : nodes) {
for(int i = 0; i < taskMethod.getNumberOfParameters(); i++) {
//don't count task objects as escaping because you can't write to them anyways; reduces size of the sets
if(! WalaConstants.isTaskType(taskMethod.getParameterType(i))) {
int ssaVariable = ir.getParameter(i);
escapeAnalysisRoots.add(heapModel.getPointerKeyForLocal(node, ssaVariable));
}
}
}
}
//
// compute escaping types: all types flowing to escaping roots and
// all types transitively reachable through their fields.
//
Set<InstanceKey> escapingInstanceKeys = HashSetFactory.make();
//
// pass 1: get abstract objects (instance keys) for escaping locations
//
for (PointerKey root : escapeAnalysisRoots) {
OrdinalSet<InstanceKey> objects = pa.getPointsToSet(root);
for (InstanceKey obj : objects) {
escapingInstanceKeys.add(obj);
}
}
//
// passes 2+: get fields of escaping keys, and add pointed-to keys
//
Set<InstanceKey> newKeys = HashSetFactory.make();
do {
newKeys.clear();
for (InstanceKey key : escapingInstanceKeys) {
IClass type = key.getConcreteType();
if (type.isReferenceType()) {
if (type.isArrayClass()) {
if (((ArrayClass) type).getElementClass() != null) {
PointerKey fk = heapModel.getPointerKeyForArrayContents(key);
OrdinalSet<InstanceKey> fobjects = pa.getPointsToSet(fk);
for (InstanceKey fobj : fobjects) {
if (!escapingInstanceKeys.contains(fobj)) {
newKeys.add(fobj);
}
}
}
} else {
Collection<IField> fields = type.getAllInstanceFields();
for (IField f : fields) {
if (f.getFieldTypeReference().isReferenceType()) {
PointerKey fk = heapModel.getPointerKeyForInstanceField(key, f);
OrdinalSet<InstanceKey> fobjects = pa.getPointsToSet(fk);
for (InstanceKey fobj : fobjects) {
if (!escapingInstanceKeys.contains(fobj)) {
newKeys.add(fobj);
}
}
}
}
}
}
}
escapingInstanceKeys.addAll(newKeys);
} while (!newKeys.isEmpty());
return escapingInstanceKeys;
}
}