package xsched.analysis.wala;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.Context;
import com.ibm.wala.ipa.callgraph.ContextItem;
import com.ibm.wala.ipa.callgraph.ContextKey;
import com.ibm.wala.ipa.callgraph.ContextSelector;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.ssa.SSANewInstruction;
public class TaskStringContextSelector implements ContextSelector {
public static final ContextKey TASK_CREATION_SITE = new ContextKey() {
@Override
public String toString() {
return "TASK_CREATION_SITE_KEY";
}
};
private final ContextSelector base;
public TaskStringContextSelector(ContextSelector base) {
this.base = base;
}
//do something like: have a base context selector (probably a default one).
//ask the base selector for a context
//check for the task context of the caller and add the tasks up to some length n
//combine the task string and the base context into a single context
//pretty much, steal from the nCFAContextSelector and its superclass CallStringContextSelector
@Override
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
Context baseContext = base.getCalleeTarget(caller, site, callee, receiver);
IR ir = caller.getIR();
if(WalaConstants.isTaskMethod(site.getDeclaredTarget())) {
SSAAbstractInvokeInstruction[] invokes = ir.getCalls(site);
assert invokes.length == 1;
//0 is the "this" of the invoke, 1 is the "now" parameter (1st param)
int now = invokes[0].getUse(1);
SSAInstruction creationSite = caller.getDU().getDef(now);
TaskCreationSite tcs = new TaskCreationSite(caller.getMethod(), (SSANewInstruction)creationSite);
return new TaskContextPair(tcs, baseContext);
} else {
//normal call
TaskCreationSite tcs = (TaskCreationSite)caller.getContext().get(TASK_CREATION_SITE);
return new TaskContextPair(tcs, baseContext);
}
}
//the "new" site of a task as a combination of it's def-use
private static class TaskCreationSite implements ContextItem {
private final SSANewInstruction creationSite;
private final IMethod method;
public TaskCreationSite(IMethod method, SSANewInstruction creationSite) {
assert method != null;
assert creationSite != null;
this.method = method;
this.creationSite = creationSite;
}
@Override
public int hashCode() {
return method.hashCode() * creationSite.hashCode();
}
@Override
public boolean equals(Object other) {
if(other instanceof TaskCreationSite) {
TaskCreationSite otherTCS = (TaskCreationSite)other;
return otherTCS.method.equals(method) && otherTCS.creationSite.equals(creationSite);
} else {
return false;
}
}
}
private static class TaskContextPair implements Context {
private final TaskCreationSite taskCreationSite;
private final Context base;
private TaskContextPair(TaskCreationSite cs, Context base) {
assert base != null;
this.taskCreationSite = cs;
this.base = base;
}
@Override
public boolean equals(Object o) {
if(taskCreationSite == null) {
return (o instanceof TaskContextPair) && ((TaskContextPair) o).taskCreationSite == null
&& ((TaskContextPair) o).base.equals(base);
} else {
return (o instanceof TaskContextPair) && ((TaskContextPair) o).taskCreationSite.equals(taskCreationSite)
&& ((TaskContextPair) o).base.equals(base);
}
}
@Override
public String toString() {
return "TaskCreationSite: " + taskCreationSite + ":" + base.toString();
}
@Override
public int hashCode() {
return taskCreationSite == null ? base.hashCode() : taskCreationSite.hashCode() * base.hashCode();
}
public ContextItem get(ContextKey name) {
if (TASK_CREATION_SITE.equals(name)) {
return taskCreationSite;
} else {
return base.get(name);
}
}
};
}