package xsched.analysis.wala;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import xsched.analysis.core.AnalysisResult;
import xsched.analysis.core.AnalysisSession;
import xsched.analysis.core.AnalysisTask;
import xsched.analysis.core.AnalysisTaskResolver;
import xsched.analysis.core.TaskSchedule;
import xsched.analysis.wala.escape.TaskEscapeAnalysis;
import xsched.analysis.wala.schedule_extraction.NormalNodeFlowData;
import xsched.analysis.wala.schedule_extraction.TaskScheduleSolver;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.ipa.callgraph.AnalysisCache;
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
import com.ibm.wala.ipa.callgraph.AnalysisScope;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ipa.callgraph.CallGraphBuilder;
import com.ibm.wala.ipa.callgraph.CallGraphBuilderCancelException;
import com.ibm.wala.ipa.callgraph.Entrypoint;
import com.ibm.wala.ipa.callgraph.impl.AllApplicationEntrypoints;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis;
import com.ibm.wala.ipa.cha.ClassHierarchy;
import com.ibm.wala.ipa.cha.ClassHierarchyException;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.SSAInvokeInstruction;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.util.config.AnalysisScopeReader;
import com.ibm.wala.util.ref.ReferenceCleanser;
public class WalaScheduleAnalysisDriver {
//private static boolean DEBUG = true;
private static final ClassLoader MY_CLASSLOADER = WalaScheduleAnalysisDriver.class.getClassLoader();
private final AnalysisProperties properties;
private AnalysisCache cache;
private AnalysisScope scope;
private ClassHierarchy classHierarchy;
private Iterable<Entrypoint> entrypoints;
private AnalysisOptions options;
private CallGraph cg;
private PointerAnalysis pointerAnalysis;
private HashSet<IMethod> taskMethods;
//all main tasks; those are included in the taskMethods, too!
private HashSet<IMethod> mainTaskMethods;
private AnalysisSession<CGNode, Integer, WalaTaskScheduleManager> analysis;
private AnalysisResult<CGNode> scheduleAnalysisResult;
private Set<InstanceKey> escapeAnalysisResult;
public WalaScheduleAnalysisDriver(AnalysisProperties properties) {
this.properties = properties;
}
public Set<IMethod> taskMethods() {
return taskMethods;
}
public Set<IMethod> mainTaskMethods() {
return mainTaskMethods;
}
public Iterable<Entrypoint> entrypoints() {
assert entrypoints != null;
return this.entrypoints;
}
public CallGraph callGraph() {
assert cg != null;
return this.cg;
}
public PointerAnalysis pointerAnalysis() {
assert pointerAnalysis != null;
return pointerAnalysis;
}
public ClassHierarchy classHierarchy() {
assert classHierarchy != null;
return classHierarchy;
}
public void _1_setUp() throws IOException, ClassHierarchyException {
assert cache == null;
cache = new AnalysisCache();
ReferenceCleanser.registerCache(cache);
//
scope = AnalysisScopeReader.readJavaScope(properties.standardScopeFile, properties.openExclusionsFile(), MY_CLASSLOADER);
for(String s : properties.applicationFiles) {
AnalysisScope appScope = AnalysisScopeReader.makeJavaBinaryAnalysisScope(s, properties.openExclusionsFile());
scope.addToScope(appScope);
}
//
classHierarchy = ClassHierarchy.make(scope);
ReferenceCleanser.registerClassHierarchy(classHierarchy);
//
this.entrypoints = new AllApplicationEntrypoints(scope, classHierarchy);
this.options = new AnalysisOptions(scope, entrypoints);
//
analysis = new AnalysisSession<CGNode, Integer, WalaTaskScheduleManager>();
}
public void _2_findTaskMethods() {
this.taskMethods = new HashSet<IMethod>();
this.mainTaskMethods = new HashSet<IMethod>();
Iterator<IClass> classes = classHierarchy.iterator();
while(classes.hasNext()) {
IClass clazz = classes.next();
//we don't have to look in the standard library because they don't have any task methods
if( ! clazz.getClassLoader().getReference().equals(ClassLoaderReference.Primordial)) {
for(IMethod method : clazz.getDeclaredMethods()) {
if(WalaConstants.isTaskMethod(method.getReference())) {
taskMethods.add(method);
if(WalaConstants.isMainTaskMethod(method.getReference())) {
mainTaskMethods.add(method);
}
}
}
}
}
}
public void _3_makeCallGraph() throws IllegalArgumentException, CallGraphBuilderCancelException {
CallGraphBuilder builder = properties.createCallGraphBuilder(options, cache, scope, classHierarchy);
cg = builder.makeCallGraph(options, null);
pointerAnalysis = builder.getPointerAnalysis();
}
public NormalNodeFlowData _n_computeNodeFlowData(IR ir) {
NormalNodeFlowData flowData = TaskScheduleSolver.solve(ir);
return flowData;
}
//this method will call computeNodeFlowData() so you con't have to do that if you don't need the flow data
public TaskSchedule<Integer, WalaTaskScheduleManager> _n_computeTaskSchedule(IR ir) {
NormalNodeFlowData flowData = _n_computeNodeFlowData(ir);
WalaTaskScheduleManager manager = WalaTaskScheduleManager.make(cache.getSSACache(), ir, flowData);
TaskSchedule<Integer, WalaTaskScheduleManager> taskSchedule = flowData.makeTaskSchedule(manager);
return taskSchedule;
}
public AnalysisTaskResolver<CGNode, Integer, WalaTaskScheduleManager> createResolver() {
return new AnalysisTaskResolver<CGNode, Integer,WalaTaskScheduleManager>() {
@Override
public Collection<CGNode> possibleTargetTasksForSite(
AnalysisTask<CGNode, Integer, WalaTaskScheduleManager> task,
Integer scheduleNode) {
WalaTaskScheduleManager manager = task.taskSchedule().taskScheduleManager();
SSAInvokeInstruction invoke = manager.scheduleSiteForNode(scheduleNode);
return cg.getNodes(invoke.getDeclaredTarget());
}
};
}
public IR irForMethod(IMethod method) {
return cache.getIR(method);
}
public void _4_createAnalysisTasks() {
for(IMethod taskMethod : taskMethods) {
TaskSchedule<Integer, WalaTaskScheduleManager> taskSchedule = _n_computeTaskSchedule(irForMethod(taskMethod));
for(CGNode node : cg.getNodes(taskMethod.getReference())) {
analysis.createTask(node, taskSchedule);
}
}
}
public AnalysisResult<CGNode> _5_runAnalysisOnMainTaskMethods() {
AnalysisTaskResolver<CGNode, Integer, WalaTaskScheduleManager> resolver = createResolver();
AnalysisResult<CGNode> result = new AnalysisResult<CGNode>();
//now solve the analysis for each main task
for(IMethod mainTaskMethod : mainTaskMethods) {
for(CGNode node : cg.getNodes(mainTaskMethod.getReference())) {
AnalysisTask<CGNode, Integer, WalaTaskScheduleManager> task = analysis.taskForID(node);
AnalysisResult<CGNode> analysisResult = task.solveAsRoot(resolver);
result.mergeWith(analysisResult);
}
}
return result;
}
public AnalysisResult<CGNode> scheduleAnalysisResult() {
assert scheduleAnalysisResult != null;
return scheduleAnalysisResult;
}
public void runScheduleAnalysis() throws IOException, ClassHierarchyException, IllegalArgumentException, CallGraphBuilderCancelException {
this._1_setUp();
this._2_findTaskMethods();
this._3_makeCallGraph();
this._4_createAnalysisTasks();
this.scheduleAnalysisResult = this._5_runAnalysisOnMainTaskMethods();
//XXX note: in FakeRootClass, Wala imitates schedules of all task methods, it seems; is that a problem?
}
public Set<InstanceKey> escapeAnalysisResult() {
return this.escapeAnalysisResult;
}
public void runTaskEscapeAnalysis() {
TaskEscapeAnalysis analysis = new TaskEscapeAnalysis(this);
this.escapeAnalysisResult = analysis.collectEscapingInstanceKeys();
}
}