Changes to extend supported context sensitivity to CPA-style:

1) extend ContextSelector interface to allow it to specify parameters of interest
  2) extend filtering mechanism at call sites to allow CPA-style filtering when requested by contexts
  3) various related fixes and extensions:
    a) removed redundant code to handle dispatch for JavaScript, so now it shares the core mechanism
    b) tighten types for operators that take an array of args - now the array is T[] at the cost of a few array allocation methods
    c) a bit more support for empty int sets
    d) void function objects
    e) bug fixes for lexical scoping support, and adaptation to work with core dispatch mechanism
    f) example of CPA-style sensitivity to handle nastiness in a JavaScript for(.. in ...) loop
    

git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@4150 f5eafffb-2e1d-0410-98e4-8ec43c5233c4
This commit is contained in:
dolby-oss 2011-04-27 13:58:56 +00:00
parent 3fffba2c87
commit 4da02a9125
74 changed files with 1151 additions and 659 deletions

View File

@ -117,7 +117,7 @@ public class AstJavaTypeInference extends AstTypeInference {
private PrimAndStringOp() {
}
public byte evaluate(TypeVariable lhs, IVariable[] rhs) {
public byte evaluate(TypeVariable lhs, TypeVariable[] rhs) {
TypeAbstraction meet = null;
for (int i = 0; i < rhs.length; i++) {

View File

@ -132,7 +132,7 @@ public class AstJavaSSAPropagationCallGraphBuilder extends AstSSAPropagationCall
public AstJavaConstraintVisitor(
AstSSAPropagationCallGraphBuilder builder,
ExplicitCallGraph.ExplicitNode node)
CGNode node)
{
super(builder, node);
}
@ -277,7 +277,7 @@ public class AstJavaSSAPropagationCallGraphBuilder extends AstSSAPropagationCall
}
}
protected ConstraintVisitor makeVisitor(ExplicitCallGraph.ExplicitNode node) {
protected ConstraintVisitor makeVisitor(CGNode node) {
return new AstJavaConstraintVisitor(this, node);
}
}

View File

@ -41,7 +41,7 @@ public class AstJavaZeroOneContainerCFABuilder extends AstJavaCFABuilder {
ContextSelector appContextSelector, SSAContextInterpreter appContextInterpreter) {
super(cha, options, cache);
ContextSelector def = new DefaultContextSelector(options);
ContextSelector def = new DefaultContextSelector(options, cha);
ContextSelector contextSelector = appContextSelector == null ? def : new DelegatingContextSelector(appContextSelector, def);
SSAContextInterpreter contextInterpreter = makeDefaultContextInterpreters(appContextInterpreter, options, cha);

View File

@ -32,7 +32,7 @@ public class AstJavaZeroXCFABuilder extends AstJavaCFABuilder {
SSAContextInterpreter contextInterpreter = makeDefaultContextInterpreters(appContextInterpreter, options, cha);
setContextInterpreter(contextInterpreter);
ContextSelector def = new DefaultContextSelector(options);
ContextSelector def = new DefaultContextSelector(options, cha);
ContextSelector contextSelector = appContextSelector == null ? def : new DelegatingContextSelector(appContextSelector, def);
setContextSelector(contextSelector);

View File

@ -74,7 +74,7 @@ public class JavaCAst2IRTranslator extends AstTranslator {
}
protected TypeReference defaultCatchType() {
return TypeReference.JavaLangException;
return TypeReference.JavaLangThrowable;
}
protected TypeReference makeType(CAstType type) {

View File

@ -0,0 +1,14 @@
package com.ibm.wala.cast.js.test;
import org.junit.Before;
import com.ibm.wala.cast.js.translator.CAstRhinoTranslatorFactory;
public class TestForInLoopHackRhino extends TestForInLoopHack {
@Before
public void setUp() {
com.ibm.wala.cast.js.ipa.callgraph.Util.setTranslatorFactory(new CAstRhinoTranslatorFactory());
}
}

View File

@ -1,6 +1,6 @@
(function () {
(function _top_level () {
var jQuery = window.jQuery = window.$ = function (selector, context) {
@ -10,7 +10,7 @@
var undefined;
jQuery.extend = jQuery.fn.extend = function () {
jQuery.extend = jQuery.fn.extend = function _extend () {
var target = arguments[0] || {},
i = 1,
length = arguments.length,
@ -26,21 +26,24 @@
target = this;
--i;
}
for (; i < length; i++) if ((options = arguments[i]) != null) for (var name in options) {
var src = target[name],
copy = options[name];
if (target === copy) continue;
if (deep && copy && typeof copy == "object" && !copy.nodeType) {
target[name] = jQuery.extend(deep, src || (copy.length != null ? [] : {}), copy);
}
else if (copy !== undefined) target[name] = copy;
// else target[name] = copy;
for (; i < length; i++) if ((options = arguments[i]) != null)
for (var name in options) {
(function _forin_body (name) {
var src = target[name],
copy = options[name];
if (target === copy) return;
if (deep && copy && typeof copy == "object" && !copy.nodeType) {
target[name] = jQuery.extend(deep, src || (copy.length != null ? [] : {}), copy);
}
else if (copy !== undefined) target[name] = copy;
else target[name] = copy;
})(name);
}
return target;
};
jQuery.extend({
speed: function (speed, easing, fn) {
speed: function _speed (speed, easing, fn) {
var opt = speed && speed.constructor == Object ? speed : {
complete: fn || !fn && easing || jQuery.isFunction(speed) && speed,
duration: speed,
@ -48,7 +51,7 @@
};
opt.duration = (opt.duration && opt.duration.constructor == Number ? opt.duration : jQuery.fx.speeds[opt.duration]) || jQuery.fx.speeds.def;
opt.old = opt.complete;
opt.complete = function () {
opt.complete = function _complete () {
if (opt.queue !== false) jQuery(this).dequeue();
if (jQuery.isFunction(opt.old)) opt.old.call(this);
};

View File

@ -0,0 +1,33 @@
function copyObj(to, from) {
for(var p in from) {
(function _forin_body (name) {
to[name] = from[name];
})(p);
}
}
function testForIn( x ) {
var z;
for(var y in x) {
if (y in x) {
z = (x[y])();
}
}
}
var obj = {
foo: function testForIn1() { return 7; },
bar: function testForIn2() { return "whatever"; }
}
testForIn(obj);
(function _check_obj_foo () { obj.foo(); })();
(function _check_obj_bar () { obj.bar(); })();
var copy = new Object();
copyObj(copy, obj);
(function _check_copy_foo () { copy.foo(); })();
(function _check_copy_bar () { copy.bar(); })();

View File

@ -0,0 +1,137 @@
package com.ibm.wala.cast.js.test;
import java.io.IOException;
import java.net.URL;
import org.junit.Before;
import org.junit.Test;
import com.ibm.wala.cast.js.html.JSSourceExtractor;
import com.ibm.wala.cast.js.ipa.callgraph.JSCFABuilder;
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.CallGraph;
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.FilteredPointerKey;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.util.CancelException;
import com.ibm.wala.util.intset.IntSet;
import com.ibm.wala.util.intset.IntSetUtil;
public class TestForInLoopHack extends TestJSCallGraphShape {
@Before
public void config() {
JSSourceExtractor.USE_TEMP_NAME = false;
JSSourceExtractor.DELETE_UPON_EXIT = false;
}
@Test public void testPage3WithoutHack() throws IOException, IllegalArgumentException, CancelException {
URL url = getClass().getClassLoader().getResource("pages/page3.html");
JSCFABuilder builder = Util.makeHTMLCGBuilder(url);
CallGraph CG = builder.makeCallGraph(builder.getOptions());
Util.dumpCG(builder, CG);
}
@Test public void testPage3WithHack() throws IOException, IllegalArgumentException, CancelException {
URL url = getClass().getClassLoader().getResource("pages/page3.html");
JSCFABuilder builder = Util.makeHTMLCGBuilder(url);
addHackedForInLoopSensitivity(builder);
CallGraph CG = builder.makeCallGraph(builder.getOptions());
Util.dumpCG(builder, CG);
}
private static final Object[][] assertionsForBadForin = new Object[][] {
new Object[] { ROOT,
new String[] { "tests/badforin.js" } },
new Object[] { "tests/badforin.js",
new String[] { "tests/badforin.js/testForIn", "tests/badforin.js/_check_obj_foo", "tests/badforin.js/_check_obj_bar", "tests/badforin.js/_check_copy_foo", "tests/badforin.js/_check_copy_bar"} },
new Object[] { "tests/badforin.js/testForIn",
new String[] { "tests/badforin.js/testForIn1", "tests/badforin.js/testForIn2" } },
new Object[] { "tests/badforin.js/_check_obj_foo",
new String[] { "tests/badforin.js/testForIn1" } },
new Object[] { "tests/badforin.js/_check_copy_foo",
new String[] { "tests/badforin.js/testForIn1" } },
new Object[] { "tests/badforin.js/_check_obj_bar",
new String[] { "tests/badforin.js/testForIn2" } },
new Object[] { "tests/badforin.js/_check_copy_bar",
new String[] { "tests/badforin.js/testForIn2" } }
};
@Test public void testBadForInWithoutHack() throws IOException, IllegalArgumentException, CancelException {
JSCFABuilder B = Util.makeScriptCGBuilder("tests", "badforin.js");
CallGraph CG = B.makeCallGraph(B.getOptions());
Util.dumpCG(B, CG);
verifyGraphAssertions(CG, assertionsForBadForin);
}
private static final Object[][] assertionsForBadForinHackPrecision = new Object[][] {
new Object[] { "tests/badforin.js/_check_obj_foo",
new String[] { "!tests/badforin.js/testForIn2" } },
new Object[] { "tests/badforin.js/_check_copy_foo",
new String[] { "!tests/badforin.js/testForIn2" } },
new Object[] { "tests/badforin.js/_check_obj_bar",
new String[] { "!tests/badforin.js/testForIn1" } },
new Object[] { "tests/badforin.js/_check_copy_bar",
new String[] { "!tests/badforin.js/testForIn1" } }
};
@Test public void testBadForInWithHack() throws IOException, IllegalArgumentException, CancelException {
JSCFABuilder B = Util.makeScriptCGBuilder("tests", "badforin.js");
addHackedForInLoopSensitivity(B);
CallGraph CG = B.makeCallGraph(B.getOptions());
Util.dumpCG(B, CG);
verifyGraphAssertions(CG, assertionsForBadForin);
verifyGraphAssertions(CG, assertionsForBadForinHackPrecision);
}
private void addHackedForInLoopSensitivity(JSCFABuilder builder) {
final ContextSelector orig = builder.getContextSelector();
builder.setContextSelector(new ContextSelector() {
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, final InstanceKey[] receiver) {
final Context origContext = orig.getCalleeTarget(caller, site, callee, receiver);
if (callee.getDeclaringClass().getName().toString().contains("_forin_body")) {
class ForInContext implements Context {
private final InstanceKey obj = receiver[2];
public ContextItem get(ContextKey name) {
if (name.equals(ContextKey.PARAMETERS[2])) {
return new FilteredPointerKey.SingleInstanceFilter(obj);
} else {
return origContext.get(name);
}
}
@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 new ForInContext();
} else {
return origContext;
}
}
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
if (caller.getIR().getCalls(site)[0].getNumberOfUses() > 2) {
return IntSetUtil.make(new int[]{2}).union(orig.getRelevantParameters(caller, site));
} else {
return orig.getRelevantParameters(caller, site);
}
}
});
}
}

View File

@ -136,9 +136,9 @@ public abstract class TestSimpleCallGraphShape extends TestJSCallGraphShape {
"tests/simple-lexical.js/outer",
new String[] { "tests/simple-lexical.js/outer/indirect", "tests/simple-lexical.js/outer/inner",
"tests/simple-lexical.js/outer/inner2", "tests/simple-lexical.js/outer/inner3" } },
new Object[] { "tests/simple-lexical.js/outer/indirect",
new String[] { "tests/simple-lexical.js/outer/inner", "tests/simple-lexical.js/outer/inner3" } },
new Object[] { "tests/simple-lexical.js/outer/inner2",
new String[] { "tests/simple-lexical.js/outer/inner", "tests/simple-lexical.js/outer/inner3" } },
new Object[] { "tests/simple-lexical.js/outer/indirect",
new String[] { "tests/simple-lexical.js/outer/inner", "tests/simple-lexical.js/outer/inner3" } } };
@Test public void testSimpleLexical() throws IOException, IllegalArgumentException, CancelException {
@ -277,10 +277,6 @@ public abstract class TestSimpleCallGraphShape extends TestJSCallGraphShape {
// all we need is for it to finish building CG successfully.
}
// @Test public void testCalls() throws IOException, IllegalArgumentException, CancelException {
// CallGraph CG = Util.makeScriptCG("tests", "calls.js");
// }
protected IVector<Set<Pair<CGNode, Integer>>> computeIkIdToVns(PointerAnalysis pa) {
// Created by reversing the points to mapping for local pointer keys.

View File

@ -29,9 +29,6 @@ import com.ibm.wala.cast.js.ssa.JavaScriptWithRegion;
import com.ibm.wala.cast.js.types.JavaScriptTypes;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.fixpoint.AbstractOperator;
import com.ibm.wala.fixpoint.IVariable;
import com.ibm.wala.fixpoint.IntSetVariable;
import com.ibm.wala.fixpoint.UnaryOperator;
import com.ibm.wala.ipa.callgraph.AnalysisCache;
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
import com.ibm.wala.ipa.callgraph.CGNode;
@ -55,13 +52,12 @@ import com.ibm.wala.shrikeBT.BinaryOpInstruction;
import com.ibm.wala.shrikeBT.IUnaryOpInstruction;
import com.ibm.wala.ssa.DefUse;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
import com.ibm.wala.ssa.SSABinaryOpInstruction;
import com.ibm.wala.ssa.SSAUnaryOpInstruction;
import com.ibm.wala.ssa.SymbolTable;
import com.ibm.wala.util.collections.HashSetFactory;
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;
public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraphBuilder {
@ -251,13 +247,13 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
//
// ///////////////////////////////////////////////////////////////////////////
protected ConstraintVisitor makeVisitor(ExplicitCallGraph.ExplicitNode node) {
protected JSConstraintVisitor makeVisitor(CGNode node) {
return new JSConstraintVisitor(this, node);
}
public static class JSConstraintVisitor extends AstConstraintVisitor implements InstructionVisitor {
public JSConstraintVisitor(AstSSAPropagationCallGraphBuilder builder, ExplicitCallGraph.ExplicitNode node) {
public JSConstraintVisitor(AstSSAPropagationCallGraphBuilder builder, CGNode node) {
super(builder, node);
}
@ -326,200 +322,7 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
}
public void visitJavaScriptInvoke(JavaScriptInvoke instruction) {
PointerKey F = getPointerKeyForLocal(instruction.getFunction());
InstanceKey[][] consts = computeInvariantParameters(instruction);
PointerKey uniqueCatch = null;
if (hasUniqueCatchBlock(instruction, ir)) {
uniqueCatch = getBuilder().getUniqueCatchKey(instruction, ir, node);
}
if (contentsAreInvariant(symbolTable, du, instruction.getFunction())) {
system.recordImplicitPointsToSet(F);
InstanceKey[] ik = getInvariantContents(instruction.getFunction());
for (int i = 0; i < ik.length; i++) {
system.findOrCreateIndexForInstanceKey(ik[i]);
CGNode n = getTargetForCall(node, instruction.getCallSite(), ik[i]);
if (n != null) {
processJSCall(node, instruction, n, ik[i], consts, uniqueCatch);
}
}
} else {
system.newSideEffect(new JSDispatchOperator(instruction, node, consts, uniqueCatch), F);
}
}
// ///////////////////////////////////////////////////////////////////////////
//
// function call handling
//
// ///////////////////////////////////////////////////////////////////////////
class JSDispatchOperator extends UnaryOperator<PointsToSetVariable> {
private final JavaScriptInvoke call;
private final ExplicitCallGraph.ExplicitNode node;
private final InstanceKey[][] constParams;
private final PointerKey uniqueCatch;
public boolean isLoadOperator() {
return false;
}
public String toString() {
return "JSDispatch of " + call.getCallSite();
}
public int hashCode() {
return call.getCallSite().hashCode() * node.hashCode();
}
public boolean equals(Object o) {
return (o instanceof JSDispatchOperator) && ((JSDispatchOperator) o).node.equals(node)
&& ((JSDispatchOperator) o).call.equals(call);
}
/**
* @param call
* @param node
*/
JSDispatchOperator(JavaScriptInvoke call, ExplicitCallGraph.ExplicitNode node, InstanceKey[][] constParams,
PointerKey uniqueCatch) {
this.call = call;
this.node = node;
this.constParams = constParams;
this.uniqueCatch = uniqueCatch;
}
private MutableIntSet previousReceivers = IntSetUtil.getDefaultIntSetFactory().make();
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) {
final IntSetVariable receivers = (IntSetVariable) rhs;
if (receivers.getValue() != null) {
receivers.getValue().foreachExcluding(previousReceivers, new IntSetAction() {
public void act(int ptr) {
InstanceKey iKey = system.getInstanceKey(ptr);
CGNode target = getTargetForCall(node, call.getCallSite(), iKey);
if (target != null) {
processJSCall(node, call, target, iKey, constParams, uniqueCatch);
if (!getBuilder().haveAlreadyVisited(target)) {
getBuilder().markDiscovered(target);
}
}
}
});
previousReceivers.addAll(receivers.getValue());
}
return NOT_CHANGED;
};
}
@SuppressWarnings("deprecation")
void processJSCall(CGNode caller, JavaScriptInvoke instruction, CGNode target, InstanceKey function,
InstanceKey constParams[][], PointerKey uniqueCatchKey) {
caller.addTarget(instruction.getCallSite(), target);
if (!getBuilder().haveAlreadyVisited(target)) {
getBuilder().markDiscovered(target);
}
IR sourceIR = getBuilder().getCFAContextInterpreter().getIR(caller);
SymbolTable sourceST = sourceIR.getSymbolTable();
IR targetIR = getBuilder().getCFAContextInterpreter().getIR(target);
SymbolTable targetST = targetIR.getSymbolTable();
int av = -1;
for (int v = 0; v <= targetST.getMaxValueNumber(); v++) {
String[] vns = targetIR.getLocalNames(1, v);
for (int n = 0; vns != null && n < vns.length; n++) {
if ("arguments".equals(vns[n])) {
av = v;
break;
}
}
}
int paramCount = targetST.getParameterValueNumbers().length;
int argCount = instruction.getNumberOfParameters();
// pass actual arguments to formals in the normal way
for (int i = 0; i < Math.min(paramCount, argCount); i++) {
int fn = targetST.getConstant(i);
PointerKey F = (i == 0) ? getBuilder().getFilteredPointerKeyForLocal(target, targetST.getParameter(i), function.getConcreteType())
: getBuilder().getPointerKeyForLocal(target, targetST.getParameter(i));
if (constParams != null && constParams[i] != null) {
for (int j = 0; j < constParams[i].length; j++) {
system.newConstraint(F, constParams[i][j]);
}
if (av != -1)
newFieldWrite(target, av, fn, constParams[i]);
} else {
PointerKey A = getBuilder().getPointerKeyForLocal(caller, instruction.getUse(i));
system.newConstraint(F, (F instanceof FilteredPointerKey) ? getBuilder().filterOperator : assignOperator, A);
if (av != -1)
newFieldWrite(target, av, fn, F);
}
}
// extra actual arguments get assigned into the ``arguments'' object
if (paramCount < argCount) {
if (av != -1) {
for (int i = paramCount; i < argCount; i++) {
int fn = targetST.getConstant(i);
if (constParams != null && constParams[i] != null) {
newFieldWrite(target, av, fn, constParams[i]);
} else {
PointerKey A = getBuilder().getPointerKeyForLocal(caller, instruction.getUse(i));
newFieldWrite(target, av, fn, A);
}
}
}
}
// extra formal parameters get null (extra args are ignored here)
else if (argCount < paramCount) {
int nullvn = sourceST.getNullConstant();
DefUse sourceDU = getBuilder().getCFAContextInterpreter().getDU(caller);
InstanceKey[] nullkeys = getInvariantContents(sourceST, sourceDU, caller, nullvn);
for (int i = argCount; i < paramCount; i++) {
PointerKey F = getBuilder().getPointerKeyForLocal(target, targetST.getParameter(i));
for (int k = 0; k < nullkeys.length; k++) {
system.newConstraint(F, nullkeys[k]);
}
}
}
// write `length' in argument objects
if (av != -1) {
int svn = targetST.getConstant(argCount);
int lnv = targetST.getConstant("length");
newFieldWrite(target, av, lnv, svn);
}
// return values
if (instruction.getDef(0) != -1) {
PointerKey RF = getBuilder().getPointerKeyForReturnValue(target);
PointerKey RA = getBuilder().getPointerKeyForLocal(caller, instruction.getDef(0));
system.newConstraint(RA, assignOperator, RF);
}
PointerKey EF = getBuilder().getPointerKeyForExceptionalReturnValue(target);
if (SHORT_CIRCUIT_SINGLE_USES && uniqueCatchKey != null) {
// e has exactly one use. so, represent e implicitly
system.newConstraint(uniqueCatchKey, assignOperator, EF);
} else {
PointerKey EA = getBuilder().getPointerKeyForLocal(caller, instruction.getDef(1));
system.newConstraint(EA, assignOperator, EF);
}
visitInvokeInternal(instruction);
}
// ///////////////////////////////////////////////////////////////////////////
@ -600,7 +403,7 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
}
}
public byte evaluate(PointsToSetVariable lhs, final IVariable[] rhs) {
public byte evaluate(PointsToSetVariable lhs, final PointsToSetVariable[] rhs) {
boolean doDefault = false;
byte changed = NOT_CHANGED;
@ -679,4 +482,111 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
}
}
/////////////////////////////////////////////////////////////////////////////
//
// function call handling
//
////////////////////////////////////////////////////////////////////////////
@Override
protected void processCallingConstraints(CGNode caller, SSAAbstractInvokeInstruction instruction, CGNode target,
InstanceKey[][] constParams, PointerKey uniqueCatchKey) {
IR sourceIR = getCFAContextInterpreter().getIR(caller);
SymbolTable sourceST = sourceIR.getSymbolTable();
IR targetIR = getCFAContextInterpreter().getIR(target);
SymbolTable targetST = targetIR.getSymbolTable();
JSConstraintVisitor targetVisitor = null;
int av = -1;
for (int v = 0; v <= targetST.getMaxValueNumber(); v++) {
String[] vns = targetIR.getLocalNames(1, v);
for (int n = 0; vns != null && n < vns.length; n++) {
if ("arguments".equals(vns[n])) {
av = v;
targetVisitor = makeVisitor(target);
break;
}
}
}
int paramCount = targetST.getParameterValueNumbers().length;
int argCount = instruction.getNumberOfParameters();
// pass actual arguments to formals in the normal way
for (int i = 0; i < Math.min(paramCount, argCount); i++) {
int fn = targetST.getConstant(i);
PointerKey F = getTargetPointerKey(target, i);
if (constParams != null && constParams[i] != null) {
for (int j = 0; j < constParams[i].length; j++) {
system.newConstraint(F, constParams[i][j]);
}
if (av != -1)
targetVisitor.newFieldWrite(target, av, fn, constParams[i]);
} else {
PointerKey A = getPointerKeyForLocal(caller, instruction.getUse(i));
system.newConstraint(F, (F instanceof FilteredPointerKey) ? filterOperator : assignOperator, A);
if (av != -1)
targetVisitor.newFieldWrite(target, av, fn, F);
}
}
// extra actual arguments get assigned into the ``arguments'' object
if (paramCount < argCount) {
if (av != -1) {
for (int i = paramCount; i < argCount; i++) {
int fn = targetST.getConstant(i);
if (constParams != null && constParams[i] != null) {
targetVisitor.newFieldWrite(target, av, fn, constParams[i]);
} else {
PointerKey A = getPointerKeyForLocal(caller, instruction.getUse(i));
targetVisitor.newFieldWrite(target, av, fn, A);
}
}
}
}
// extra formal parameters get null (extra args are ignored here)
else if (argCount < paramCount) {
int nullvn = sourceST.getNullConstant();
DefUse sourceDU = getCFAContextInterpreter().getDU(caller);
InstanceKey[] nullkeys = getInvariantContents(sourceST, sourceDU, caller, nullvn, this);
for (int i = argCount; i < paramCount; i++) {
PointerKey F = getPointerKeyForLocal(target, targetST.getParameter(i));
for (int k = 0; k < nullkeys.length; k++) {
system.newConstraint(F, nullkeys[k]);
}
}
}
// write `length' in argument objects
if (av != -1) {
int svn = targetST.getConstant(argCount);
int lnv = targetST.getConstant("length");
targetVisitor.newFieldWrite(target, av, lnv, svn);
}
// return values
if (instruction.getDef(0) != -1) {
PointerKey RF = getPointerKeyForReturnValue(target);
PointerKey RA = getPointerKeyForLocal(caller, instruction.getDef(0));
system.newConstraint(RA, assignOperator, RF);
}
PointerKey EF = getPointerKeyForExceptionalReturnValue(target);
if (SHORT_CIRCUIT_SINGLE_USES && uniqueCatchKey != null) {
// e has exactly one use. so, represent e implicitly
system.newConstraint(uniqueCatchKey, assignOperator, EF);
} else {
PointerKey EA = getPointerKeyForLocal(caller, instruction.getDef(1));
system.newConstraint(EA, assignOperator, EF);
}
}
}

View File

@ -38,7 +38,7 @@ public class JSZeroOrOneXCFABuilder extends JSCFABuilder {
options.setSelector(new JavaScriptConstructTargetSelector(cha, options.getMethodTargetSelector()));
options.setSelector(new LoadFileTargetSelector(options.getMethodTargetSelector(), this));
ContextSelector def = new DefaultContextSelector(options);
ContextSelector def = new DefaultContextSelector(options, cha);
ContextSelector contextSelector = appContextSelector == null ? def : new DelegatingContextSelector(appContextSelector, def);
contextSelector = new ScopeMappingKeysContextSelector(contextSelector);
contextSelector = new JavaScriptConstructorContextSelector(contextSelector);

View File

@ -8,6 +8,7 @@ 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.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.util.intset.IntSet;
public class JavaScriptConstructorContextSelector implements ContextSelector {
private final ContextSelector base;
@ -16,7 +17,13 @@ public class JavaScriptConstructorContextSelector implements ContextSelector {
this.base = base;
}
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
return base.getRelevantParameters(caller, site);
}
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) {
if (callee instanceof JavaScriptConstructor && caller.getContext() instanceof ScopeMappingContext) {
return caller.getContext();
} else {

View File

@ -48,4 +48,20 @@ public class JSCallSiteReference extends CallSiteReference {
return new JSCallSiteReference(pc);
}
@Override
public boolean isDispatch() {
return true;
}
@Override
public boolean isStatic() {
return false;
}
@Override
public boolean isFixed() {
return false;
}
}

View File

@ -727,7 +727,11 @@ public class JavaScriptLoader extends CAstAbstractModuleLoader {
}
public TypeReference getParameterType(int i) {
return JavaScriptTypes.Root;
if (i == 0) {
return getDeclaringClass().getReference();
} else {
return JavaScriptTypes.Root;
}
}
}

View File

@ -122,27 +122,40 @@ public abstract class TestCallGraphShape extends WalaTestCase {
Assert.assertTrue("cannot find " + assertionData[i][0], srcs.hasNext());
while (srcs.hasNext()) {
boolean checkAbsence = false;
String targetName = ((String[]) assertionData[i][1])[j];
if (targetName.startsWith("!")) {
checkAbsence = true;
targetName = targetName.substring(1);
}
check_edges: while (srcs.hasNext()) {
CGNode src = (CGNode) srcs.next();
for (Iterator sites = src.iterateCallSites(); sites.hasNext();) {
CallSiteReference sr = (CallSiteReference) sites.next();
Iterator dsts = getNodes(CG, ((String[]) assertionData[i][1])[j]).iterator();
Assert.assertTrue("cannot find " + ((String[]) assertionData[i][1])[j], dsts.hasNext());
Iterator dsts = getNodes(CG, targetName).iterator();
Assert.assertTrue("cannot find " + targetName, dsts.hasNext());
while (dsts.hasNext()) {
CGNode dst = (CGNode) dsts.next();
for (Iterator tos = CG.getPossibleTargets(src, sr).iterator(); tos.hasNext();) {
if (tos.next().equals(dst)) {
System.err.println(("found expected " + src + " --> " + dst + " at " + sr));
continue check_target;
if (checkAbsence) {
System.err.println(("found unexpected " + src + " --> " + dst + " at " + sr));
Assert.assertTrue("found edge " + assertionData[i][0] + " ---> " + targetName, false);
} else {
System.err.println(("found expected " + src + " --> " + dst + " at " + sr));
continue check_target;
}
}
}
}
}
}
Assert.assertTrue("cannot find edge " + assertionData[i][0] + " ---> " + ((String[]) assertionData[i][1])[j], false);
System.err.println("cannot find edge " + assertionData[i][0] + " ---> " + targetName);
Assert.assertTrue("cannot find edge " + assertionData[i][0] + " ---> " + targetName, checkAbsence);
}
}
}

View File

@ -151,6 +151,10 @@ public class AstCallGraph extends ExplicitCallGraph {
cachedDU = new DefUse(ir);
}
public void clearMutatedCache(CallSiteReference cs) {
targets.remove(cs.getProgramCounter());
}
public IR getLexicallyMutatedIR() {
if (lexicalScopingChanges) {
return cachedIR;

View File

@ -39,7 +39,6 @@ import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.fixpoint.AbstractOperator;
import com.ibm.wala.fixpoint.IVariable;
import com.ibm.wala.fixpoint.IntSetVariable;
import com.ibm.wala.fixpoint.UnaryOperator;
import com.ibm.wala.ipa.callgraph.AnalysisCache;
@ -64,6 +63,8 @@ import com.ibm.wala.ipa.callgraph.propagation.cfa.DelegatingSSAContextInterprete
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.ssa.DefUse;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.ssa.SSAPutInstruction;
import com.ibm.wala.ssa.SymbolTable;
import com.ibm.wala.util.collections.EmptyIterator;
@ -263,7 +264,7 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
private final CallGraph cg;
public AstConstraintVisitor(AstSSAPropagationCallGraphBuilder builder, ExplicitCallGraph.ExplicitNode node) {
public AstConstraintVisitor(AstSSAPropagationCallGraphBuilder builder, CGNode node) {
super(builder, node);
this.cg = builder.callGraph;
}
@ -502,6 +503,30 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
}
protected void visitInvokeInternal(final SSAAbstractInvokeInstruction instruction) {
super.visitInvokeInternal(instruction);
if (instruction instanceof AbstractLexicalInvoke) {
AbstractLexicalInvoke I = (AbstractLexicalInvoke) instruction;
for(int wi = 0; wi < I.getNumberOfDefs(); wi++) {
if (I.isLexicalDef(wi)) {
Access w = I.getLexicalDef(wi);
for(int ri = 0; ri < I.getNumberOfUses(); ri++) {
if (I.isLexicalUse(ri)) {
Access r = I.getLexicalUse(ri);
if (w.variableName.equals(r.variableName)) {
if (w.variableDefiner==null? r.variableDefiner==null: w.variableDefiner.equals(r.variableDefiner)) {
PointerKey rk = getBuilder().getPointerKeyForLocal(node, r.valueNumber);
PointerKey wk = getBuilder().getPointerKeyForLocal(node, w.valueNumber);
system.newConstraint(wk, assignOperator, rk);
}
}
}
}
}
}
}
}
// /////////////////////////////////////////////////////////////////////////
//
// lexical scoping handling
@ -835,17 +860,48 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
if (values[i] == -1)
return null;
// find calls that may be altered, and clear their caches
DefUse newDU = getAnalysisCache().getSSACache().findOrCreateDU(ir, n.getContext());
Iterator<SSAInstruction> insts = newDU.getUses(values[i]);
while(insts.hasNext()) {
SSAInstruction inst = insts.next();
if (inst instanceof SSAAbstractInvokeInstruction) {
System.err.println("clearing for " + inst);
CallSiteReference cs = ((SSAAbstractInvokeInstruction)inst).getCallSite();
((AstCallGraph.AstCGNode)n).clearMutatedCache(cs);
}
}
// if values[i] was altered by copy propagation, we must undo
// that to ensure we do not bash the wrong value number in the
// the next steps.
SSAConversion.undoCopyPropagation(ir, pc, -i - 1);
// possibly new instruction due to renames, so get it again
I = (AbstractLexicalInvoke) ir.getInstructions()[pc];
// we assume that the callee might not necessarily write,
// so the call becomes like a phi node. hence it needs a
// read of the old value
ensureRead: {
for(int l = 0; l < I.getNumberOfUses(); l++) {
if (I.isLexicalUse(l)) {
Access r = I.getLexicalUse(l);
if (name.equals(r.variableName)) {
if (definer==null? r.variableDefiner == null: definer.equals(r.variableDefiner)) {
break ensureRead;
}
}
}
}
I.addLexicalUse(new Access(name, definer, values[i]));
}
// add new lexical definition
I.addLexicalDef(new Access(name, definer, values[i]));
if (SSAConversion.DEBUG_UNDO)
System.err.println(("new def of " + values[i] + " at inst " + pc + ": " + I));
System.err.println("new def of " + values[i] + " at inst " + pc + ": " + I);
// new def has broken SSA form for values[i], so fix for that
// value
@ -853,14 +909,13 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
vs.add(values[i]);
SSAConversion.convert(AstM, ir, getOptions().getSSAOptions());
// now redo analysis
// force analysis to be redone
// TODO: only values[i] uses need to be re-done.
ir.lexicalInfo().handleAlteration();
((AstCallGraph.AstCGNode)n).setLexicallyMutatedIR(ir);
getAnalysisCache().getSSACache().invalidateDU(M, n.getContext());
// addConstraintsFromChangedNode(n);
getBuilder().markChanged(n);
// get SSA-renamed def from call site instruction
return getLocalWriteKey(n, callSite, name, definer, definingNode);
}
@ -1070,7 +1125,7 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
} else {
system.newSideEffect(new AbstractOperator<PointsToSetVariable>() {
public byte evaluate(PointsToSetVariable lhs, final IVariable[] rhs) {
public byte evaluate(PointsToSetVariable lhs, final PointsToSetVariable[] rhs) {
final IntSetVariable receivers = (IntSetVariable) rhs[0];
final IntSetVariable fields = (IntSetVariable) rhs[1];
if (receivers.getValue() != null && fields.getValue() != null) {
@ -1124,7 +1179,7 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
}
}
protected void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, int rhsVn) {
public void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, int rhsVn) {
IR ir = getBuilder().getCFAContextInterpreter().getIR(opNode);
SymbolTable symtab = ir.getSymbolTable();
DefUse du = getBuilder().getCFAContextInterpreter().getDU(opNode);
@ -1137,7 +1192,7 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
}
}
protected void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, final InstanceKey[] rhsFixedValues) {
public void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, final InstanceKey[] rhsFixedValues) {
try {
newFieldOperation(opNode, objVn, fieldsVn, false, new ReflectedFieldAction() {
@ -1165,7 +1220,7 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
}
}
protected void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, final PointerKey rhs) {
public void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, final PointerKey rhs) {
newFieldOperation(opNode, objVn, fieldsVn, false, new ReflectedFieldAction() {
public void dump(AbstractFieldPointerKey fieldKey, boolean constObj, boolean constProp) {
System.err.println(("write " + rhs + " to " + fieldKey + " " + constObj + ", " + constProp));

View File

@ -18,6 +18,7 @@ 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.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.util.intset.IntSet;
import com.ibm.wala.util.strings.Atom;
/**
@ -52,7 +53,11 @@ public class CrossLanguageContextSelector implements ContextSelector {
return (ContextSelector)languageSelectors.get(getLanguage(site));
}
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) {
return getSelector(site).getCalleeTarget(caller, site, callee, receiver);
}
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
return getSelector(site).getRelevantParameters(caller, site);
}
}

View File

@ -30,6 +30,7 @@ import com.ibm.wala.types.TypeName;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.intset.IntSet;
import com.ibm.wala.util.strings.Atom;
public class MiscellaneousHacksContextSelector implements ContextSelector {
@ -107,7 +108,7 @@ public class MiscellaneousHacksContextSelector implements ContextSelector {
System.err.println(("hacking context selector for methods " + methodsToSpecialize));
}
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) {
if (methodsToSpecialize.contains(site.getDeclaredTarget()) || methodsToSpecialize.contains(callee.getReference())) {
return specialPolicy.getCalleeTarget(caller, site, callee, receiver);
} else {
@ -115,15 +116,8 @@ public class MiscellaneousHacksContextSelector implements ContextSelector {
}
}
public int getBoundOnNumberOfTargets(CGNode caller, CallSiteReference reference, IMethod targetMethod) {
return -1;
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
return specialPolicy.getRelevantParameters(caller, site).union(basePolicy.getRelevantParameters(caller, site));
}
public boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) {
return true;
}
public boolean allSitesDispatchIdentically(CGNode node, CallSiteReference site) {
return false;
}
}
}

View File

@ -26,6 +26,9 @@ public abstract class ReflectedFieldPointerKey extends AbstractFieldPointerKey {
};
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof ReflectedFieldPointerKey) {
ReflectedFieldPointerKey other = (ReflectedFieldPointerKey) obj;
return
@ -37,11 +40,11 @@ public abstract class ReflectedFieldPointerKey extends AbstractFieldPointerKey {
}
public int hashCode() {
return getFieldIdentifier().hashCode();
return getFieldIdentifier().hashCode() ^ getInstanceKey().hashCode();
}
public String toString() { return "field:" + getFieldIdentifier(); }
public static ReflectedFieldPointerKey literal(final String lit, InstanceKey instance) {
return new ReflectedFieldPointerKey(instance) {
public Object getFieldIdentifier() {

View File

@ -21,12 +21,13 @@ import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.classLoader.ProgramCounter;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKeyFactory;
import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.graph.impl.GraphInverter;
import com.ibm.wala.util.graph.traverse.DFS;
/**
* An {@link InstanceKeyFactory} that returns {@link ScopeMappingInstanceKey}s as necessary to handle interprocedural lexical
@ -60,6 +61,27 @@ abstract public class ScopeMappingInstanceKeys implements InstanceKeyFactory {
private static final long serialVersionUID = 3645910671551712906L;
private void scan(int level, int toDo, LexicalParent parents[], CGNode node, Set<CGNode> parentNodes) {
Iterator<CGNode> preds = DFS.iterateDiscoverTime(GraphInverter.invert(builder.getCallGraph()), node);
while (preds.hasNext()) {
CGNode pred = preds.next();
for (int i = 0; i < parents.length; i++) {
if (parents[i] != null) {
if (pred.getMethod() == parents[i].getMethod()) {
if (containsKey(parents[i].getName()))
assert get(parents[i].getName()) == pred;
else {
toDo--;
put(parents[i].getName(), pred);
if (AstTranslator.DEBUG_LEXICAL)
System.err.println((level + ": Adding lexical parent " + parents[i].getName() + " for " + base + " at " + creator
+ "(toDo is now " + toDo + ")"));
}
}
}
}
}
/*
if (toDo > 0) {
int restoreIndex = -1;
LexicalParent restoreParent = null;
@ -109,6 +131,7 @@ abstract public class ScopeMappingInstanceKeys implements InstanceKeyFactory {
parents[restoreIndex] = restoreParent;
}
}
*/
}
private ScopeMap() {

View File

@ -9,6 +9,8 @@ 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.util.intset.IntSet;
import com.ibm.wala.util.intset.IntSetUtil;
public class ScopeMappingKeysContextSelector implements ContextSelector {
@ -59,12 +61,20 @@ public class ScopeMappingKeysContextSelector implements ContextSelector {
this.base = base;
}
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) {
Context bc = base.getCalleeTarget(caller, site, callee, receiver);
if (receiver instanceof ScopeMappingInstanceKey) {
return new ScopeMappingContext(bc, (ScopeMappingInstanceKey) receiver);
if (receiver[0] instanceof ScopeMappingInstanceKey) {
return new ScopeMappingContext(bc, (ScopeMappingInstanceKey) receiver[0]);
} else {
return bc;
}
}
private static final IntSet thisParameter = IntSetUtil.make(new int[]{0});
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
return thisParameter;
}
}

View File

@ -109,7 +109,7 @@ public abstract class AbstractLexicalInvoke extends MultiReturnValueInvokeInstru
}
public boolean isLexicalUse(int use) {
return use >= super.getNumberOfUses();
return use >= getNumberOfParameters();
}
public void addLexicalUse(Access use) {

View File

@ -135,6 +135,7 @@ public class CFGTest extends WalaTestCase {
IMethod m = cha.resolveMethod(mr);
AnalysisCache cache = new AnalysisCache();
IR ir = cache.getIR(m);
System.out.println(ir);
SSACFG controlFlowGraph = ir.getControlFlowGraph();
Assert.assertEquals(1, controlFlowGraph.getSuccNodeCount(controlFlowGraph.getBlockForInstruction(21)));
}
@ -164,4 +165,14 @@ public class CFGTest extends WalaTestCase {
SSACFG controlFlowGraph = ir.getControlFlowGraph();
Assert.assertEquals(1, controlFlowGraph.getSuccNodeCount(controlFlowGraph.getBlockForInstruction(33)));
}
public static void testCFG(SSACFG cfg, int[][] assertions) {
for(int i = 0; i < assertions.length; i++) {
SSACFG.BasicBlock bb= cfg.getNode(i);
Assert.assertEquals("basic block " + i, assertions[i].length, cfg.getSuccNodeCount(bb));
for(int j = 0; j < assertions[i].length; j++) {
Assert.assertTrue(cfg.hasEdge(bb, cfg.getNode(assertions[i][j])));
}
}
}
}

View File

@ -71,7 +71,7 @@ public class ClassFactoryContextInterpreter implements SSAContextInterpreter {
if (!(node.getContext() instanceof JavaTypeContext)) {
return false;
}
return ClassFactoryContextSelector.isClassFactory(node.getMethod());
return ClassFactoryContextSelector.isClassFactory(node.getMethod().getReference());
}
/*

View File

@ -26,6 +26,9 @@ import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.Descriptor;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.intset.EmptyIntSet;
import com.ibm.wala.util.intset.IntSet;
import com.ibm.wala.util.intset.IntSetUtil;
import com.ibm.wala.util.strings.Atom;
import com.ibm.wala.util.strings.StringStuff;
@ -55,11 +58,11 @@ class ClassFactoryContextSelector implements ContextSelector {
public ClassFactoryContextSelector() {
}
public static boolean isClassFactory(IMethod m) {
if (m.getReference().equals(FOR_NAME_REF)) {
public static boolean isClassFactory(MethodReference m) {
if (m.equals(FOR_NAME_REF)) {
return true;
}
if (m.getReference().equals(LOAD_CLASS_REF)) {
if (m.equals(LOAD_CLASS_REF)) {
return true;
}
return false;
@ -79,10 +82,10 @@ class ClassFactoryContextSelector implements ContextSelector {
*
* @see com.ibm.wala.ipa.callgraph.ContextSelector#getCalleeTarget(com.ibm.wala.ipa.callgraph.CGNode,
* com.ibm.wala.classLoader.CallSiteReference, com.ibm.wala.classLoader.IMethod,
* com.ibm.wala.ipa.callgraph.propagation.InstanceKey)
* InstanceKey[])
*/
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
if (isClassFactory(callee)) {
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) {
if (isClassFactory(callee.getReference())) {
IR ir = caller.getIR();
SymbolTable symbolTable = ir.getSymbolTable();
SSAAbstractInvokeInstruction[] invokeInstructions = caller.getIR().getCalls(site);
@ -103,22 +106,24 @@ class ClassFactoryContextSelector implements ContextSelector {
return null;
}
/**
* This object may understand a dispatch to Class.forName(s) when s is a string constant.
*/
public boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) {
if (isClassFactory(targetMethod)) {
IR ir = caller.getIR();
SymbolTable symbolTable = ir.getSymbolTable();
private static final IntSet thisParameter = IntSetUtil.make(new int[]{0});
private static final IntSet firstParameter = IntSetUtil.make(new int[]{1});
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
if (isClassFactory(site.getDeclaredTarget())) {
SSAAbstractInvokeInstruction[] invokeInstructions = caller.getIR().getCalls(site);
if (invokeInstructions.length != 1) {
return false;
}
int use = getUseOfStringParameter(invokeInstructions[0]);
if (symbolTable.isStringConstant(use)) {
return true;
if (invokeInstructions[0].isStatic()) {
return thisParameter;
} else {
return firstParameter;
}
} else {
return EmptyIntSet.instance;
}
} else {
return EmptyIntSet.instance;
}
return false;
}
}

View File

@ -19,6 +19,9 @@ import com.ibm.wala.ipa.callgraph.Context;
import com.ibm.wala.ipa.callgraph.ContextSelector;
import com.ibm.wala.ipa.callgraph.propagation.ConstantKey;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.util.intset.EmptyIntSet;
import com.ibm.wala.util.intset.IntSet;
import com.ibm.wala.util.intset.IntSetUtil;
/**
* A {@link ContextSelector} to intercept calls to Class.newInstance()
@ -33,9 +36,9 @@ class ClassNewInstanceContextSelector implements ContextSelector {
* representing the type of the IClass. (This corresponds to the case where we know the exact type that will be
* allocated by the <code>Class.newInstance()</code> call.) Otherwise, return <code>null</code>.
*/
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
if (callee.getReference().equals(ClassNewInstanceContextInterpreter.CLASS_NEW_INSTANCE_REF) && isTypeConstant(receiver)) {
IClass c = (IClass) ((ConstantKey) receiver).getValue();
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) {
if (callee.getReference().equals(ClassNewInstanceContextInterpreter.CLASS_NEW_INSTANCE_REF) && isTypeConstant(receiver[0])) {
IClass c = (IClass) ((ConstantKey) receiver[0]).getValue();
if (!c.isAbstract() && !c.isInterface()) {
return new JavaTypeContext(new PointType(c));
}
@ -52,4 +55,14 @@ class ClassNewInstanceContextSelector implements ContextSelector {
}
return false;
}
private static final IntSet thisParameter = IntSetUtil.make(new int[]{0});
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
if (site.isDispatch() || site.getDeclaredTarget().getNumberOfParameters() > 0) {
return thisParameter;
} else {
return EmptyIntSet.instance;
}
}
}

View File

@ -19,6 +19,8 @@ import com.ibm.wala.ipa.callgraph.ContextSelector;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.callgraph.propagation.cfa.CallString;
import com.ibm.wala.ipa.callgraph.propagation.cfa.CallStringContext;
import com.ibm.wala.util.intset.EmptyIntSet;
import com.ibm.wala.util.intset.IntSet;
/**
* For synthetic methods marked as "Factories", we analyze in a context defined by the caller.
@ -31,7 +33,7 @@ class FactoryContextSelector implements ContextSelector {
/*
* @see com.ibm.wala.ipa.callgraph.ContextSelector#getCalleeTarget(com.ibm.wala.ipa.callgraph.CGNode, com.ibm.wala.classLoader.CallSiteReference, com.ibm.wala.classLoader.IMethod)
*/
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) {
if (callee == null) {
throw new IllegalArgumentException("callee is null");
}
@ -44,4 +46,8 @@ class FactoryContextSelector implements ContextSelector {
return null;
}
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
return EmptyIntSet.instance;
}
}

View File

@ -19,6 +19,9 @@ import com.ibm.wala.ipa.callgraph.ContextSelector;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.intset.EmptyIntSet;
import com.ibm.wala.util.intset.IntSet;
import com.ibm.wala.util.intset.IntSetUtil;
/**
* A {@link ContextSelector} to intercept calls to Object.getClass()
@ -36,10 +39,21 @@ class GetClassContextSelector implements ContextSelector {
* com.ibm.wala.classLoader.CallSiteReference, com.ibm.wala.classLoader.IMethod,
* com.ibm.wala.ipa.callgraph.propagation.InstanceKey)
*/
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) {
if (callee.getReference().equals(GET_CLASS)) {
return new JavaTypeContext(new PointType(receiver.getConcreteType()));
return new JavaTypeContext(new PointType(receiver[0].getConcreteType()));
}
return null;
}
private static final IntSet thisParameter = IntSetUtil.make(new int[]{0});
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
if (site.isDispatch() || site.getDeclaredTarget().getNumberOfParameters() > 0) {
return thisParameter;
} else {
return EmptyIntSet.instance;
}
}
}

View File

@ -24,6 +24,9 @@ import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.intset.EmptyIntSet;
import com.ibm.wala.util.intset.IntSet;
import com.ibm.wala.util.intset.IntSetUtil;
/**
* A {@link ContextSelector} to intercept calls to certain methods on java.lang.Class when the receiver is a type constant
@ -45,9 +48,9 @@ class JavaLangClassContextSelector implements ContextSelector {
* If the {@link CallSiteReference} invokes a method we understand and c is a type constant, return a {@link JavaTypeContext}
* representing the type named by s, if we can resolve it in the {@link IClassHierarchy}.
*/
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
if (mayUnderstand(caller, site, callee, receiver)) {
return new JavaTypeContext(new PointType(getTypeConstant(receiver)));
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) {
if (receiver != null && receiver.length > 0 && mayUnderstand(caller, site, callee, receiver[0])) {
return new JavaTypeContext(new PointType(getTypeConstant(receiver[0])));
}
return null;
}
@ -81,4 +84,14 @@ class JavaLangClassContextSelector implements ContextSelector {
private boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) {
return UNDERSTOOD_METHOD_REFS.contains(targetMethod.getReference()) && getTypeConstant(instance) != null;
}
private static final IntSet thisParameter = IntSetUtil.make(new int[]{0});
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
if (site.isDispatch() || site.getDeclaredTarget().getNumberOfParameters() > 0) {
return thisParameter;
} else {
return EmptyIntSet.instance;
}
}
}

View File

@ -36,7 +36,7 @@ public class JavaTypeContext implements Context {
public ContextItem get(ContextKey name) {
if (name == ContextKey.RECEIVER) {
return type;
} else if (name == ContextKey.FILTER) {
} else if (name == ContextKey.PARAMETERS[0]) {
if (type instanceof PointType) {
IClass cls = ((PointType) type).getIClass();
return new FilteredPointerKey.SingleClassFilter(cls);
@ -44,7 +44,6 @@ public class JavaTypeContext implements Context {
return null;
}
} else {
Assertions.UNREACHABLE();
return null;
}
}

View File

@ -18,6 +18,8 @@ import com.ibm.wala.ipa.callgraph.Context;
import com.ibm.wala.ipa.callgraph.ContextSelector;
import com.ibm.wala.ipa.callgraph.impl.DelegatingContextSelector;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.util.intset.EmptyIntSet;
import com.ibm.wala.util.intset.IntSet;
/**
* A {@link ContextSelector} to handle default reflection logic.
@ -32,9 +34,12 @@ public class ReflectionContextSelector {
// start with a dummy
ContextSelector result = new ContextSelector() {
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) {
return null;
}
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
return EmptyIntSet.instance;
}
};
if (options.getReflectionOptions().getNumFlowToCastIterations() > 0) {
result = new DelegatingContextSelector(new FactoryContextSelector(), result);

View File

@ -24,6 +24,9 @@ import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.ssa.SSANewInstruction;
import com.ibm.wala.ssa.SymbolTable;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.intset.EmptyIntSet;
import com.ibm.wala.util.intset.IntSet;
import com.ibm.wala.util.intset.IntSetUtil;
/**
* A {@link ContextSelector} to intercept calls to reflective method invocations such as Constructor.newInstance and Method.invoke
@ -44,20 +47,20 @@ class ReflectiveInvocationSelector implements ContextSelector {
* <li>Otherwise, return a new {@link ReceiverInstanceContext} for <code>receiver</code>.
* </ol>
*/
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
if (!mayUnderstand(caller, site, callee, receiver)) {
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) {
if (receiver == null || receiver.length == 0 || !mayUnderstand(caller, site, callee, receiver[0])) {
return null;
}
IR ir = caller.getIR();
SSAAbstractInvokeInstruction[] invokeInstructions = ir.getCalls(site);
if (invokeInstructions.length != 1) {
return new ReceiverInstanceContext(receiver);
return new ReceiverInstanceContext(receiver[0]);
}
SymbolTable st = ir.getSymbolTable();
ConstantKey receiverConstantKey = (ConstantKey) receiver;
ConstantKey receiverConstantKey = (ConstantKey) receiver[0];
IMethod m = (IMethod) receiverConstantKey.getValue();
boolean isStatic = m.isStatic();
boolean isConstructor = isConstructorConstant(receiver);
boolean isConstructor = isConstructorConstant(receiver[0]);
// If the method being invoked through reflection is not a constructor and is definitely static, then
// we should not create a callee target for any method that is not static
@ -79,7 +82,7 @@ class ReflectiveInvocationSelector implements ContextSelector {
int paramUse = invokeInstructions[0].getUse(paramIndex);
SSAInstruction instr = caller.getDU().getDef(paramUse);
if (!(instr instanceof SSANewInstruction)) {
return new ReceiverInstanceContext(receiver);
return new ReceiverInstanceContext(receiver[0]);
}
SSANewInstruction newInstr = (SSANewInstruction) instr;
if (!newInstr.getConcreteType().isArrayType()) {
@ -89,12 +92,12 @@ class ReflectiveInvocationSelector implements ContextSelector {
try {
int arrayLength = st.getIntValue(vn);
if (arrayLength == numberOfParams) {
return new ReceiverInstanceContext(receiver);
return new ReceiverInstanceContext(receiver[0]);
} else {
return new IllegalArgumentExceptionContext();
}
} catch (IllegalArgumentException e) {
return new ReceiverInstanceContext(receiver);
return new ReceiverInstanceContext(receiver[0]);
}
}
@ -120,4 +123,14 @@ class ReflectiveInvocationSelector implements ContextSelector {
}
return false;
}
private static final IntSet thisParameter = IntSetUtil.make(new int[]{0});
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
if (site.isDispatch() || site.getDeclaredTarget().getNumberOfParameters() > 0) {
return thisParameter;
} else {
return EmptyIntSet.instance;
}
}
}

View File

@ -233,6 +233,11 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
super.initializeVariables();
AbstractIntStackMachine.this.initializeVariables();
}
@Override
protected MachineState[] makeStmtRHS(int size) {
return new MachineState[size];
}
};
}
@ -276,7 +281,7 @@ public abstract class AbstractIntStackMachine implements FixedPointConstants {
}
@Override
public byte evaluate(MachineState lhs, IVariable[] rhs) {
public byte evaluate(MachineState lhs, MachineState[] rhs) {
BasicBlock bb = lhs.getBasicBlock();
if (!bb.isCatchBlock()) {
return meet(lhs, rhs, bb, meeter) ? CHANGED : NOT_CHANGED;

View File

@ -296,7 +296,7 @@ public class TypeInference extends SSAInference<TypeVariable> implements FixedPo
* TODO: work on efficiency shortcuts for this.
*/
@Override
public byte evaluate(TypeVariable lhs, IVariable[] rhs) {
public byte evaluate(TypeVariable lhs, TypeVariable[] rhs) {
if (DEBUG) {
System.err.print("PhiOperator.meet " + lhs + " ");
@ -347,7 +347,7 @@ public class TypeInference extends SSAInference<TypeVariable> implements FixedPo
* TODO: work on efficiency shortcuts for this.
*/
@Override
public byte evaluate(TypeVariable lhs, IVariable[] rhsOperands) {
public byte evaluate(TypeVariable lhs, TypeVariable[] rhsOperands) {
TypeAbstraction lhsType = lhs.getType();
TypeVariable rhs = (TypeVariable) rhsOperands[0];
@ -383,7 +383,7 @@ public class TypeInference extends SSAInference<TypeVariable> implements FixedPo
}
@Override
public byte evaluate(TypeVariable lhs, IVariable[] rhs) {
public byte evaluate(TypeVariable lhs, TypeVariable[] rhs) {
TypeAbstraction lhsType = lhs.getType();
TypeAbstraction meet = TypeAbstraction.TOP;
for (int i = 0; i < rhs.length; i++) {
@ -429,7 +429,7 @@ public class TypeInference extends SSAInference<TypeVariable> implements FixedPo
}
@Override
public byte evaluate(TypeVariable lhs, IVariable[] rhs) {
public byte evaluate(TypeVariable lhs, TypeVariable[] rhs) {
TypeAbstraction arrayType = getType(load.getArrayRef());
if (arrayType == null || arrayType.equals(TypeAbstraction.TOP)) {
return NOT_CHANGED;
@ -786,4 +786,9 @@ public class TypeInference extends SSAInference<TypeVariable> implements FixedPo
return ret;
}
@Override
protected TypeVariable[] makeStmtRHS(int size) {
return new TypeVariable[size];
}
}

View File

@ -112,7 +112,7 @@ public abstract class SSAInference<T extends IVariable> extends DefaultFixedPoin
newStatement(def, (NullaryOperator<T>) op, false, false);
} else {
int n = s.getNumberOfUses();
IVariable[] uses = new IVariable[n];
T[] uses = makeStmtRHS(n);
for (int j = 0; j < n; j++) {
if (s.getUse(j) > -1) {
uses[j] = getVariable(s.getUse(j));

View File

@ -81,7 +81,7 @@ class ThisFilteringHeapModel implements HeapModel {
}
private FilteredPointerKey.TypeFilter getFilter(CGNode target) {
FilteredPointerKey.TypeFilter filter = (FilteredPointerKey.TypeFilter) target.getContext().get(ContextKey.FILTER);
FilteredPointerKey.TypeFilter filter = (FilteredPointerKey.TypeFilter) target.getContext().get(ContextKey.PARAMETERS[0]);
if (filter != null) {
return filter;

View File

@ -36,14 +36,35 @@ public interface ContextKey {
public final static ContextKey RECEIVER = new ContextKey() {
};
/**
* A property of contexts that might be generally useful: an identifier for the type filters applied to the receiver object ...
* used for filtering propagation across dynamic dispatched
*
* Implementations (ContextItems) for FILTER are to be instances of FilteredContextKey.TypeFilter
*
*/
public final static ContextKey FILTER = new ContextKey() {
};
public static class ParameterKey implements ContextKey {
public final int index;
public ParameterKey(int index) {
super();
this.index = index;
}
}
public static final ContextKey PARAMETERS[] = new ContextKey[]{
new ParameterKey(0),
new ParameterKey(1),
new ParameterKey(2),
new ParameterKey(3),
new ParameterKey(4),
new ParameterKey(5),
new ParameterKey(6),
new ParameterKey(7),
new ParameterKey(8),
new ParameterKey(9),
new ParameterKey(10),
new ParameterKey(11),
new ParameterKey(12),
new ParameterKey(13),
new ParameterKey(14),
new ParameterKey(15),
new ParameterKey(16),
new ParameterKey(17),
new ParameterKey(18),
new ParameterKey(19)
};
}

View File

@ -13,17 +13,30 @@ package com.ibm.wala.ipa.callgraph;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.util.intset.IntSet;
/**
* An interface to an object which helps control context-sensitivity
* An interface to an object which helps control context-sensitivity.
*/
public interface ContextSelector {
/**
* Given a call site, returns the Context in which the callee should be evaluated.
* Given a calling node and a call site, returns the Context in which the callee should be evaluated.
*
* @param caller the node containing the call site
* @param site description of the call site
* @param actualParameters the abstract objects (InstanceKeys) of parameters of interest to the selector
* @return the Context in which the callee should be evaluated, or null if no information is available.
*/
Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver);
Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] actualParameters);
/**
* Given a calling node and a call site, return the set of parameters based
* on which this selector may choose to specialize contexts.
*
* @param caller the calling node
* @param site the specific call site
* @return the set of parameters of interest
*/
IntSet getRelevantParameters(CGNode caller, CallSiteReference site);
}

View File

@ -17,35 +17,20 @@ 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.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.util.intset.EmptyIntSet;
import com.ibm.wala.util.intset.IntSet;
/**
* A basic context selector that ignores context.
*/
public class ContextInsensitiveSelector implements ContextSelector {
public boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) {
return true;
}
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) {
return Everywhere.EVERYWHERE;
}
public int getBoundOnNumberOfTargets(CGNode caller, CallSiteReference site, IMethod targetMethod) {
return 1;
}
/*
* @see com.ibm.wala.ipa.callgraph.ContextSelector#contextIsIrrelevant(com.ibm.wala.classLoader.CallSiteReference)
*/
public boolean contextIsIrrelevant(CGNode node, CallSiteReference site) {
return true;
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
return EmptyIntSet.instance;
}
/*
* @see com.ibm.wala.ipa.callgraph.ContextSelector#contextIsIrrelevant(com.ibm.wala.types.MethodReference)
*/
public boolean allSitesDispatchIdentically(CGNode node, CallSiteReference site) {
return true;
}
}

View File

@ -19,6 +19,8 @@ import com.ibm.wala.ipa.callgraph.Context;
import com.ibm.wala.ipa.callgraph.ContextSelector;
import com.ibm.wala.ipa.callgraph.propagation.CloneContextSelector;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.util.intset.IntSet;
/**
* Default object to control context-insensitive context selection, This includes reflection logic.
@ -27,21 +29,25 @@ public class DefaultContextSelector implements ContextSelector {
private final ContextSelector delegate;
public DefaultContextSelector(AnalysisOptions options) {
public DefaultContextSelector(AnalysisOptions options, IClassHierarchy cha) {
if (options == null) {
throw new IllegalArgumentException("null options");
}
ContextInsensitiveSelector ci = new ContextInsensitiveSelector();
ContextSelector r = ReflectionContextSelector.createReflectionContextSelector(options);
ContextSelector s = new DelegatingContextSelector(r, ci);
delegate = new DelegatingContextSelector(new CloneContextSelector(), s);
delegate = new DelegatingContextSelector(new CloneContextSelector(cha), s);
}
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) {
if (caller == null) {
throw new IllegalArgumentException("null caller");
}
return delegate.getCalleeTarget(caller, site, callee, receiver);
}
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
return delegate.getRelevantParameters(caller, site);
}
}

View File

@ -16,6 +16,7 @@ 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.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.util.intset.IntSet;
/**
* A context selector that first checks with A, then defaults to B.
@ -38,7 +39,7 @@ public class DelegatingContextSelector implements ContextSelector {
}
}
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) {
if (DEBUG) {
System.err.println(("getCalleeTarget " + caller + " " + site + " " + callee));
}
@ -58,4 +59,8 @@ public class DelegatingContextSelector implements ContextSelector {
return C;
}
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
return A.getRelevantParameters(caller, site).union(B.getRelevantParameters(caller, site));
}
}

View File

@ -16,6 +16,9 @@ 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.ipa.cha.IClassHierarchy;
import com.ibm.wala.util.intset.EmptyIntSet;
import com.ibm.wala.util.intset.IntSet;
/**
* This context selector selects a context based on the concrete type of
@ -25,11 +28,14 @@ public class CloneContextSelector implements ContextSelector {
private final ReceiverTypeContextSelector selector;
public CloneContextSelector() {
private final IClassHierarchy cha;
public CloneContextSelector(IClassHierarchy cha) {
this.selector = new ReceiverTypeContextSelector();
this.cha = cha;
}
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) {
if (receiver == null) {
return null;
}
@ -40,37 +46,14 @@ public class CloneContextSelector implements ContextSelector {
}
}
public int getBoundOnNumberOfTargets(CGNode caller, CallSiteReference reference, IMethod targetMethod) {
return -1;
}
public boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) {
if (targetMethod == null) {
throw new IllegalArgumentException("targetMethod is null");
}
return targetMethod.getReference().equals(CloneInterpreter.CLONE);
}
public boolean contextIsIrrelevant(CGNode node, CallSiteReference site) {
if (site == null) {
throw new IllegalArgumentException("site is null");
}
if (!site.getDeclaredTarget().equals(CloneInterpreter.CLONE)) {
return true;
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
IMethod declaredTarget = cha.resolveMethod(site.getDeclaredTarget());
if (declaredTarget != null && declaredTarget.getReference().equals(CloneInterpreter.CLONE)) {
return selector.getRelevantParameters(caller, site);
} else {
return false;
return EmptyIntSet.instance;
}
}
public boolean allSitesDispatchIdentically(CGNode node, CallSiteReference site) {
if (site == null) {
throw new IllegalArgumentException("site is null");
}
if (!site.getDeclaredTarget().equals(CloneInterpreter.CLONE)) {
return true;
} else {
return false;
}
}
}

View File

@ -29,6 +29,8 @@ public interface FilteredPointerKey extends PointerKey {
boolean addInverseFiltered(PropagationSystem system, PointsToSetVariable L, PointsToSetVariable R);
boolean isRootFilter();
}
public class SingleClassFilter implements TypeFilter {
@ -70,6 +72,10 @@ public interface FilteredPointerKey extends PointerKey {
// use addAllInIntersection
return (f == null) ? L.addAll(R) : L.addAll(IntSetUtil.diff(R.getValue(), f));
}
public boolean isRootFilter() {
return concreteType.equals(concreteType.getClassHierarchy().getRootClass());
}
}
public class MultipleClassesFilter implements TypeFilter {
@ -139,6 +145,10 @@ public interface FilteredPointerKey extends PointerKey {
// use addAllInIntersection
return (f == null) ? L.addAll(R) : L.addAll(IntSetUtil.diff(R.getValue(), f));
}
public boolean isRootFilter() {
return concreteType.length == 1 && concreteType[0].getClassHierarchy().getRootClass().equals(concreteType[0]);
}
}
public class SingleInstanceFilter implements TypeFilter {
@ -189,6 +199,10 @@ public interface FilteredPointerKey extends PointerKey {
return L.addAll(copy);
}
}
public boolean isRootFilter() {
return false;
}
}
public class TargetMethodFilter implements TypeFilter {
@ -263,6 +277,10 @@ public interface FilteredPointerKey extends PointerKey {
return act.result;
}
}
public boolean isRootFilter() {
return false;
}
}
/**

View File

@ -34,14 +34,18 @@ import com.ibm.wala.ipa.callgraph.ContextSelector;
import com.ibm.wala.ipa.callgraph.Entrypoint;
import com.ibm.wala.ipa.callgraph.impl.AbstractRootMethod;
import com.ibm.wala.ipa.callgraph.impl.ExplicitCallGraph;
import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder.DispatchOperator;
import com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.CancelException;
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.functions.VoidFunction;
import com.ibm.wala.util.intset.IntIterator;
import com.ibm.wala.util.intset.IntSet;
import com.ibm.wala.util.intset.IntSetAction;
import com.ibm.wala.util.intset.IntSetUtil;
@ -685,9 +689,8 @@ public abstract class PropagationCallGraphBuilder implements CallGraphBuilder {
* @param iKey an abstraction of the receiver of the call (or null if not applicable)
* @return the CGNode to which this particular call should dispatch.
*/
public CGNode getTargetForCall(CGNode caller, CallSiteReference site, InstanceKey iKey) {
protected CGNode getTargetForCall(CGNode caller, CallSiteReference site, IClass recv, InstanceKey iKey[]) {
IClass recv = (iKey != null) ? iKey.getConcreteType() : null;
IMethod targetMethod = options.getMethodTargetSelector().getCalleeTarget(caller, site, recv);
// this most likely indicates an exclusion at work; the target selector
@ -696,6 +699,7 @@ public abstract class PropagationCallGraphBuilder implements CallGraphBuilder {
return null;
}
Context targetContext = contextSelector.getCalleeTarget(caller, site, targetMethod, iKey);
if (targetContext instanceof IllegalArgumentExceptionContext) {
return null;
}
@ -705,7 +709,7 @@ public abstract class PropagationCallGraphBuilder implements CallGraphBuilder {
return null;
}
}
/**
* @return the context selector for this call graph builder
*/

View File

@ -192,7 +192,7 @@ public class PropagationSystem extends DefaultFixedPointSolver<PointsToSetVariab
if (klass == null) {
throw new IllegalArgumentException("klass is null");
}
assert klass.getReference() != TypeReference.JavaLangObject;
assert klass != klass.getClassHierarchy().getRootClass();
return class2InstanceKey.get(klass);
}
@ -568,6 +568,21 @@ public class PropagationSystem extends DefaultFixedPointSolver<PointsToSetVariab
newStatement(null, op, v1, true, true);
}
public void newSideEffect(AbstractOperator<PointsToSetVariable> op, PointerKey[] arg0) {
if (arg0 == null) {
throw new IllegalArgumentException("null arg0");
}
if (DEBUG) {
System.err.println("add constraint D: " + op + " " + arg0);
}
PointsToSetVariable[] vs = new PointsToSetVariable[ arg0.length ];
for(int i = 0; i < arg0.length; i++) {
assert !pointsToMap.isUnified(arg0[i]);
vs[i] = findOrCreatePointsToSet(arg0[i]);
}
newStatement(null, op, vs, true, true);
}
public void newSideEffect(AbstractOperator<PointsToSetVariable> op, PointerKey arg0, PointerKey arg1) {
if (DEBUG) {
System.err.println("add constraint D: " + op + " " + arg0);
@ -888,4 +903,9 @@ public class PropagationSystem extends DefaultFixedPointSolver<PointsToSetVariab
public int getNumber(PointerKey p) {
return pointsToMap.getIndex(p);
}
@Override
protected PointsToSetVariable[] makeStmtRHS(int size) {
return new PointsToSetVariable[size];
}
}

View File

@ -35,10 +35,9 @@ public class ReceiverInstanceContext implements Context {
public ContextItem get(ContextKey name) {
if (name == ContextKey.RECEIVER)
return ik;
else if (name == ContextKey.FILTER)
else if (name == ContextKey.PARAMETERS[0])
return new FilteredPointerKey.SingleInstanceFilter(ik);
else {
Assertions.UNREACHABLE();
return null;
}
}

View File

@ -17,6 +17,8 @@ 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;
/**
* This context selector selects a context based on the concrete type of the receiver.
@ -26,27 +28,18 @@ public class ReceiverTypeContextSelector implements ContextSelector {
public ReceiverTypeContextSelector() {
}
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) {
if (receiver == null) {
throw new IllegalArgumentException("receiver is null");
}
PointType P = new PointType(receiver.getConcreteType());
PointType P = new PointType(receiver[0].getConcreteType());
return new JavaTypeContext(P);
}
public int getBoundOnNumberOfTargets(CGNode caller, CallSiteReference reference, IMethod targetMethod) {
return -1;
private static final IntSet receiver = IntSetUtil.make(new int[]{ 0 });
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
return receiver;
}
public boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) {
return true;
}
public boolean contextIsIrrelevant(CGNode node, CallSiteReference site) {
return false;
}
public boolean allSitesDispatchIdentically(CGNode node, CallSiteReference site) {
return false;
}
}

View File

@ -28,8 +28,7 @@ import com.ibm.wala.classLoader.IField;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.classLoader.ProgramCounter;
import com.ibm.wala.fixpoint.IntSetVariable;
import com.ibm.wala.fixpoint.UnaryOperator;
import com.ibm.wala.fixpoint.AbstractOperator;
import com.ibm.wala.ipa.callgraph.AnalysisCache;
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
import com.ibm.wala.ipa.callgraph.CGNode;
@ -71,6 +70,8 @@ import com.ibm.wala.types.Selector;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.functions.VoidFunction;
import com.ibm.wala.util.intset.IntIterator;
import com.ibm.wala.util.intset.IntSet;
import com.ibm.wala.util.intset.IntSetAction;
import com.ibm.wala.util.intset.IntSetUtil;
@ -227,7 +228,7 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
/**
* @return a visitor to examine instructions in the ir
*/
protected ConstraintVisitor makeVisitor(ExplicitCallGraph.ExplicitNode node) {
protected ConstraintVisitor makeVisitor(CGNode node) {
return new ConstraintVisitor(this, node);
}
@ -235,7 +236,7 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
* Add pointer flow constraints based on instructions in a given node
*/
protected void addNodeInstructionConstraints(CGNode node) {
ConstraintVisitor v = makeVisitor((ExplicitCallGraph.ExplicitNode) node);
ConstraintVisitor v = makeVisitor(node);
IR ir = getCFAContextInterpreter().getIR(node);
ControlFlowGraph<SSAInstruction, ISSABasicBlock> cfg = ir.getControlFlowGraph();
@ -492,7 +493,7 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
/**
* The node whose statements we are currently traversing
*/
protected final ExplicitCallGraph.ExplicitNode node;
protected final CGNode node;
/**
* The governing call graph.
@ -524,7 +525,7 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
*/
protected final DefUse du;
public ConstraintVisitor(SSAPropagationCallGraphBuilder builder, ExplicitCallGraph.ExplicitNode node) {
public ConstraintVisitor(SSAPropagationCallGraphBuilder builder, CGNode node) {
this.builder = builder;
this.node = node;
@ -601,14 +602,18 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
return getBuilder().getInstanceKeyForClassObject(type);
}
public CGNode getTargetForCall(CGNode caller, CallSiteReference site, InstanceKey iKey) {
return getBuilder().getTargetForCall(caller, site, iKey);
public CGNode getTargetForCall(CGNode caller, CallSiteReference site, IClass recv, InstanceKey iKey[]) {
return getBuilder().getTargetForCall(caller, site, recv, iKey);
}
protected boolean contentsAreInvariant(SymbolTable symbolTable, DefUse du, int valueNumber) {
return getBuilder().contentsAreInvariant(symbolTable, du, valueNumber);
}
protected boolean contentsAreInvariant(SymbolTable symbolTable, DefUse du, int valueNumber[]) {
return getBuilder().contentsAreInvariant(symbolTable, du, valueNumber);
}
protected InstanceKey[] getInvariantContents(int valueNumber) {
return getInvariantContents(ir.getSymbolTable(), du, node, valueNumber);
}
@ -1005,7 +1010,7 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
visitInvokeInternal(instruction);
}
protected void visitInvokeInternal(SSAAbstractInvokeInstruction instruction) {
protected void visitInvokeInternal(final SSAAbstractInvokeInstruction instruction) {
if (DEBUG) {
System.err.println("visitInvoke: " + instruction);
}
@ -1016,9 +1021,7 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
}
if (instruction.getCallSite().isStatic()) {
CGNode n = getTargetForCall(node, instruction.getCallSite(), (InstanceKey) null);
if (n == null) {
} else {
for (CGNode n : getBuilder().getTargetsForCall(node, instruction.getCallSite())) {
getBuilder().processResolvedCall(node, instruction, n, computeInvariantParameters(instruction), uniqueCatch);
if (DEBUG) {
System.err.println("visitInvoke class init " + n);
@ -1031,32 +1034,42 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
// Add a side effect that will fire when we determine a value
// for the receiver. This side effect will create a new node
// and new constraints based on the new callee context.
// NOTE: This will not be adequate for CPA-style context selectors,
// where the callee context may depend on state other than the
// receiver. TODO: rectify this when needed.
PointerKey receiver = getPointerKeyForLocal(instruction.getReceiver());
// if (!supportFullPointerFlowGraph &&
// contentsAreInvariant(instruction.getReceiver())) {
if (contentsAreInvariant(symbolTable, du, instruction.getReceiver())) {
system.recordImplicitPointsToSet(receiver);
InstanceKey[] ik = getInvariantContents(instruction.getReceiver());
for (int i = 0; i < ik.length; i++) {
system.findOrCreateIndexForInstanceKey(ik[i]);
CGNode n = getTargetForCall(node, instruction.getCallSite(), ik[i]);
if (n == null) {
} else {
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;
public void act(int x) {
vns[i++] = instruction.getUse(x);
}
});
if (contentsAreInvariant(symbolTable, du, vns)) {
for(CGNode n : getBuilder().getTargetsForCall(node, instruction.getCallSite())) {
getBuilder().processResolvedCall(node, instruction, n, computeInvariantParameters(instruction), uniqueCatch);
// side effect of invoke: may call class initializer
processClassInitializer(n.getMethod().getDeclaringClass());
}
}
} else {
if (DEBUG) {
System.err.println("Add side effect, dispatch to " + instruction + ", receiver " + receiver);
System.err.println("Add side effect, dispatch to " + instruction + " for " + params);
}
final List<PointerKey> pks = new ArrayList<PointerKey>(params.size());
params.foreach(new IntSetAction() {
public void act(int x) {
if (! contentsAreInvariant(symbolTable, du, instruction.getUse(x))) {
pks.add(getBuilder().getPointerKeyForLocal(node, instruction.getUse(x)));
}
}
});
DispatchOperator dispatchOperator = getBuilder().new DispatchOperator(instruction, node,
computeInvariantParameters(instruction), uniqueCatch);
system.newSideEffect(dispatchOperator, receiver);
computeInvariantParameters(instruction), uniqueCatch, params);
system.newSideEffect(dispatchOperator, pks.toArray(new PointerKey[pks.size()]));
}
}
}
@ -1374,7 +1387,7 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
CallSiteReference site = CallSiteReference.make(1, m, IInvokeInstruction.Dispatch.STATIC);
IMethod targetMethod = getOptions().getMethodTargetSelector().getCalleeTarget(callGraph.getFakeRootNode(), site, null);
if (targetMethod != null) {
CGNode target = getTargetForCall(callGraph.getFakeRootNode(), site, (InstanceKey) null);
CGNode target = getTargetForCall(callGraph.getFakeRootNode(), site, null, null);
if (target != null && callGraph.getPredNodeCount(target) == 0) {
SSAAbstractInvokeInstruction s = fakeWorldClinitMethod.addInvocation(new int[0], site);
PointerKey uniqueCatch = getBuilder().getPointerKeyForExceptionalReturnValue(callGraph.getFakeRootNode());
@ -1422,7 +1435,12 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
if (!haveAlreadyVisited(target)) {
markDiscovered(target);
}
processCallingConstraints(caller, instruction, target, constParams, uniqueCatchKey);
}
protected void processCallingConstraints(CGNode caller, SSAAbstractInvokeInstruction instruction, CGNode target,
InstanceKey[][] constParams, PointerKey uniqueCatchKey) {
// TODO: i'd like to enable this optimization, but it's a little tricky
// to recover the implicit points-to sets with recursion. TODO: don't
// be lazy and code the recursive logic to enable this.
@ -1457,57 +1475,27 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
return;
}
boolean needsFilter = !instruction.getCallSite().isStatic() && needsFilterForReceiver(instruction, target);
// we're a little sloppy for now ... we don't filter calls to
// java.lang.Object.
// TODO: we need much more precise filters than cones in order to handle
// the various types of dispatch logic. We need a filter that expresses
// "the set of types s.t. x.foo resolves to y.foo."
for (int i = 0; i < instruction.getNumberOfParameters(); i++) {
// we rely on the invariant that the value number for the ith parameter
// is i+1
final int vn = i + 1;
if (target.getMethod().getParameterType(i).isReferenceType()) {
// if (constParams != null && constParams[i] != null &&
// !supportFullPointerFlowGraph) {
PointerKey formal = getTargetPointerKey(target, i);
if (constParams != null && constParams[i] != null) {
InstanceKey[] ik = constParams[i];
for (int j = 0; j < ik.length; j++) {
if (needsFilter && (i == 0)) {
FilteredPointerKey.TypeFilter C = getFilter(target);
PointerKey formal = null;
if (isRootType(C)) {
// TODO: we need much better filtering here ... see comments
// above.
formal = getPointerKeyForLocal(target, vn);
} else {
formal = getFilteredPointerKeyForLocal(target, vn, C);
}
system.newConstraint(formal, ik[j]);
} else {
PointerKey formal = getPointerKeyForLocal(target, vn);
system.newConstraint(formal, ik[j]);
}
system.newConstraint(formal, ik[j]);
}
} else {
if (instruction.getUse(i) < 0) {
Assertions.UNREACHABLE("unexpected " + instruction + " in " + caller);
}
PointerKey actual = getPointerKeyForLocal(caller, instruction.getUse(i));
if (needsFilter && (i == 0)) {
FilteredPointerKey.TypeFilter C = getFilter(target);
if (isRootType(C)) {
// TODO: we need much better filtering here ... see comments
// above.
PointerKey formal = getPointerKeyForLocal(target, vn);
system.newConstraint(formal, assignOperator, actual);
} else {
FilteredPointerKey formal = getFilteredPointerKeyForLocal(target, vn, C);
system.newConstraint(formal, filterOperator, actual);
}
if (formal instanceof FilteredPointerKey) {
system.newConstraint(formal, filterOperator, actual);
} else {
PointerKey formal = getPointerKeyForLocal(target, vn);
system.newConstraint(formal, assignOperator, actual);
}
}
@ -1536,127 +1524,138 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
* An operator to fire when we discover a potential new callee for a virtual or interface call site.
*
* This operator will create a new callee context and constraints if necessary.
*
* N.B: This implementation assumes that the calling context depends solely on the dataflow information computed for the receiver.
* TODO: generalize this to have other forms of context selection, such as CPA-style algorithms.
*/
final class DispatchOperator extends UnaryOperator<PointsToSetVariable> implements IPointerOperator {
final class DispatchOperator extends AbstractOperator<PointsToSetVariable> implements IPointerOperator {
private final SSAAbstractInvokeInstruction call;
private final ExplicitCallGraph.ExplicitNode node;
private final CGNode node;
private final InstanceKey[][] constParams;
private final PointerKey uniqueCatch;
private final int[] dispatchIndices;
/**
* @param call
* @param node
* @param constParams if non-null, then constParams[i] holds the String constant that is passed as param i, or null if param i
* is not a String constant
*/
DispatchOperator(SSAAbstractInvokeInstruction call, ExplicitCallGraph.ExplicitNode node, InstanceKey[][] constParams,
PointerKey uniqueCatch) {
DispatchOperator(SSAAbstractInvokeInstruction call, CGNode node, InstanceKey[][] constParams,
PointerKey uniqueCatch, IntSet dispatchIndices) {
this.call = call;
this.node = node;
this.constParams = constParams;
this.uniqueCatch = uniqueCatch;
this.dispatchIndices = IntSetUtil.toArray(dispatchIndices);
previousPtrs = new MutableIntSet[dispatchIndices.size()];
for(int i = 0; i < previousPtrs.length; i++) {
previousPtrs[i] = IntSetUtil.getDefaultIntSetFactory().make();
}
}
/**
* The set of pointers that have already been processed.
*/
final private MutableIntSet previousReceivers = IntSetUtil.getDefaultIntSetFactory().make();
final private MutableIntSet[] previousPtrs;
/*
* @see com.ibm.wala.dataflow.fixpoint.UnaryOperator#evaluate(com.ibm.wala.dataflow.fixpoint.IVariable,
* com.ibm.wala.dataflow.fixpoint.IVariable)
*/
@Override
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) {
final IntSetVariable receivers = rhs;
public byte evaluate(PointsToSetVariable lhs, final PointsToSetVariable[] rhs) {
assert dispatchIndices.length >= rhs.length : "bad operator at " + call;
final MutableBoolean sideEffect = new MutableBoolean();
// compute the set of pointers that were not previously handled
IntSet value = receivers.getValue();
if (value == null) {
// this constraint was put on the work list, probably by
// initialization,
// even though the right-hand-side is empty.
// TODO: be more careful about what goes on the worklist to
// avoid this.
if (DEBUG) {
System.err.println("EVAL dispatch with value null");
}
return NOT_CHANGED;
}
if (DEBUG) {
System.err.println("EVAL dispatch to " + node + ":" + call);
System.err.println("receivers: " + value);
}
IntSetAction action = new IntSetAction() {
public void act(int ptr) {
for(PointsToSetVariable v : rhs) {
if (v.getValue() == null) {
// this constraint was put on the work list, probably by
// initialization,
// even though the right-hand-side is empty.
// TODO: be more careful about what goes on the worklist to
// avoid this.
if (DEBUG) {
System.err.println(" dispatch to ptr " + ptr);
}
InstanceKey iKey = system.getInstanceKey(ptr);
CGNode target;
if (clone2Assign) {
// for efficiency: assume that only call sites that reference
// clone() might dispatch to clone methods
if (call.getCallSite().getDeclaredTarget().getSelector().equals(cloneSelector)) {
IClass recv = (iKey != null) ? iKey.getConcreteType() : null;
IMethod targetMethod = getOptions().getMethodTargetSelector().getCalleeTarget(node, call.getCallSite(), recv);
if (targetMethod != null && targetMethod.getReference().equals(CloneInterpreter.CLONE)) {
// treat this call to clone as an assignment
PointerKey result = getPointerKeyForLocal(node, call.getDef());
PointerKey receiver = getPointerKeyForLocal(node, call.getReceiver());
system.newConstraint(result, assignOperator, receiver);
return;
}
}
}
target = getTargetForCall(node, call.getCallSite(), iKey);
if (target == null) {
// This indicates an error; I sure hope getTargetForCall
// raised a warning about this!
if (DEBUG) {
System.err.println("Warning: null target for call " + call + " " + iKey);
}
} else {
IntSet targets = getCallGraph().getPossibleTargetNumbers(node, call.getCallSite());
if (targets != null && targets.contains(target.getGraphNodeId())) {
// do nothing; we've previously discovered and handled this
// receiver for this call site.
} else {
// process the newly discovered target for this call
sideEffect.b = true;
processResolvedCall(node, call, target, constParams, uniqueCatch);
if (!haveAlreadyVisited(target)) {
markDiscovered(target);
}
}
System.err.println("EVAL dispatch with value null");
}
return NOT_CHANGED;
}
};
try {
value.foreachExcluding(previousReceivers, action);
} catch (Error e) {
System.err.println("error in " + call + " on " + receivers + " of types " + value + " for " + node);
throw e;
} catch (RuntimeException e) {
System.err.println("error in " + call + " on " + receivers + " of types " + value + " for " + node);
throw e;
}
new Object() {
InstanceKey keys[] = new InstanceKey[constParams == null? dispatchIndices[dispatchIndices.length-1]+1: constParams.length];
void rec(int index, int rhsIndex, boolean redundant) {
if (index < dispatchIndices.length) {
int pi = dispatchIndices[index];
if (constParams != null && constParams[pi] != null) {
for(int i = 0; i < constParams[pi].length; i++) {
keys[pi] = constParams[pi][i];
int ii = system.instanceKeys.getMappedIndex(constParams[pi][i]);
rec(index+1, rhsIndex, redundant & previousPtrs[index].contains(ii));
}
} else {
PointsToSetVariable v = rhs[rhsIndex];
IntIterator ptrs = v.getValue().intIterator();
while (ptrs.hasNext()) {
int ptr = ptrs.next();
keys[dispatchIndices[index]] = system.getInstanceKey(ptr);
rec(index+1, rhsIndex+1, redundant & previousPtrs[index].contains(ptr));
}
}
} else if (!redundant) {
if (clone2Assign) {
// for efficiency: assume that only call sites that reference
// clone() might dispatch to clone methods
if (call.getCallSite().getDeclaredTarget().getSelector().equals(cloneSelector)) {
IClass recv = (keys[0] != null) ? keys[0].getConcreteType() : null;
IMethod targetMethod = getOptions().getMethodTargetSelector().getCalleeTarget(node, call.getCallSite(), recv);
if (targetMethod != null && targetMethod.getReference().equals(CloneInterpreter.CLONE)) {
// treat this call to clone as an assignment
PointerKey result = getPointerKeyForLocal(node, call.getDef());
PointerKey receiver = getPointerKeyForLocal(node, call.getReceiver());
system.newConstraint(result, assignOperator, receiver);
return;
}
}
}
CGNode target = getTargetForCall(node, call.getCallSite(), keys[0].getConcreteType(), keys);
if (target == null) {
// This indicates an error; I sure hope getTargetForCall
// raised a warning about this!
if (DEBUG) {
System.err.println("Warning: null target for call " + call);
}
} else {
IntSet targets = getCallGraph().getPossibleTargetNumbers(node, call.getCallSite());
if (targets != null && targets.contains(target.getGraphNodeId())) {
// do nothing; we've previously discovered and handled this
// receiver for this call site.
} else {
// process the newly discovered target for this call
sideEffect.b = true;
processResolvedCall(node, call, target, constParams, uniqueCatch);
if (!haveAlreadyVisited(target)) {
markDiscovered(target);
}
}
}
}
}
}.rec(0, 0, true);
// update the set of receivers previously considered
previousReceivers.copySet(value);
for(int ri = 0, i = 0; i < rhs.length; i++) {
int pi = dispatchIndices[i];
if (constParams != null && constParams[pi] != null) {
for(int ci = 0; ci < constParams[pi].length; ci++) {
previousPtrs[i].add(system.instanceKeys.getMappedIndex(constParams[i][ci]));
}
} else {
previousPtrs[i].addAll(rhs[ri++].getValue());
}
}
byte sideEffectMask = sideEffect.b ? (byte) SIDE_EFFECT_MASK : 0;
return (byte) (NOT_CHANGED | sideEffectMask);
}
@ -1697,6 +1696,82 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
}
}
protected void iterateCrossProduct(final CGNode caller, final CallSiteReference site, IntSet parameters, final VoidFunction<InstanceKey[]> f) {
final IR ir = caller.getIR();
final int params[] = IntSetUtil.toArray(parameters);
for (final SSAAbstractInvokeInstruction call : ir.getCalls(site)) {
final InstanceKey[] keys = new InstanceKey[call.getNumberOfParameters()];
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);
if (contentsAreInvariant(ir.getSymbolTable(), caller.getDU(), vn)) {
system.recordImplicitPointsToSet(var);
InstanceKey[] ik = getInvariantContents(ir.getSymbolTable(), caller.getDU(), caller, vn, SSAPropagationCallGraphBuilder.this);
if (ik != null && 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() {
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);
}
}
protected Set<CGNode> getTargetsForCall(final CGNode caller, final CallSiteReference site) {
IntSet params = contextSelector.getRelevantParameters(caller, site);
if (!site.isStatic() && !params.contains(0)) {
params = IntSetUtil.makeMutableCopy(params);
((MutableIntSet)params).add(0);
}
final Set<CGNode> targets = HashSetFactory.make();
VoidFunction<InstanceKey[]> f = new VoidFunction<InstanceKey[]>() {
public void apply(InstanceKey[] v) {
IClass recv = null;
if (site.isDispatch()) {
recv = v[0].getConcreteType();
}
CGNode target = getTargetForCall(caller, site, recv, v);
if (target != null) {
targets.add(target);
}
}
};
if (site.getDeclaredTarget().getName().toString().contains("numericToTextFormat")) {
System.err.println(site + "\n" + params + "\n" + targets);
}
iterateCrossProduct(caller, site, params, f);
return targets;
}
public boolean hasNoInterestingUses(CGNode node, int vn, DefUse du) {
if (du == null) {
@ -1808,7 +1883,7 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
*/
private boolean needsFilterForReceiver(SSAAbstractInvokeInstruction instruction, CGNode target) {
FilteredPointerKey.TypeFilter f = (FilteredPointerKey.TypeFilter) target.getContext().get(ContextKey.FILTER);
FilteredPointerKey.TypeFilter f = (FilteredPointerKey.TypeFilter) target.getContext().get(ContextKey.PARAMETERS[0]);
if (f != null) {
// the context selects a particular concrete type for the receiver.
@ -1851,16 +1926,30 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
* @param target
* @return an IClass which represents
*/
private FilteredPointerKey.TypeFilter getFilter(CGNode target) {
FilteredPointerKey.TypeFilter filter = (FilteredPointerKey.TypeFilter) target.getContext().get(ContextKey.FILTER);
if (filter != null) {
return filter;
protected PointerKey getTargetPointerKey(CGNode target, int index) {
int vn;
if (target.getIR() != null) {
vn = target.getIR().getSymbolTable().getParameter(index);
} else {
vn = index+1;
}
FilteredPointerKey.TypeFilter filter = (FilteredPointerKey.TypeFilter) target.getContext().get(ContextKey.PARAMETERS[index]);
if (filter != null && !filter.isRootFilter()) {
return pointerKeyFactory.getFilteredPointerKeyForLocal(target, vn, filter);
} else if (index == 0 && !target.getMethod().isStatic()) {
// the context does not select a particular concrete type for the
// receiver.
// receiver, so use the type of the method
IClass C = getReceiverClass(target.getMethod());
return new FilteredPointerKey.SingleClassFilter(C);
if (C.getClassHierarchy().getRootClass().equals(C)) {
return pointerKeyFactory.getPointerKeyForLocal(target, vn);
} else {
return pointerKeyFactory.getFilteredPointerKeyForLocal(target, vn, new FilteredPointerKey.SingleClassFilter(C));
}
} else {
return pointerKeyFactory.getPointerKeyForLocal(target, vn);
}
}
@ -1901,6 +1990,15 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap
}
}
protected boolean contentsAreInvariant(SymbolTable symbolTable, DefUse du, int valueNumbers[]) {
for(int i = 0; i < valueNumbers.length; i++) {
if (! contentsAreInvariant(symbolTable, du, valueNumbers[i])) {
return false;
}
}
return true;
}
/**
* precondition:contentsAreInvariant(valueNumber)
*

View File

@ -19,6 +19,8 @@ import com.ibm.wala.ipa.callgraph.ContextKey;
import com.ibm.wala.ipa.callgraph.ContextSelector;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.types.Selector;
import com.ibm.wala.util.intset.IntSet;
import com.ibm.wala.util.intset.IntSetUtil;
/**
* This context selector selects a context based on whether the receiver type
@ -32,12 +34,12 @@ public class TargetMethodContextSelector implements ContextSelector {
this.selector = selector;
}
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey R) {
if (R == null) {
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] R) {
if (R == null || R[0] == null) {
throw new IllegalArgumentException("R is null");
}
final IMethod M = R.getConcreteType().getMethod(selector);
final IMethod M = R[0].getConcreteType().getMethod(selector);
class MethodDispatchContext implements Context {
@ -46,7 +48,7 @@ public class TargetMethodContextSelector implements ContextSelector {
}
public ContextItem get(ContextKey name) {
if (name.equals(ContextKey.FILTER)) {
if (name.equals(ContextKey.PARAMETERS[0])) {
return new FilteredPointerKey.TargetMethodFilter(M);
} else {
return null;
@ -73,19 +75,10 @@ public class TargetMethodContextSelector implements ContextSelector {
return new MethodDispatchContext();
}
public int getBoundOnNumberOfTargets(CGNode caller, CallSiteReference reference, IMethod targetMethod) {
return -1;
private static final IntSet thisParameter = IntSetUtil.make(new int[]{0});
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
return thisParameter;
}
public boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) {
return true;
}
public boolean contextIsIrrelevant(CGNode node, CallSiteReference site) {
return false;
}
public boolean allSitesDispatchIdentically(CGNode node, CallSiteReference site) {
return false;
}
}

View File

@ -19,6 +19,8 @@ import com.ibm.wala.ipa.callgraph.ContextKey;
import com.ibm.wala.ipa.callgraph.ContextSelector;
import com.ibm.wala.ipa.callgraph.impl.Everywhere;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.util.intset.EmptyIntSet;
import com.ibm.wala.util.intset.IntSet;
public abstract class CallStringContextSelector implements ContextSelector {
@ -88,7 +90,7 @@ public abstract class CallStringContextSelector implements ContextSelector {
/*
* @see com.ibm.wala.ipa.callgraph.ContextSelector#getCalleeTarget(com.ibm.wala.ipa.callgraph.CGNode, com.ibm.wala.classLoader.CallSiteReference, com.ibm.wala.classLoader.IMethod, com.ibm.wala.ipa.callgraph.propagation.InstanceKey)
*/
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) {
Context baseContext = base.getCalleeTarget(caller, site, callee, receiver);
CallString cs = getCallString(caller, site, callee);
if (cs == null) {
@ -99,4 +101,9 @@ public abstract class CallStringContextSelector implements ContextSelector {
return new CallStringContextPair(cs, baseContext);
}
}
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
return EmptyIntSet.instance;
}
}

View File

@ -27,6 +27,9 @@ import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeName;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.intset.EmptyIntSet;
import com.ibm.wala.util.intset.IntSet;
import com.ibm.wala.util.intset.IntSetUtil;
import com.ibm.wala.util.strings.Atom;
/**
@ -100,11 +103,15 @@ public class ContainerContextSelector implements ContextSelector {
* com.ibm.wala.classLoader.CallSiteReference, com.ibm.wala.classLoader.IMethod,
* com.ibm.wala.ipa.callgraph.propagation.InstanceKey)
*/
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] keys) {
if (DEBUG) {
System.err.println("ContainerContextSelector: getCalleeTarget " + callee);
}
if (mayUnderstand(caller, site, callee, receiver)) {
InstanceKey receiver = null;
if (keys != null && keys.length > 0 && keys[0] != null) {
receiver = keys[0];
}
if (receiver != null && mayUnderstand(caller, site, callee, receiver)) {
if (DEBUG) {
System.err.println("May Understand: " + callee + " recv " + receiver);
}
@ -258,12 +265,6 @@ public class ContainerContextSelector implements ContextSelector {
return (n == null) ? null : n.getContext();
}
public int getBoundOnNumberOfTargets(CGNode caller, CallSiteReference site, IMethod targetMethod) {
// if we understand this call, we don't know how many target contexts we may
// create.
return -1;
}
public boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey receiver) {
if (targetMethod == null) {
throw new IllegalArgumentException("targetMethod is null");
@ -326,15 +327,18 @@ public class ContainerContextSelector implements ContextSelector {
return ContainerUtil.isContainer(C);
}
public boolean contextIsIrrelevant(CGNode node, CallSiteReference site) {
return false;
}
protected IClassHierarchy getClassHierarchy() {
return cha;
}
public boolean allSitesDispatchIdentically(CGNode node, CallSiteReference site) {
return false;
private static final IntSet thisParameter = IntSetUtil.make(new int[]{0});
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
if (site.isDispatch() || site.getDeclaredTarget().getNumberOfParameters() > 0) {
return thisParameter;
} else {
return EmptyIntSet.instance;
}
}
}

View File

@ -17,6 +17,7 @@ import com.ibm.wala.ipa.callgraph.Context;
import com.ibm.wala.ipa.callgraph.ContextSelector;
import com.ibm.wala.ipa.callgraph.impl.Everywhere;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.util.intset.IntSet;
/**
* This is a context selector that adds one level of calling context to a base context selector.
@ -36,7 +37,7 @@ public class OneLevelSiteContextSelector implements ContextSelector {
this.baseSelector = baseSelector;
}
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) {
Context baseContext = baseSelector.getCalleeTarget(caller, site, callee, receiver);
if (baseContext.equals(Everywhere.EVERYWHERE)) {
return new CallerSiteContext(caller, site);
@ -45,4 +46,8 @@ public class OneLevelSiteContextSelector implements ContextSelector {
}
}
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
return baseSelector.getRelevantParameters(caller, site);
}
}

View File

@ -32,7 +32,7 @@ public class ZeroXCFABuilder extends SSAPropagationCallGraphBuilder {
super(cha, options, cache, new DefaultPointerKeyFactory());
ContextSelector def = new DefaultContextSelector(options);
ContextSelector def = new DefaultContextSelector(options, cha);
ContextSelector contextSelector = appContextSelector == null ? def : new DelegatingContextSelector(appContextSelector, def);
setContextSelector(contextSelector);

View File

@ -37,7 +37,7 @@ public class nCFABuilder extends SSAPropagationCallGraphBuilder {
setInstanceKeys(new ClassBasedInstanceKeys(options, cha));
ContextSelector def = new DefaultContextSelector(options);
ContextSelector def = new DefaultContextSelector(options, cha);
ContextSelector contextSelector = new DelegatingContextSelector(appContextSelector, def);
contextSelector = new nCFAContextSelector(n, contextSelector);
setContextSelector(contextSelector);

View File

@ -238,7 +238,7 @@ public abstract class AbstractRTABuilder extends PropagationCallGraphBuilder {
IInvokeInstruction.IDispatch code = site.getInvocationCode();
if (code == IInvokeInstruction.Dispatch.STATIC) {
CGNode n = getTargetForCall(node, site, (InstanceKey) null);
CGNode n = getTargetForCall(node, site, null, null);
if (n != null) {
processResolvedCall(node, site, n);
@ -372,7 +372,7 @@ public abstract class AbstractRTABuilder extends PropagationCallGraphBuilder {
}
protected ContextSelector makeContextSelector(ContextSelector appContextSelector) {
ContextSelector def = new DefaultContextSelector(options);
ContextSelector def = new DefaultContextSelector(options, cha);
ContextSelector contextSelector = appContextSelector == null ? def : new DelegatingContextSelector(appContextSelector, def);
return contextSelector;
}

View File

@ -155,7 +155,7 @@ public class BasicRTABuilder extends AbstractRTABuilder {
}
InstanceKey iKey = system.getInstanceKey(ptr);
CGNode target = getTargetForCall(caller, site, iKey);
CGNode target = getTargetForCall(caller, site, iKey.getConcreteType(), new InstanceKey[]{iKey});
if (target == null) {
// This indicates an error; I sure hope getTargetForCall
// raised a warning about this!

View File

@ -36,6 +36,8 @@ public class SymbolTable implements Cloneable {
*/
private HashMap<ConstantValue, Integer> constants = HashMapFactory.make(10);
private boolean copy = false;
/**
* @param numberOfParameters in the IR .. should be ir.getNumberOfParameters()
*/
@ -75,6 +77,7 @@ public class SymbolTable implements Cloneable {
ConstantValue v = new ConstantValue(o);
Integer result = constants.get(v);
if (result == null) {
assert ! copy : "making value for " + o;
int r = getNewValueNumber();
result = Integer.valueOf(r);
constants.put(v, result);
@ -446,6 +449,7 @@ public class SymbolTable implements Cloneable {
nt.defaultValues = this.defaultValues.clone();
}
nt.constants = HashMapFactory.make(this.constants);
nt.copy = true;
return nt;
} catch (CloneNotSupportedException e) {
Assertions.UNREACHABLE();

View File

@ -186,5 +186,10 @@ public class DeadAssignmentElimination {
}
}
@Override
protected BooleanVariable[] makeStmtRHS(int size) {
return new BooleanVariable[size];
}
}
}

View File

@ -26,6 +26,8 @@ import com.ibm.wala.types.MemberReference;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeName;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.intset.EmptyIntSet;
import com.ibm.wala.util.intset.IntSet;
import com.ibm.wala.util.strings.Atom;
/**
@ -54,7 +56,7 @@ public class J2EEContextSelector implements ContextSelector {
/**
* Analyze each call to Command.execute() in a different context
*/
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] receiver) {
if (callee.getReference().equals(ExecuteMethod)) {
ReceiverTypeInference R = typeInference.findOrCreate(caller);
if (R == null) {
@ -71,42 +73,8 @@ public class J2EEContextSelector implements ContextSelector {
}
}
public int getBoundOnNumberOfTargets(CGNode caller, CallSiteReference site, IMethod callee) {
if (callee.getReference().equals(ExecuteMethod)) {
return 1;
} else {
return -1;
}
}
public boolean contextIsIrrelevant(CGNode node, CallSiteReference site) {
Atom name = site.getDeclaredTarget().getName();
Descriptor d = site.getDeclaredTarget().getDescriptor();
if (name.equals(ExecuteAtom) && d.equals(ExecuteDesc)) {
return false;
} else {
return true;
}
}
public boolean allSitesDispatchIdentically(CGNode node, CallSiteReference site) {
// Atom name = site.getDeclaredTarget().getName();
// Descriptor d = site.getDeclaredTarget().getDescriptor();
// if (name.equals(ExecuteAtom) && d.equals(ExecuteDesc)) {
// return false;
// } else {
// return true;
// }
// todo: fix me
return false;
}
public boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) {
if (targetMethod.getReference().equals(ExecuteMethod)) {
return true;
} else {
return false;
}
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
return EmptyIntSet.instance;
}
}

View File

@ -31,4 +31,9 @@ public class BitVectorSolver<T> extends DataflowSolver<T, BitVectorVariable> {
return new BitVectorVariable();
}
@Override
protected BitVectorVariable[] makeStmtRHS(int size) {
return new BitVectorVariable[size];
}
}

View File

@ -12,7 +12,6 @@ package com.ibm.wala.dataflow.graph;
import com.ibm.wala.fixpoint.BitVectorVariable;
import com.ibm.wala.fixpoint.FixedPointConstants;
import com.ibm.wala.fixpoint.IVariable;
/**
* Operator U(n) = U(n) U U(j)
@ -50,7 +49,7 @@ public class BitVectorUnion extends AbstractMeetOperator<BitVectorVariable> impl
* @see com.ibm.wala.dataflow.fixpoint.Operator#evaluate(com.ibm.wala.dataflow.fixpoint.IVariable[])
*/
@Override
public byte evaluate(BitVectorVariable lhs, @SuppressWarnings("rawtypes") IVariable[] rhs) throws IllegalArgumentException {
public byte evaluate(BitVectorVariable lhs, BitVectorVariable[] rhs) throws IllegalArgumentException {
if (lhs == null) {
throw new IllegalArgumentException("null lhs");
}

View File

@ -22,15 +22,20 @@ public class BooleanSolver<T> extends DataflowSolver<T, BooleanVariable> {
}
@Override
protected BooleanVariable makeNodeVariable(Object n, boolean IN) {
protected BooleanVariable makeNodeVariable(T n, boolean IN) {
return new BooleanVariable();
}
@Override
protected BooleanVariable makeEdgeVariable(Object src, Object dst) {
protected BooleanVariable makeEdgeVariable(T src, T dst) {
return new BooleanVariable();
}
@Override
protected BooleanVariable[] makeStmtRHS(int size) {
return new BooleanVariable[size];
}
}

View File

@ -12,7 +12,6 @@ package com.ibm.wala.dataflow.graph;
import com.ibm.wala.fixpoint.BooleanVariable;
import com.ibm.wala.fixpoint.FixedPointConstants;
import com.ibm.wala.fixpoint.IVariable;
/**
* Operator U(n) = U(n) U U(j)
@ -47,7 +46,7 @@ public class BooleanUnion extends AbstractMeetOperator<BooleanVariable> implemen
}
@Override
public byte evaluate(BooleanVariable lhs, @SuppressWarnings("rawtypes") IVariable[] rhs) throws NullPointerException {
public byte evaluate(BooleanVariable lhs, BooleanVariable[] rhs) throws NullPointerException {
if (rhs == null) {
throw new IllegalArgumentException("null rhs");
}

View File

@ -202,7 +202,7 @@ public abstract class DataflowSolver<T, V extends IVariable> extends DefaultFixe
int nPred = G.getPredNodeCount(node);
if (nPred >= meetThreshold) {
// todo: optimize further using unary operators when possible?
V[] rhs = (V[]) new IVariable[nPred];
V[] rhs = makeStmtRHS(nPred);
int i = 0;
for (Iterator<?> it2 = G.getPredNodes(node); it2.hasNext();) {
rhs[i++] = (functions.hasEdgeTransferFunctions()) ? getEdge(it2.next(), node) : getOut(it2.next());

View File

@ -101,6 +101,8 @@ public abstract class AbstractFixedPointSolver<T extends IVariable> implements I
*/
private boolean firstSolve = true;
protected abstract T[] makeStmtRHS(int size);
/**
* Some setup which occurs only before the first solve
*/
@ -331,6 +333,31 @@ public abstract class AbstractFixedPointSolver<T extends IVariable> implements I
return true;
}
protected class Statement extends GeneralStatement<T> {
public Statement(T lhs, AbstractOperator<T> operator, T op1, T op2, T op3) {
super(lhs, operator, op1, op2, op3);
}
public Statement(T lhs, AbstractOperator<T> operator, T op1, T op2) {
super(lhs, operator, op1, op2);
}
public Statement(T lhs, AbstractOperator<T> operator, T[] rhs) {
super(lhs, operator, rhs);
}
public Statement(T lhs, AbstractOperator<T> operator) {
super(lhs, operator);
}
@Override
protected T[] makeRHS(int size) {
return makeStmtRHS(size);
}
}
/**
* Add an equation with two operands on the right-hand side.
*
@ -342,7 +369,7 @@ public abstract class AbstractFixedPointSolver<T extends IVariable> implements I
public void newStatement(T lhs, AbstractOperator<T> operator, T op1, T op2, boolean toWorkList, boolean eager) {
// add to the list of graph
GeneralStatement<T> s = new GeneralStatement<T>(lhs, operator, op1, op2);
GeneralStatement<T> s = new Statement(lhs, operator, op1, op2);
if (getFixedPointSystem().containsStatement(s)) {
return;
}
@ -371,7 +398,7 @@ public abstract class AbstractFixedPointSolver<T extends IVariable> implements I
}
// add to the list of graph
lhs.setOrderNumber(nextOrderNumber++);
GeneralStatement<T> s = new GeneralStatement<T>(lhs, operator, op1, op2, op3);
GeneralStatement<T> s = new Statement(lhs, operator, op1, op2, op3);
if (getFixedPointSystem().containsStatement(s)) {
nextOrderNumber--;
return;
@ -390,11 +417,11 @@ public abstract class AbstractFixedPointSolver<T extends IVariable> implements I
* @param operator the operator
* @param rhs the operands on the rhs
*/
public void newStatement(T lhs, AbstractOperator<T> operator, IVariable[] rhs, boolean toWorkList, boolean eager) {
public void newStatement(T lhs, AbstractOperator<T> operator, T[] rhs, boolean toWorkList, boolean eager) {
// add to the list of graph
if (lhs != null)
lhs.setOrderNumber(nextOrderNumber++);
GeneralStatement<T> s = new GeneralStatement<T>(lhs, operator, rhs);
GeneralStatement<T> s = new Statement(lhs, operator, rhs);
if (getFixedPointSystem().containsStatement(s)) {
nextOrderNumber--;
return;

View File

@ -17,12 +17,11 @@ import com.ibm.wala.fixpoint.IVariable;
/**
* Represents a single step in an iterative solver
*/
@SuppressWarnings("rawtypes")
public class GeneralStatement<T extends IVariable> extends AbstractStatement<T, AbstractOperator<T>> {
public abstract class GeneralStatement<T extends IVariable<?>> extends AbstractStatement<T, AbstractOperator<T>> {
protected final T lhs;
protected final IVariable[] rhs;
protected final T[] rhs;
private final int hashCode;
@ -55,7 +54,7 @@ public class GeneralStatement<T extends IVariable> extends AbstractStatement<T,
* @param cell the cell in question
* @return true or false
*/
public boolean hasVariable(IVariable cell) {
public boolean hasVariable(T cell) {
if (lhs == cell) {
return true;
}
@ -98,7 +97,7 @@ public class GeneralStatement<T extends IVariable> extends AbstractStatement<T,
}
this.operator = operator;
this.lhs = lhs;
rhs = new IVariable[2];
rhs = makeRHS(2);
rhs[0] = op1;
rhs[1] = op2;
this.hashCode = makeHashCode();
@ -119,7 +118,7 @@ public class GeneralStatement<T extends IVariable> extends AbstractStatement<T,
throw new IllegalArgumentException("null operator");
}
this.operator = operator;
rhs = new IVariable[3];
rhs = makeRHS(3);
this.lhs = lhs;
rhs[0] = op1;
rhs[1] = op2;
@ -135,7 +134,7 @@ public class GeneralStatement<T extends IVariable> extends AbstractStatement<T,
* @param rhs the operands of the right-hand side in order
* @throws IllegalArgumentException if rhs is null
*/
public GeneralStatement(T lhs, AbstractOperator<T> operator, IVariable[] rhs) {
public GeneralStatement(T lhs, AbstractOperator<T> operator, T[] rhs) {
super();
if (operator == null) {
throw new IllegalArgumentException("null operator");
@ -166,6 +165,8 @@ public class GeneralStatement<T extends IVariable> extends AbstractStatement<T,
return result;
}
protected abstract T[] makeRHS(int size);
@Override
public int hashCode() {
return hashCode;
@ -177,7 +178,7 @@ public class GeneralStatement<T extends IVariable> extends AbstractStatement<T,
return false;
}
if (getClass().equals(o.getClass())) {
GeneralStatement other = (GeneralStatement) o;
GeneralStatement<?> other = (GeneralStatement<?>) o;
if (hashCode == other.hashCode) {
if (lhs == null || other.lhs == null) {
if (other.lhs != lhs) {
@ -208,7 +209,7 @@ public class GeneralStatement<T extends IVariable> extends AbstractStatement<T,
return operator;
}
public IVariable[] getRHS() {
public T[] getRHS() {
return rhs;
}
}

View File

@ -22,7 +22,7 @@ import com.ibm.wala.fixpoint.IVariable;
public abstract class NullaryOperator<T extends IVariable> extends AbstractOperator<T> implements FixedPointConstants {
@Override
public byte evaluate(T lhs, IVariable[] rhs) throws UnsupportedOperationException {
public byte evaluate(T lhs, T[] rhs) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**

View File

@ -28,7 +28,7 @@ public abstract class AbstractOperator<T extends IVariable> implements FixedPoin
* @return a code that indicates: 1) has the lhs value changed? 2) has this equation reached a fixed-point, in that we never have
* to evaluate the equation again, even if rhs operands change?
*/
public abstract byte evaluate(T lhs, IVariable[] rhs);
public abstract byte evaluate(T lhs, T[] rhs);
@Override
public abstract int hashCode();

View File

@ -38,7 +38,7 @@ public interface IFixedPointStatement<T extends IVariable> extends INodeWithNumb
* returns the list of free variables appearing in the right-hand side of the
* statement
*/
public IVariable[] getRHS();
public T[] getRHS();
/**
* Evaluate this statement, setting a new value for the left-hand side. The

View File

@ -39,7 +39,7 @@ public abstract class UnaryOperator<T extends IVariable> extends AbstractOperato
}
@Override
public byte evaluate(T lhs, IVariable[] rhs) throws UnimplementedError {
public byte evaluate(T lhs, T[] rhs) throws UnimplementedError {
// this should never be called. Use the other, more efficient form.
Assertions.UNREACHABLE();
return 0;

View File

@ -0,0 +1,7 @@
package com.ibm.wala.util.functions;
public interface VoidFunction<T> {
void apply(T v);
}

View File

@ -78,6 +78,8 @@ public class IntSetUtil {
MutableIntSet pCopy = makeMutableCopy(((DebuggingMutableIntSet) set).primaryImpl);
MutableIntSet sCopy = makeMutableCopy(((DebuggingMutableIntSet) set).secondaryImpl);
return new DebuggingMutableIntSet(pCopy, sCopy);
} else if (set instanceof EmptyIntSet) {
return IntSetUtil.make();
} else {
Assertions.UNREACHABLE(set.getClass().toString());
return null;