support for full CPA, when desired.
This commit is contained in:
parent
cfbef4fe47
commit
8b2ab22335
|
@ -20,6 +20,7 @@ import com.ibm.wala.cast.ipa.callgraph.GlobalObjectKey;
|
|||
import com.ibm.wala.cast.ir.ssa.AstGlobalRead;
|
||||
import com.ibm.wala.cast.ir.ssa.AstGlobalWrite;
|
||||
import com.ibm.wala.cast.ir.ssa.AstIsDefinedInstruction;
|
||||
import com.ibm.wala.cast.ir.ssa.CAstUnaryOp;
|
||||
import com.ibm.wala.cast.ir.ssa.EachElementHasNextInstruction;
|
||||
import com.ibm.wala.cast.js.analysis.typeInference.JSTypeInference;
|
||||
import com.ibm.wala.cast.js.ipa.callgraph.JSSSAPropagationCallGraphBuilder.JSPointerAnalysisImpl.JSImplicitPointsToSetVisitor;
|
||||
|
@ -78,9 +79,12 @@ import com.ibm.wala.types.TypeReference;
|
|||
import com.ibm.wala.util.CancelException;
|
||||
import com.ibm.wala.util.CancelRuntimeException;
|
||||
import com.ibm.wala.util.MonitorUtil;
|
||||
import com.ibm.wala.util.MonitorUtil.IProgressMonitor;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
import com.ibm.wala.util.intset.IntSetAction;
|
||||
import com.ibm.wala.util.intset.IntSetUtil;
|
||||
import com.ibm.wala.util.intset.MutableIntSet;
|
||||
import com.ibm.wala.util.intset.MutableMapping;
|
||||
import com.ibm.wala.util.intset.MutableSparseIntSet;
|
||||
import com.ibm.wala.util.intset.OrdinalSet;
|
||||
|
@ -301,7 +305,7 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
|
|||
protected InterestingVisitor makeInterestingVisitor(CGNode node, int vn) {
|
||||
return new JSInterestingVisitor(vn);
|
||||
}
|
||||
|
||||
|
||||
// ///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// specialized pointer analysis
|
||||
|
@ -444,6 +448,8 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
|
|||
public void visitUnaryOp(SSAUnaryOpInstruction inst) {
|
||||
if (inst.getOpcode() == IUnaryOpInstruction.Operator.NEG) {
|
||||
addLvalTypeKeyConstraint(inst, JavaScriptTypes.Boolean);
|
||||
} else if (inst.getOpcode() == CAstUnaryOp.MINUS) {
|
||||
addLvalTypeKeyConstraint(inst, JavaScriptTypes.Number);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -594,10 +600,12 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
|
|||
private AbstractFieldPointerKey getProperty() { return fieldKey; }
|
||||
private CGNode getNode() { return node; }
|
||||
|
||||
private MutableIntSet previous = IntSetUtil.make();
|
||||
|
||||
@Override
|
||||
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable ptrs) {
|
||||
if (ptrs.getValue() != null) {
|
||||
ptrs.getValue().foreach(new IntSetAction() {
|
||||
ptrs.getValue().foreachExcluding(previous, new IntSetAction() {
|
||||
@Override
|
||||
public void act(int x) {
|
||||
final InstanceKey functionObj = system.getInstanceKey(x);
|
||||
|
@ -615,6 +623,7 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
|
|||
});
|
||||
}
|
||||
});
|
||||
previous.addAll(ptrs.getValue());
|
||||
}
|
||||
return NOT_CHANGED;
|
||||
}
|
||||
|
@ -668,6 +677,8 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
|
|||
}
|
||||
} else {
|
||||
class ReceiverForDispatchOp extends UnaryOperator<PointsToSetVariable> {
|
||||
MutableIntSet previous = IntSetUtil.make();
|
||||
|
||||
private JavaScriptInvoke getInstruction() {
|
||||
return instruction;
|
||||
}
|
||||
|
@ -675,7 +686,7 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
|
|||
@Override
|
||||
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) {
|
||||
if (rhs.getValue() != null) {
|
||||
rhs.getValue().foreach(new IntSetAction() {
|
||||
rhs.getValue().foreachExcluding(previous, new IntSetAction() {
|
||||
@Override
|
||||
public void act(int x) {
|
||||
try {
|
||||
|
@ -687,6 +698,7 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
|
|||
handleJavascriptDispatch(instruction, ik);
|
||||
}
|
||||
});
|
||||
previous.addAll(rhs.getValue());
|
||||
}
|
||||
return NOT_CHANGED;
|
||||
}
|
||||
|
@ -848,6 +860,25 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
|
|||
}
|
||||
}
|
||||
|
||||
if (iks1 == null || iks1.length == 0 || iks2 == null || iks2.length == 0) {
|
||||
if (iks1 != null) {
|
||||
for(InstanceKey ik : iks1) {
|
||||
if (addKey(ik)) {
|
||||
changed = CHANGED;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (iks2 != null) {
|
||||
for(InstanceKey ik : iks2) {
|
||||
if (addKey(ik)) {
|
||||
changed = CHANGED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.err.println(instruction);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
|
|
|
@ -148,8 +148,8 @@ public class JavaScriptFunctionApplyContextInterpreter extends AstContextInsensi
|
|||
// the commented line is correct, but it doesn't work because
|
||||
// of our broken handling of int constants as properties.
|
||||
// TODO fix property handling, and then fix this
|
||||
// S.addConstant(constVN, new ConstantValue(Integer.toString(i-1)));
|
||||
S.addConstant(constVN, new ConstantValue(i-1));
|
||||
S.addConstant(constVN, new ConstantValue(Integer.toString(i-1)));
|
||||
//S.addConstant(constVN, new ConstantValue(i-1));
|
||||
int propertyReadResult = curValNum++;
|
||||
// 4 is position of arguments array
|
||||
S.addStatement(insts.PropertyRead(S.getNumberOfStatements(), propertyReadResult, 4, constVN));
|
||||
|
|
|
@ -25,6 +25,7 @@ import com.ibm.wala.ipa.callgraph.propagation.cfa.OneLevelSiteContextSelector;
|
|||
import com.ibm.wala.types.TypeName;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
import com.ibm.wala.util.intset.IntSetUtil;
|
||||
import com.ibm.wala.util.intset.MutableIntSet;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -57,11 +58,11 @@ public class JavaScriptFunctionApplyContextSelector implements ContextSelector {
|
|||
// 0 for function (synthetic apply), 1 for this (function being invoked), 2
|
||||
// for this arg of function being invoked,
|
||||
// 3 for arguments array
|
||||
if (caller.getIR().getCalls(site)[0].getNumberOfUses() >= 4) {
|
||||
return IntSetUtil.make(new int[] { 3 }).union(base.getRelevantParameters(caller, site));
|
||||
} else {
|
||||
return base.getRelevantParameters(caller, site);
|
||||
MutableIntSet params = IntSetUtil.make();
|
||||
for(int i = 0; i < 4 && i < caller.getIR().getCalls(site)[0].getNumberOfUses(); i++) {
|
||||
params.add(i);
|
||||
}
|
||||
return params.union(base.getRelevantParameters(caller, site));
|
||||
}
|
||||
|
||||
public static class ApplyContext implements Context {
|
||||
|
|
|
@ -61,7 +61,7 @@ class ClassNewInstanceContextSelector implements ContextSelector {
|
|||
|
||||
@Override
|
||||
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
|
||||
if (site.isDispatch() || site.getDeclaredTarget().getNumberOfParameters() > 0) {
|
||||
if (ClassNewInstanceContextInterpreter.CLASS_NEW_INSTANCE_REF.equals(site.getDeclaredTarget())) {
|
||||
return thisParameter;
|
||||
} else {
|
||||
return EmptyIntSet.instance;
|
||||
|
|
|
@ -51,7 +51,7 @@ public class GetClassContextSelector implements ContextSelector {
|
|||
|
||||
@Override
|
||||
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
|
||||
if (site.isDispatch() || site.getDeclaredTarget().getNumberOfParameters() > 0) {
|
||||
if (site.getDeclaredTarget().equals(GET_CLASS)) {
|
||||
return thisParameter;
|
||||
} else {
|
||||
return EmptyIntSet.instance;
|
||||
|
|
|
@ -161,7 +161,7 @@ public class GetMethodContextSelector implements ContextSelector {
|
|||
|
||||
@Override
|
||||
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
|
||||
if (site.isDispatch() || site.getDeclaredTarget().getNumberOfParameters() > 0) {
|
||||
if (UNDERSTOOD_METHOD_REFS.contains(site.getDeclaredTarget())) {
|
||||
return thisParameter;
|
||||
} else {
|
||||
return EmptyIntSet.instance;
|
||||
|
|
|
@ -90,7 +90,7 @@ class JavaLangClassContextSelector implements ContextSelector {
|
|||
|
||||
@Override
|
||||
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
|
||||
if (site.isDispatch() || site.getDeclaredTarget().getNumberOfParameters() > 0) {
|
||||
if (UNDERSTOOD_METHOD_REFS.contains(site.getDeclaredTarget())) {
|
||||
return thisParameter;
|
||||
} else {
|
||||
return EmptyIntSet.instance;
|
||||
|
|
|
@ -107,7 +107,8 @@ class ReflectiveInvocationSelector implements ContextSelector {
|
|||
*/
|
||||
private boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) {
|
||||
if (instance instanceof ConstantKey) {
|
||||
if (targetMethod.getReference().equals(ReflectiveInvocationInterpreter.METHOD_INVOKE) || isConstructorConstant(instance)
|
||||
if (targetMethod.getReference().equals(ReflectiveInvocationInterpreter.METHOD_INVOKE) ||
|
||||
isConstructorConstant(instance)
|
||||
&& targetMethod.getReference().equals(ReflectiveInvocationInterpreter.CTOR_NEW_INSTANCE)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -129,7 +130,8 @@ class ReflectiveInvocationSelector implements ContextSelector {
|
|||
|
||||
@Override
|
||||
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
|
||||
if (site.isDispatch() || site.getDeclaredTarget().getNumberOfParameters() > 0) {
|
||||
if (site.getDeclaredTarget().equals(ReflectiveInvocationInterpreter.METHOD_INVOKE) ||
|
||||
site.getDeclaredTarget().equals(ReflectiveInvocationInterpreter.CTOR_NEW_INSTANCE)) {
|
||||
return thisParameter;
|
||||
} else {
|
||||
return EmptyIntSet.instance;
|
||||
|
|
|
@ -44,9 +44,13 @@ public interface ContextKey {
|
|||
public final int index;
|
||||
|
||||
public ParameterKey(int index) {
|
||||
super();
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "P" + index;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 IBM Corporation.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package com.ibm.wala.ipa.callgraph.propagation;
|
||||
|
||||
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.ContextSelector;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
import com.ibm.wala.util.intset.IntSetUtil;
|
||||
import com.ibm.wala.util.intset.MutableIntSet;
|
||||
|
||||
public class CPAContextSelector implements ContextSelector {
|
||||
|
||||
private final ContextSelector base;
|
||||
|
||||
public CPAContextSelector(ContextSelector base) {
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
public static class CPAContext extends SelectiveCPAContext {
|
||||
|
||||
public CPAContext(Context base, InstanceKey[] x) {
|
||||
super(base, x);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] actualParameters) {
|
||||
Context target = base.getCalleeTarget(caller, site, callee, actualParameters);
|
||||
if (actualParameters != null && actualParameters.length > 0) {
|
||||
return new CPAContext(target, actualParameters);
|
||||
} else {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean dispatchIndex(CallSiteReference ref, int i) {
|
||||
if (ref.isStatic()) {
|
||||
return ! ref.getDeclaredTarget().getParameterType(i).isPrimitiveType();
|
||||
} else {
|
||||
return i==0 || ! ref.getDeclaredTarget().getParameterType(i-1).isPrimitiveType();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
|
||||
MutableIntSet s = IntSetUtil.make();
|
||||
for(int i = 0; i < caller.getIR().getCalls(site)[0].getNumberOfUses(); i++) {
|
||||
if (dispatchIndex(site, i)) {
|
||||
s.add(i);
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
|
@ -78,6 +78,7 @@ import com.ibm.wala.util.MonitorUtil;
|
|||
import com.ibm.wala.util.MonitorUtil.IProgressMonitor;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.debug.Assertions;
|
||||
import com.ibm.wala.util.debug.UnimplementedError;
|
||||
import com.ibm.wala.util.functions.VoidFunction;
|
||||
import com.ibm.wala.util.intset.IntIterator;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
|
@ -232,6 +233,8 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
|
|||
|
||||
addNodeInstructionConstraints(node, monitor);
|
||||
|
||||
addNodeValueConstraints(node, monitor);
|
||||
|
||||
DefUse du = getCFAContextInterpreter().getDU(node);
|
||||
addNodePassthruExceptionConstraints(node, ir, du);
|
||||
// conservatively assume something changed
|
||||
|
@ -264,6 +267,14 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for aubclasses to add pointer flow constraints based on values in a given node
|
||||
* @throws CancelException
|
||||
*/
|
||||
protected void addNodeValueConstraints(CGNode node, IProgressMonitor monitor) throws CancelException {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add constraints for a particular basic block.
|
||||
* @throws CancelException
|
||||
|
@ -497,6 +508,74 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
|
|||
return result;
|
||||
}
|
||||
|
||||
private class CrossProductRec {
|
||||
private final InstanceKey[][] invariants;
|
||||
private final VoidFunction<InstanceKey[]> f;
|
||||
private final SSAAbstractInvokeInstruction call;
|
||||
private final CGNode caller;
|
||||
private final int[] params;
|
||||
private final CallSiteReference site;
|
||||
private final InstanceKey[] keys;
|
||||
|
||||
private CrossProductRec(InstanceKey[][] invariants, SSAAbstractInvokeInstruction call, CGNode caller,
|
||||
VoidFunction<InstanceKey[]> f) {
|
||||
this.invariants = invariants;
|
||||
this.f = f;
|
||||
this.call = call;
|
||||
this.caller = caller;
|
||||
this.site = call.getCallSite();
|
||||
this.params = IntSetUtil.toArray(getRelevantParameters(caller, site));
|
||||
this.keys = new InstanceKey[ params.length ];
|
||||
}
|
||||
|
||||
protected void rec(final int pi, final int rhsi) {
|
||||
if (pi == params.length) {
|
||||
f.apply(keys);
|
||||
} else {
|
||||
final int p = params[pi];
|
||||
int vn = call.getUse(p);
|
||||
InstanceKey[] ik = invariants != null ? invariants[p] : null;
|
||||
if (ik != null) {
|
||||
if (ik.length > 0) {
|
||||
for (int i = 0; i < ik.length; i++) {
|
||||
system.findOrCreateIndexForInstanceKey(ik[i]);
|
||||
keys[pi] = ik[i];
|
||||
rec(pi + 1, rhsi);
|
||||
}
|
||||
} else {
|
||||
if (!site.isDispatch() || p != 0) {
|
||||
keys[pi] = null;
|
||||
rec(pi + 1, rhsi);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
IntSet s = getParamObjects(pi, rhsi);
|
||||
if (s != null && !s.isEmpty()) {
|
||||
s.foreach(new IntSetAction() {
|
||||
@Override
|
||||
public void act(int x) {
|
||||
keys[pi] = system.getInstanceKey(x);
|
||||
rec(pi + 1, rhsi + 1);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (!site.isDispatch() || p != 0) {
|
||||
keys[pi] = null;
|
||||
rec(pi + 1, rhsi + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected IntSet getParamObjects(int paramIndex, int rhsi) {
|
||||
int paramVn = call.getUse(paramIndex);
|
||||
PointerKey var = getPointerKeyForLocal(caller, paramVn);
|
||||
IntSet s = system.findOrCreatePointsToSet(var).getValue();
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A visitor that generates constraints based on statements in SSA form.
|
||||
*/
|
||||
|
@ -1045,7 +1124,22 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
|
|||
}
|
||||
|
||||
InstanceKey[][] invariantParameters = invs.computeInvariantParameters(instruction);
|
||||
if (instruction.getCallSite().isStatic()) {
|
||||
|
||||
IntSet params = getBuilder().getContextSelector().getRelevantParameters(node, instruction.getCallSite());
|
||||
if (!instruction.getCallSite().isStatic() && !params.contains(0) && (invariantParameters == null || invariantParameters[0] == null)) {
|
||||
params = IntSetUtil.makeMutableCopy(params);
|
||||
((MutableIntSet)params).add(0);
|
||||
}
|
||||
|
||||
if (invariantParameters != null) {
|
||||
for(int i = 0; i < invariantParameters.length; i++) {
|
||||
if (invariantParameters[i] != null) {
|
||||
params = IntSetUtil.makeMutableCopy(params);
|
||||
((MutableIntSet)params).remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (params.isEmpty()) {
|
||||
for (CGNode n : getBuilder().getTargetsForCall(node, instruction, invariantParameters)) {
|
||||
getBuilder().processResolvedCall(node, instruction, n, invariantParameters, uniqueCatch);
|
||||
if (DEBUG) {
|
||||
|
@ -1059,11 +1153,6 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
|
|||
// Add a side effect that will fire when we determine a value
|
||||
// for a dispatch parameter. This side effect will create a new node
|
||||
// and new constraints based on the new callee context.
|
||||
IntSet params = getBuilder().getContextSelector().getRelevantParameters(node, instruction.getCallSite());
|
||||
if (! params.contains(0)) {
|
||||
params = IntSetUtil.makeMutableCopy(params);
|
||||
((MutableIntSet)params).add(0);
|
||||
}
|
||||
final int vns[] = new int[ params.size() ];
|
||||
params.foreach(new IntSetAction() {
|
||||
private int i = 0;
|
||||
|
@ -1635,15 +1724,65 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
|
|||
this.uniqueCatch = uniqueCatch;
|
||||
this.dispatchIndices = IntSetUtil.toArray(dispatchIndices);
|
||||
// we better always be interested in the receiver
|
||||
assert this.dispatchIndices[0] == 0;
|
||||
// assert this.dispatchIndices[0] == 0;
|
||||
previousPtrs = new MutableIntSet[dispatchIndices.size()];
|
||||
for(int i = 0; i < previousPtrs.length; i++) {
|
||||
previousPtrs[i] = IntSetUtil.getDefaultIntSetFactory().make();
|
||||
}
|
||||
}
|
||||
|
||||
private byte cpa(PointsToSetVariable lhs, final PointsToSetVariable[] rhs) {
|
||||
final MutableBoolean changed = new MutableBoolean();
|
||||
for(int rhsIndex = 0; rhsIndex < rhs.length; rhsIndex++) {
|
||||
final int y = rhsIndex;
|
||||
IntSet currentObjs = rhs[rhsIndex].getValue();
|
||||
if (currentObjs != null) {
|
||||
final IntSet oldObjs = previousPtrs[rhsIndex];
|
||||
currentObjs.foreachExcluding(oldObjs, new IntSetAction() {
|
||||
@Override
|
||||
public void act(final int x) {
|
||||
new CrossProductRec(constParams, call, node,
|
||||
new VoidFunction<InstanceKey[]>() {
|
||||
@Override
|
||||
public void apply(InstanceKey[] v) {
|
||||
IClass recv = null;
|
||||
if (call.getCallSite().isDispatch()) {
|
||||
recv = v[0].getConcreteType();
|
||||
}
|
||||
CGNode target = getTargetForCall(node, call.getCallSite(), recv, v);
|
||||
if (target != null) {
|
||||
changed.b = true;
|
||||
processResolvedCall(node, call, target, constParams, uniqueCatch);
|
||||
if (!haveAlreadyVisited(target)) {
|
||||
markDiscovered(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}) {
|
||||
|
||||
{
|
||||
rec(0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IntSet getParamObjects(int paramVn, int rhsi) {
|
||||
if (rhsi == y) {
|
||||
return IntSetUtil.make(new int[]{ x });
|
||||
} else {
|
||||
return previousPtrs[rhsi];
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
previousPtrs[rhsIndex].addAll(currentObjs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
byte sideEffectMask = changed.b ? (byte) SIDE_EFFECT_MASK : 0;
|
||||
return (byte) (NOT_CHANGED | sideEffectMask);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see com.ibm.wala.dataflow.fixpoint.UnaryOperator#evaluate(com.ibm.wala.dataflow.fixpoint.IVariable,
|
||||
* com.ibm.wala.dataflow.fixpoint.IVariable)
|
||||
|
@ -1651,6 +1790,10 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
|
|||
@Override
|
||||
public byte evaluate(PointsToSetVariable lhs, final PointsToSetVariable[] rhs) {
|
||||
assert dispatchIndices.length >= rhs.length : "bad operator at " + call;
|
||||
|
||||
return cpa(lhs, rhs);
|
||||
|
||||
/*
|
||||
// did evaluating the dispatch operation add a new possible target
|
||||
// to the call site?
|
||||
final MutableBoolean addedNewTarget = new MutableBoolean();
|
||||
|
@ -1744,6 +1887,7 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
|
|||
|
||||
byte sideEffectMask = addedNewTarget.b ? (byte) SIDE_EFFECT_MASK : 0;
|
||||
return (byte) (NOT_CHANGED | sideEffectMask);
|
||||
*/
|
||||
}
|
||||
|
||||
private void handleAllReceivers(MutableIntSet receiverVals, InstanceKey[] keys, MutableBoolean sideEffect) {
|
||||
|
@ -1864,51 +2008,7 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
|
|||
|
||||
protected void iterateCrossProduct(final CGNode caller, final SSAAbstractInvokeInstruction call, IntSet parameters,
|
||||
final InstanceKey[][] invariants, final VoidFunction<InstanceKey[]> f) {
|
||||
final int params[] = IntSetUtil.toArray(parameters);
|
||||
final InstanceKey[] keys = new InstanceKey[call.getNumberOfParameters()];
|
||||
final CallSiteReference site = call.getCallSite();
|
||||
new Object() {
|
||||
private void rec(final int pi) {
|
||||
if (pi == params.length) {
|
||||
f.apply(keys);
|
||||
} else {
|
||||
final int p = params[pi];
|
||||
int vn = call.getUse(p);
|
||||
PointerKey var = getPointerKeyForLocal(caller, vn);
|
||||
InstanceKey[] ik = invariants != null ? invariants[p] : null;
|
||||
if (ik != null) {
|
||||
if (ik.length > 0) {
|
||||
for (int i = 0; i < ik.length; i++) {
|
||||
system.findOrCreateIndexForInstanceKey(ik[i]);
|
||||
keys[p] = ik[i];
|
||||
rec(pi + 1);
|
||||
}
|
||||
} else {
|
||||
if (!site.isDispatch() || p != 0) {
|
||||
keys[p] = null;
|
||||
rec(pi + 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
IntSet s = system.findOrCreatePointsToSet(var).getValue();
|
||||
if (s != null && !s.isEmpty()) {
|
||||
s.foreach(new IntSetAction() {
|
||||
@Override
|
||||
public void act(int x) {
|
||||
keys[p] = system.getInstanceKey(x);
|
||||
rec(pi + 1);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (!site.isDispatch() || p != 0) {
|
||||
keys[p] = null;
|
||||
rec(pi + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.rec(0);
|
||||
new CrossProductRec(invariants, call, caller, f).rec(0, 0);
|
||||
}
|
||||
|
||||
protected Set<CGNode> getTargetsForCall(final CGNode caller, final SSAAbstractInvokeInstruction instruction, InstanceKey[][] invs) {
|
||||
|
@ -1919,11 +2019,7 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
|
|||
// to take the invoke instruction as a parameter instead, since invs is
|
||||
// associated with the instruction
|
||||
final CallSiteReference site = instruction.getCallSite();
|
||||
IntSet params = contextSelector.getRelevantParameters(caller, site);
|
||||
if (!site.isStatic() && !params.contains(0)) {
|
||||
params = IntSetUtil.makeMutableCopy(params);
|
||||
((MutableIntSet)params).add(0);
|
||||
}
|
||||
IntSet params = getRelevantParameters(caller, site);
|
||||
final Set<CGNode> targets = HashSetFactory.make();
|
||||
VoidFunction<InstanceKey[]> f = new VoidFunction<InstanceKey[]>() {
|
||||
@Override
|
||||
|
@ -1942,6 +2038,15 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
|
|||
return targets;
|
||||
}
|
||||
|
||||
private IntSet getRelevantParameters(final CGNode caller, final CallSiteReference site) throws UnimplementedError {
|
||||
IntSet params = contextSelector.getRelevantParameters(caller, site);
|
||||
if (!site.isStatic() && !params.contains(0)) {
|
||||
params = IntSetUtil.makeMutableCopy(params);
|
||||
((MutableIntSet)params).add(0);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
public boolean hasNoInterestingUses(CGNode node, int vn, DefUse du) {
|
||||
|
||||
if (du == null) {
|
||||
|
|
|
@ -17,6 +17,7 @@ import java.util.Map;
|
|||
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.util.collections.HashMapFactory;
|
||||
|
||||
/**
|
||||
* A selective Cartesian product context that enforces object sensitivity on some set
|
||||
|
@ -34,12 +35,13 @@ public class SelectiveCPAContext implements Context {
|
|||
|
||||
// helper method for constructing the parameterObjs map
|
||||
private static Map<ContextKey, InstanceKey> makeMap(InstanceKey[] x) {
|
||||
Map<ContextKey, InstanceKey> result = new HashMap<ContextKey, InstanceKey>();
|
||||
Map<ContextKey, InstanceKey> result = HashMapFactory.make();
|
||||
for(int i = 0; i < x.length; i++) {
|
||||
if (x[i] != null) {
|
||||
result.put(ContextKey.PARAMETERS[i], x[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -53,6 +55,11 @@ public class SelectiveCPAContext implements Context {
|
|||
hashCode = base.hashCode() ^ parameterObjs.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "cpa:" + parameterObjs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextItem get(ContextKey name) {
|
||||
if (parameterObjs.containsKey(name)) {
|
||||
|
@ -78,5 +85,4 @@ public class SelectiveCPAContext implements Context {
|
|||
parameterObjs.equals(((SelectiveCPAContext)other).parameterObjs);
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue