experiments with context sensitivity and fixes to use base contexts
git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@4203 f5eafffb-2e1d-0410-98e4-8ec43c5233c4
This commit is contained in:
parent
880a6166a7
commit
bcd742f06c
|
@ -10,6 +10,11 @@
|
|||
*******************************************************************************/
|
||||
package com.ibm.wala.cast.js.ipa.callgraph;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.ibm.wala.cast.ir.ssa.AbstractReflectiveGet;
|
||||
import com.ibm.wala.classLoader.CallSiteReference;
|
||||
import com.ibm.wala.classLoader.IMethod;
|
||||
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||
|
@ -19,63 +24,169 @@ import com.ibm.wala.ipa.callgraph.ContextKey;
|
|||
import com.ibm.wala.ipa.callgraph.ContextSelector;
|
||||
import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey;
|
||||
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
|
||||
import com.ibm.wala.util.intset.EmptyIntSet;
|
||||
import com.ibm.wala.ipa.callgraph.propagation.cfa.OneLevelSiteContextSelector;
|
||||
import com.ibm.wala.ssa.DefUse;
|
||||
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
|
||||
import com.ibm.wala.ssa.SSAGetInstruction;
|
||||
import com.ibm.wala.ssa.SSAInstruction;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
import com.ibm.wala.util.intset.IntSetUtil;
|
||||
import com.ibm.wala.util.intset.MutableIntSet;
|
||||
|
||||
public class ForInContextSelector implements ContextSelector {
|
||||
|
||||
public static class ForInContext implements Context {
|
||||
private final InstanceKey obj;
|
||||
|
||||
public final static ContextKey FORIN_KEY = new ContextKey() {
|
||||
|
||||
ForInContext(InstanceKey obj) {
|
||||
this.obj = obj;
|
||||
};
|
||||
|
||||
public static final ContextItem FORIN_MARKER = new ContextItem() {
|
||||
|
||||
};
|
||||
|
||||
public static final String HACK_METHOD_STR = "_forin_body";
|
||||
|
||||
public static boolean USE_CPA_IN_BODIES = false;
|
||||
|
||||
public static boolean USE_1LEVEL_IN_BODIES = false;
|
||||
|
||||
public static boolean DEPENDENT_THRU_READS = true;
|
||||
|
||||
public static class SelectiveCPAContext implements Context {
|
||||
private final Context base;
|
||||
|
||||
private final Map<ContextKey, InstanceKey> parameterObjs;
|
||||
|
||||
private final int hashCode;
|
||||
|
||||
private static Map<ContextKey, InstanceKey> makeMap(InstanceKey[] x) {
|
||||
Map<ContextKey, InstanceKey> result = new HashMap<ContextKey, InstanceKey>();
|
||||
for(int i = 0; i < x.length; i++) {
|
||||
if (x[i] != null) {
|
||||
result.put(ContextKey.PARAMETERS[i], x[i]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public SelectiveCPAContext(Context base, InstanceKey[] x) {
|
||||
this(base, makeMap(x));
|
||||
}
|
||||
|
||||
public SelectiveCPAContext(Context base, Map<ContextKey, InstanceKey> parameterObjs) {
|
||||
this.base = base;
|
||||
this.parameterObjs = parameterObjs;
|
||||
hashCode = base.hashCode() ^ parameterObjs.hashCode();
|
||||
}
|
||||
|
||||
public ContextItem get(ContextKey name) {
|
||||
if (parameterObjs.containsKey(name)) {
|
||||
return new FilteredPointerKey.SingleInstanceFilter(parameterObjs.get(name));
|
||||
} else {
|
||||
return base.get(name);
|
||||
}
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return other != null &&
|
||||
getClass().equals(other.getClass()) &&
|
||||
base.equals(((SelectiveCPAContext)other).base) &&
|
||||
parameterObjs.equals(((SelectiveCPAContext)other).parameterObjs);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static class ForInContext extends SelectiveCPAContext {
|
||||
|
||||
ForInContext(Context base, InstanceKey obj) {
|
||||
super(base, Collections.singletonMap(ContextKey.PARAMETERS[2], obj));
|
||||
}
|
||||
public ContextItem get(ContextKey name) {
|
||||
if (name.equals(ContextKey.PARAMETERS[2])) {
|
||||
return new FilteredPointerKey.SingleInstanceFilter(obj);
|
||||
|
||||
public ContextItem get(ContextKey key) {
|
||||
if (FORIN_KEY.equals(key)) {
|
||||
return FORIN_MARKER;
|
||||
} else {
|
||||
return null;
|
||||
return super.get(key);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return obj.hashCode();
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return other != null &&
|
||||
getClass().equals(other.getClass()) &&
|
||||
obj.equals(((ForInContext)other).obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "for in hack filter for " + obj;
|
||||
return "for in hack filter for " + get(ContextKey.PARAMETERS[2]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final ContextSelector base;
|
||||
|
||||
private final ContextSelector oneLevel;
|
||||
|
||||
private void collectValues(DefUse du, SSAInstruction inst, MutableIntSet values) {
|
||||
if (inst instanceof SSAGetInstruction) {
|
||||
SSAGetInstruction g = (SSAGetInstruction) inst;
|
||||
values.add(g.getRef());
|
||||
if (g.getRef() != -1) {
|
||||
collectValues(du, du.getDef(g.getRef()), values);
|
||||
}
|
||||
} else if (inst instanceof AbstractReflectiveGet) {
|
||||
AbstractReflectiveGet g = (AbstractReflectiveGet) inst;
|
||||
values.add(g.getObjectRef());
|
||||
collectValues(du, du.getDef(g.getObjectRef()), values);
|
||||
values.add(g.getMemberRef());
|
||||
collectValues(du, du.getDef(g.getMemberRef()), values);
|
||||
}
|
||||
}
|
||||
|
||||
public static final String HACK_METHOD_STR = "_forin_body";
|
||||
private IntSet identifyDependentParameters(CGNode caller, CallSiteReference site) {
|
||||
MutableIntSet dependentParameters = IntSetUtil.make();
|
||||
SSAAbstractInvokeInstruction inst = caller.getIR().getCalls(site)[0];
|
||||
DefUse du = caller.getDU();
|
||||
for(int i = 0; i < inst.getNumberOfParameters(); i++) {
|
||||
MutableIntSet values = IntSetUtil.make();
|
||||
values.add(inst.getUse(i));
|
||||
if (DEPENDENT_THRU_READS) {
|
||||
collectValues(du, du.getDef(inst.getUse(i)), values);
|
||||
}
|
||||
if (values.contains(3)) {
|
||||
dependentParameters.add(i);
|
||||
}
|
||||
}
|
||||
return dependentParameters;
|
||||
}
|
||||
|
||||
public ForInContextSelector(ContextSelector base) {
|
||||
this.base = base;
|
||||
this.oneLevel = new OneLevelSiteContextSelector(base);
|
||||
}
|
||||
|
||||
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, final InstanceKey[] receiver) {
|
||||
if (callee.getDeclaringClass().getName().toString().contains(HACK_METHOD_STR)) {
|
||||
|
||||
return new ForInContext(receiver[2]);
|
||||
return new ForInContext(base.getCalleeTarget(caller, site, callee, receiver), receiver[2]);
|
||||
} else if (USE_CPA_IN_BODIES && FORIN_MARKER.equals(caller.getContext().get(FORIN_KEY))) {
|
||||
return new SelectiveCPAContext(base.getCalleeTarget(caller, site, callee, receiver), receiver);
|
||||
} else if (USE_1LEVEL_IN_BODIES && FORIN_MARKER.equals(caller.getContext().get(FORIN_KEY))) {
|
||||
if (! identifyDependentParameters(caller, site).isEmpty()) {
|
||||
return oneLevel.getCalleeTarget(caller, site, callee, receiver);
|
||||
} else {
|
||||
return base.getCalleeTarget(caller, site, callee, receiver);
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
return base.getCalleeTarget(caller, site, callee, receiver);
|
||||
}
|
||||
/**
|
||||
* else if (caller.getContext() instanceof ForInContext) {
|
||||
// use one level of call strings within the special method
|
||||
return new CallerSiteContext(caller, site);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
|
||||
if (caller.getIR().getCalls(site)[0].getNumberOfUses() > 2) {
|
||||
return IntSetUtil.make(new int[]{2});
|
||||
if (USE_CPA_IN_BODIES && FORIN_MARKER.equals(caller.getContext().get(FORIN_KEY))) {
|
||||
return identifyDependentParameters(caller, site);
|
||||
} else if (caller.getIR().getCalls(site)[0].getNumberOfUses() > 2) {
|
||||
return IntSetUtil.make(new int[]{2}).union(base.getRelevantParameters(caller, site));
|
||||
} else {
|
||||
return EmptyIntSet.instance;
|
||||
return base.getRelevantParameters(caller, site);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue