diff --git a/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/analysis/typeInference/AstJavaTypeInference.java b/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/analysis/typeInference/AstJavaTypeInference.java index ff09245a4..1d5107744 100644 --- a/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/analysis/typeInference/AstJavaTypeInference.java +++ b/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/analysis/typeInference/AstJavaTypeInference.java @@ -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++) { diff --git a/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/callgraph/AstJavaSSAPropagationCallGraphBuilder.java b/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/callgraph/AstJavaSSAPropagationCallGraphBuilder.java index 2191adf4d..1069234cc 100644 --- a/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/callgraph/AstJavaSSAPropagationCallGraphBuilder.java +++ b/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/callgraph/AstJavaSSAPropagationCallGraphBuilder.java @@ -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); } } diff --git a/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/callgraph/AstJavaZeroOneContainerCFABuilder.java b/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/callgraph/AstJavaZeroOneContainerCFABuilder.java index 6ce76e52d..fcd3eb2ec 100644 --- a/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/callgraph/AstJavaZeroOneContainerCFABuilder.java +++ b/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/callgraph/AstJavaZeroOneContainerCFABuilder.java @@ -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); diff --git a/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/callgraph/AstJavaZeroXCFABuilder.java b/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/callgraph/AstJavaZeroXCFABuilder.java index 9ab9e7a36..7713bab3a 100644 --- a/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/callgraph/AstJavaZeroXCFABuilder.java +++ b/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/callgraph/AstJavaZeroXCFABuilder.java @@ -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); diff --git a/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/translator/JavaCAst2IRTranslator.java b/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/translator/JavaCAst2IRTranslator.java index 83210910e..a372c47dc 100644 --- a/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/translator/JavaCAst2IRTranslator.java +++ b/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/translator/JavaCAst2IRTranslator.java @@ -74,7 +74,7 @@ public class JavaCAst2IRTranslator extends AstTranslator { } protected TypeReference defaultCatchType() { - return TypeReference.JavaLangException; + return TypeReference.JavaLangThrowable; } protected TypeReference makeType(CAstType type) { diff --git a/com.ibm.wala.cast.js.rhino.test/harness-src/com/ibm/wala/cast/js/test/TestForInLoopHackRhino.java b/com.ibm.wala.cast.js.rhino.test/harness-src/com/ibm/wala/cast/js/test/TestForInLoopHackRhino.java new file mode 100644 index 000000000..b7c2de1c8 --- /dev/null +++ b/com.ibm.wala.cast.js.rhino.test/harness-src/com/ibm/wala/cast/js/test/TestForInLoopHackRhino.java @@ -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()); + } + +} diff --git a/com.ibm.wala.cast.js.test/examples-src/pages/2.js b/com.ibm.wala.cast.js.test/examples-src/pages/2.js index dbf8299e0..f0be7085d 100644 --- a/com.ibm.wala.cast.js.test/examples-src/pages/2.js +++ b/com.ibm.wala.cast.js.test/examples-src/pages/2.js @@ -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); }; diff --git a/com.ibm.wala.cast.js.test/examples-src/tests/badforin.js b/com.ibm.wala.cast.js.test/examples-src/tests/badforin.js new file mode 100644 index 000000000..577c8c020 --- /dev/null +++ b/com.ibm.wala.cast.js.test/examples-src/tests/badforin.js @@ -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(); })(); + diff --git a/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestForInLoopHack.java b/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestForInLoopHack.java new file mode 100644 index 000000000..8d413803e --- /dev/null +++ b/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestForInLoopHack.java @@ -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); + } + } + }); + } + +} diff --git a/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestSimpleCallGraphShape.java b/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestSimpleCallGraphShape.java index 644bc0ff9..027605461 100644 --- a/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestSimpleCallGraphShape.java +++ b/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestSimpleCallGraphShape.java @@ -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>> computeIkIdToVns(PointerAnalysis pa) { // Created by reversing the points to mapping for local pointer keys. diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/JSSSAPropagationCallGraphBuilder.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/JSSSAPropagationCallGraphBuilder.java index f19dd76e0..72a49f75f 100755 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/JSSSAPropagationCallGraphBuilder.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/JSSSAPropagationCallGraphBuilder.java @@ -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 { - 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); + } + } + + } diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/JSZeroOrOneXCFABuilder.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/JSZeroOrOneXCFABuilder.java index 5c20b8f3d..1c41d8200 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/JSZeroOrOneXCFABuilder.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/JSZeroOrOneXCFABuilder.java @@ -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); diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/JavaScriptConstructorContextSelector.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/JavaScriptConstructorContextSelector.java index adfdd1de7..fe416dfb7 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/JavaScriptConstructorContextSelector.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/JavaScriptConstructorContextSelector.java @@ -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 { diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/loader/JSCallSiteReference.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/loader/JSCallSiteReference.java index 84a768724..debf4d214 100755 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/loader/JSCallSiteReference.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/loader/JSCallSiteReference.java @@ -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; + } + + } diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/loader/JavaScriptLoader.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/loader/JavaScriptLoader.java index e0ec9291e..6c78cc86d 100755 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/loader/JavaScriptLoader.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/loader/JavaScriptLoader.java @@ -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; + } } } diff --git a/com.ibm.wala.cast.test/harness-src/com/ibm/wala/cast/test/TestCallGraphShape.java b/com.ibm.wala.cast.test/harness-src/com/ibm/wala/cast/test/TestCallGraphShape.java index dc5ce743d..168d4f2ea 100644 --- a/com.ibm.wala.cast.test/harness-src/com/ibm/wala/cast/test/TestCallGraphShape.java +++ b/com.ibm.wala.cast.test/harness-src/com/ibm/wala/cast/test/TestCallGraphShape.java @@ -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); } } } diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstCallGraph.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstCallGraph.java index 45daf3378..d7086067f 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstCallGraph.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstCallGraph.java @@ -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; diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstSSAPropagationCallGraphBuilder.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstSSAPropagationCallGraphBuilder.java index 67b408235..427ce5c1e 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstSSAPropagationCallGraphBuilder.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstSSAPropagationCallGraphBuilder.java @@ -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 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() { - 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)); diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/CrossLanguageContextSelector.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/CrossLanguageContextSelector.java index a27b351aa..5f1f470bd 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/CrossLanguageContextSelector.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/CrossLanguageContextSelector.java @@ -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); + } } diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/MiscellaneousHacksContextSelector.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/MiscellaneousHacksContextSelector.java index 192b33278..9036635de 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/MiscellaneousHacksContextSelector.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/MiscellaneousHacksContextSelector.java @@ -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; - } -} + } diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ReflectedFieldPointerKey.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ReflectedFieldPointerKey.java index 9c156eeee..a770f2986 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ReflectedFieldPointerKey.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ReflectedFieldPointerKey.java @@ -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() { diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ScopeMappingInstanceKeys.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ScopeMappingInstanceKeys.java index 6c8df3cda..dfa0d8472 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ScopeMappingInstanceKeys.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ScopeMappingInstanceKeys.java @@ -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 parentNodes) { + Iterator 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() { diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ScopeMappingKeysContextSelector.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ScopeMappingKeysContextSelector.java index 0a71615dd..ff5b93830 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ScopeMappingKeysContextSelector.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ScopeMappingKeysContextSelector.java @@ -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; + } + + } diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AbstractLexicalInvoke.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AbstractLexicalInvoke.java index 6a5121525..cc44a0ac9 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AbstractLexicalInvoke.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AbstractLexicalInvoke.java @@ -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) { diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/CFGTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/CFGTest.java index 1d14c4339..930ca720b 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/CFGTest.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/ir/CFGTest.java @@ -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]))); + } + } + } } diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassFactoryContextInterpreter.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassFactoryContextInterpreter.java index 6e3de6d9e..10ead8f3b 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassFactoryContextInterpreter.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassFactoryContextInterpreter.java @@ -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()); } /* diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassFactoryContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassFactoryContextSelector.java index 194e68b38..3f9c6c664 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassFactoryContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassFactoryContextSelector.java @@ -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; } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassNewInstanceContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassNewInstanceContextSelector.java index 5b04fc49e..248f85e27 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassNewInstanceContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ClassNewInstanceContextSelector.java @@ -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 Class.newInstance() call.) Otherwise, return null. */ - 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; + } + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryContextSelector.java index c6f2fa034..7385a7bde 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryContextSelector.java @@ -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; + } + } diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/GetClassContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/GetClassContextSelector.java index c47d565a8..fa69db771 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/GetClassContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/GetClassContextSelector.java @@ -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; + } + } + } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/JavaLangClassContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/JavaLangClassContextSelector.java index 2a83d24f1..800e8b6b8 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/JavaLangClassContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/JavaLangClassContextSelector.java @@ -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; + } + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/JavaTypeContext.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/JavaTypeContext.java index c5b1e5d3c..d3b95b55b 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/JavaTypeContext.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/JavaTypeContext.java @@ -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; } } diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectionContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectionContextSelector.java index 7526cfa9a..aedb0b219 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectionContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectionContextSelector.java @@ -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); diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectiveInvocationSelector.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectiveInvocationSelector.java index daf8e0b3d..034d4e1ab 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectiveInvocationSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/ReflectiveInvocationSelector.java @@ -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 { *
  • Otherwise, return a new {@link ReceiverInstanceContext} for receiver. * */ - 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; + } + } } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/stackMachine/AbstractIntStackMachine.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/stackMachine/AbstractIntStackMachine.java index 2c8edee3e..0f655e381 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/stackMachine/AbstractIntStackMachine.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/stackMachine/AbstractIntStackMachine.java @@ -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; diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/TypeInference.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/TypeInference.java index 8447f7fee..0aa9eb810 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/TypeInference.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/typeInference/TypeInference.java @@ -296,7 +296,7 @@ public class TypeInference extends SSAInference 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 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 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 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 implements FixedPo return ret; } + + @Override + protected TypeVariable[] makeStmtRHS(int size) { + return new TypeVariable[size]; + } } diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/ssa/SSAInference.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/ssa/SSAInference.java index 9695a27ea..cff41b1b8 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/ssa/SSAInference.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/ssa/SSAInference.java @@ -112,7 +112,7 @@ public abstract class SSAInference extends DefaultFixedPoin newStatement(def, (NullaryOperator) 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)); diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/ThisFilteringHeapModel.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/ThisFilteringHeapModel.java index 4d5920989..2f3c2fff1 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/ThisFilteringHeapModel.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/alg/ThisFilteringHeapModel.java @@ -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; diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextKey.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextKey.java index 57458dc70..40f02748e 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextKey.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextKey.java @@ -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) + }; } diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextSelector.java index ca4a5d7a7..d1f5b2b48 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/ContextSelector.java @@ -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); } diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ContextInsensitiveSelector.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ContextInsensitiveSelector.java index 06a02179d..d9bac12fa 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ContextInsensitiveSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ContextInsensitiveSelector.java @@ -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; - } } diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/DefaultContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/DefaultContextSelector.java index 5ad738a07..06c6e7140 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/DefaultContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/DefaultContextSelector.java @@ -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); + } + } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/DelegatingContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/DelegatingContextSelector.java index 98dc80fcc..b4a8eba48 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/DelegatingContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/DelegatingContextSelector.java @@ -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)); + } + } \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/CloneContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/CloneContextSelector.java index b060fab61..7b4a9339b 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/CloneContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/CloneContextSelector.java @@ -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; - } - } } diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/FilteredPointerKey.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/FilteredPointerKey.java index d2b4d6feb..57c35bf29 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/FilteredPointerKey.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/FilteredPointerKey.java @@ -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; + } } /** diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationCallGraphBuilder.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationCallGraphBuilder.java index 4d2ce03b0..5bd2103f7 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationCallGraphBuilder.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationCallGraphBuilder.java @@ -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 */ diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationSystem.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationSystem.java index 5bfc3d2da..e25c40ef1 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationSystem.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationSystem.java @@ -192,7 +192,7 @@ public class PropagationSystem extends DefaultFixedPointSolver 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 op, PointerKey arg0, PointerKey arg1) { if (DEBUG) { System.err.println("add constraint D: " + op + " " + arg0); @@ -888,4 +903,9 @@ public class PropagationSystem extends DefaultFixedPointSolver 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 pks = new ArrayList(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 implements IPointerOperator { + final class DispatchOperator extends AbstractOperator 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 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 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 targets = HashSetFactory.make(); + VoidFunction f = new VoidFunction() { + 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) * diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/TargetMethodContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/TargetMethodContextSelector.java index f28632d41..78bf13f7d 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/TargetMethodContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/TargetMethodContextSelector.java @@ -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; - } } diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallStringContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallStringContextSelector.java index 45f1c2fa0..a302cd1ed 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallStringContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/CallStringContextSelector.java @@ -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; + } + } diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ContainerContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ContainerContextSelector.java index 502d01653..bda938a09 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ContainerContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ContainerContextSelector.java @@ -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; + } } + } diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/OneLevelSiteContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/OneLevelSiteContextSelector.java index 97c72cbeb..7533db134 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/OneLevelSiteContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/OneLevelSiteContextSelector.java @@ -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); + } + } diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ZeroXCFABuilder.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ZeroXCFABuilder.java index bb4896c3a..1cd47880d 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ZeroXCFABuilder.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ZeroXCFABuilder.java @@ -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); diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/nCFABuilder.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/nCFABuilder.java index dcc4ad488..cc20eed3f 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/nCFABuilder.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/nCFABuilder.java @@ -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); diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/rta/AbstractRTABuilder.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/rta/AbstractRTABuilder.java index 2f81d81b7..15fd7122c 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/rta/AbstractRTABuilder.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/rta/AbstractRTABuilder.java @@ -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; } diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/rta/BasicRTABuilder.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/rta/BasicRTABuilder.java index b56bb8496..71095292f 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/rta/BasicRTABuilder.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/rta/BasicRTABuilder.java @@ -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! diff --git a/com.ibm.wala.core/src/com/ibm/wala/ssa/SymbolTable.java b/com.ibm.wala.core/src/com/ibm/wala/ssa/SymbolTable.java index 9b6ce7eca..3b18f645c 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ssa/SymbolTable.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ssa/SymbolTable.java @@ -36,6 +36,8 @@ public class SymbolTable implements Cloneable { */ private HashMap 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(); diff --git a/com.ibm.wala.core/src/com/ibm/wala/ssa/analysis/DeadAssignmentElimination.java b/com.ibm.wala.core/src/com/ibm/wala/ssa/analysis/DeadAssignmentElimination.java index 815c3b8ee..be9eff3a5 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ssa/analysis/DeadAssignmentElimination.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ssa/analysis/DeadAssignmentElimination.java @@ -186,5 +186,10 @@ public class DeadAssignmentElimination { } } + @Override + protected BooleanVariable[] makeStmtRHS(int size) { + return new BooleanVariable[size]; + } + } } diff --git a/com.ibm.wala.j2ee/src/com/ibm/wala/j2ee/J2EEContextSelector.java b/com.ibm.wala.j2ee/src/com/ibm/wala/j2ee/J2EEContextSelector.java index 3eb47a59a..388bfc30a 100644 --- a/com.ibm.wala.j2ee/src/com/ibm/wala/j2ee/J2EEContextSelector.java +++ b/com.ibm.wala.j2ee/src/com/ibm/wala/j2ee/J2EEContextSelector.java @@ -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; } } diff --git a/com.ibm.wala.util/src/com/ibm/wala/dataflow/graph/BitVectorSolver.java b/com.ibm.wala.util/src/com/ibm/wala/dataflow/graph/BitVectorSolver.java index f4ea979c4..40ed3a1b9 100644 --- a/com.ibm.wala.util/src/com/ibm/wala/dataflow/graph/BitVectorSolver.java +++ b/com.ibm.wala.util/src/com/ibm/wala/dataflow/graph/BitVectorSolver.java @@ -31,4 +31,9 @@ public class BitVectorSolver extends DataflowSolver { return new BitVectorVariable(); } + + @Override + protected BitVectorVariable[] makeStmtRHS(int size) { + return new BitVectorVariable[size]; + } } diff --git a/com.ibm.wala.util/src/com/ibm/wala/dataflow/graph/BitVectorUnion.java b/com.ibm.wala.util/src/com/ibm/wala/dataflow/graph/BitVectorUnion.java index b13ecf11d..84a827dfc 100644 --- a/com.ibm.wala.util/src/com/ibm/wala/dataflow/graph/BitVectorUnion.java +++ b/com.ibm.wala.util/src/com/ibm/wala/dataflow/graph/BitVectorUnion.java @@ -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 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"); } diff --git a/com.ibm.wala.util/src/com/ibm/wala/dataflow/graph/BooleanSolver.java b/com.ibm.wala.util/src/com/ibm/wala/dataflow/graph/BooleanSolver.java index b830a85f0..0bc0d7425 100644 --- a/com.ibm.wala.util/src/com/ibm/wala/dataflow/graph/BooleanSolver.java +++ b/com.ibm.wala.util/src/com/ibm/wala/dataflow/graph/BooleanSolver.java @@ -22,15 +22,20 @@ public class BooleanSolver extends DataflowSolver { } @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]; + } + } diff --git a/com.ibm.wala.util/src/com/ibm/wala/dataflow/graph/BooleanUnion.java b/com.ibm.wala.util/src/com/ibm/wala/dataflow/graph/BooleanUnion.java index 871457cf3..140b8bda5 100644 --- a/com.ibm.wala.util/src/com/ibm/wala/dataflow/graph/BooleanUnion.java +++ b/com.ibm.wala.util/src/com/ibm/wala/dataflow/graph/BooleanUnion.java @@ -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 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"); } diff --git a/com.ibm.wala.util/src/com/ibm/wala/dataflow/graph/DataflowSolver.java b/com.ibm.wala.util/src/com/ibm/wala/dataflow/graph/DataflowSolver.java index 288f6a1de..7e109b555 100644 --- a/com.ibm.wala.util/src/com/ibm/wala/dataflow/graph/DataflowSolver.java +++ b/com.ibm.wala.util/src/com/ibm/wala/dataflow/graph/DataflowSolver.java @@ -202,7 +202,7 @@ public abstract class DataflowSolver 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()); diff --git a/com.ibm.wala.util/src/com/ibm/wala/fixedpoint/impl/AbstractFixedPointSolver.java b/com.ibm.wala.util/src/com/ibm/wala/fixedpoint/impl/AbstractFixedPointSolver.java index 4e5788f33..acd6c27de 100644 --- a/com.ibm.wala.util/src/com/ibm/wala/fixedpoint/impl/AbstractFixedPointSolver.java +++ b/com.ibm.wala.util/src/com/ibm/wala/fixedpoint/impl/AbstractFixedPointSolver.java @@ -101,6 +101,8 @@ public abstract class AbstractFixedPointSolver 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 implements I return true; } + protected class Statement extends GeneralStatement { + + public Statement(T lhs, AbstractOperator operator, T op1, T op2, T op3) { + super(lhs, operator, op1, op2, op3); + } + + public Statement(T lhs, AbstractOperator operator, T op1, T op2) { + super(lhs, operator, op1, op2); + } + + public Statement(T lhs, AbstractOperator operator, T[] rhs) { + super(lhs, operator, rhs); + } + + public Statement(T lhs, AbstractOperator 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 implements I public void newStatement(T lhs, AbstractOperator operator, T op1, T op2, boolean toWorkList, boolean eager) { // add to the list of graph - GeneralStatement s = new GeneralStatement(lhs, operator, op1, op2); + GeneralStatement s = new Statement(lhs, operator, op1, op2); if (getFixedPointSystem().containsStatement(s)) { return; } @@ -371,7 +398,7 @@ public abstract class AbstractFixedPointSolver implements I } // add to the list of graph lhs.setOrderNumber(nextOrderNumber++); - GeneralStatement s = new GeneralStatement(lhs, operator, op1, op2, op3); + GeneralStatement s = new Statement(lhs, operator, op1, op2, op3); if (getFixedPointSystem().containsStatement(s)) { nextOrderNumber--; return; @@ -390,11 +417,11 @@ public abstract class AbstractFixedPointSolver implements I * @param operator the operator * @param rhs the operands on the rhs */ - public void newStatement(T lhs, AbstractOperator operator, IVariable[] rhs, boolean toWorkList, boolean eager) { + public void newStatement(T lhs, AbstractOperator operator, T[] rhs, boolean toWorkList, boolean eager) { // add to the list of graph if (lhs != null) lhs.setOrderNumber(nextOrderNumber++); - GeneralStatement s = new GeneralStatement(lhs, operator, rhs); + GeneralStatement s = new Statement(lhs, operator, rhs); if (getFixedPointSystem().containsStatement(s)) { nextOrderNumber--; return; diff --git a/com.ibm.wala.util/src/com/ibm/wala/fixedpoint/impl/GeneralStatement.java b/com.ibm.wala.util/src/com/ibm/wala/fixedpoint/impl/GeneralStatement.java index 5a02011b9..06627dd1c 100644 --- a/com.ibm.wala.util/src/com/ibm/wala/fixedpoint/impl/GeneralStatement.java +++ b/com.ibm.wala.util/src/com/ibm/wala/fixedpoint/impl/GeneralStatement.java @@ -17,12 +17,11 @@ import com.ibm.wala.fixpoint.IVariable; /** * Represents a single step in an iterative solver */ -@SuppressWarnings("rawtypes") -public class GeneralStatement extends AbstractStatement> { +public abstract class GeneralStatement> extends AbstractStatement> { protected final T lhs; - protected final IVariable[] rhs; + protected final T[] rhs; private final int hashCode; @@ -55,7 +54,7 @@ public class GeneralStatement extends AbstractStatement extends AbstractStatement extends AbstractStatement extends AbstractStatement operator, IVariable[] rhs) { + public GeneralStatement(T lhs, AbstractOperator operator, T[] rhs) { super(); if (operator == null) { throw new IllegalArgumentException("null operator"); @@ -166,6 +165,8 @@ public class GeneralStatement extends AbstractStatement extends AbstractStatement other = (GeneralStatement) o; if (hashCode == other.hashCode) { if (lhs == null || other.lhs == null) { if (other.lhs != lhs) { @@ -208,7 +209,7 @@ public class GeneralStatement extends AbstractStatement extends AbstractOperator implements FixedPointConstants { @Override - public byte evaluate(T lhs, IVariable[] rhs) throws UnsupportedOperationException { + public byte evaluate(T lhs, T[] rhs) throws UnsupportedOperationException { throw new UnsupportedOperationException(); } /** diff --git a/com.ibm.wala.util/src/com/ibm/wala/fixpoint/AbstractOperator.java b/com.ibm.wala.util/src/com/ibm/wala/fixpoint/AbstractOperator.java index 2524e13b4..d628fbf4e 100644 --- a/com.ibm.wala.util/src/com/ibm/wala/fixpoint/AbstractOperator.java +++ b/com.ibm.wala.util/src/com/ibm/wala/fixpoint/AbstractOperator.java @@ -28,7 +28,7 @@ public abstract class AbstractOperator 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(); diff --git a/com.ibm.wala.util/src/com/ibm/wala/fixpoint/IFixedPointStatement.java b/com.ibm.wala.util/src/com/ibm/wala/fixpoint/IFixedPointStatement.java index b9dfad084..b9b4e0c14 100644 --- a/com.ibm.wala.util/src/com/ibm/wala/fixpoint/IFixedPointStatement.java +++ b/com.ibm.wala.util/src/com/ibm/wala/fixpoint/IFixedPointStatement.java @@ -38,7 +38,7 @@ public interface IFixedPointStatement 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 diff --git a/com.ibm.wala.util/src/com/ibm/wala/fixpoint/UnaryOperator.java b/com.ibm.wala.util/src/com/ibm/wala/fixpoint/UnaryOperator.java index 5add28799..4154389df 100644 --- a/com.ibm.wala.util/src/com/ibm/wala/fixpoint/UnaryOperator.java +++ b/com.ibm.wala.util/src/com/ibm/wala/fixpoint/UnaryOperator.java @@ -39,7 +39,7 @@ public abstract class UnaryOperator 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; diff --git a/com.ibm.wala.util/src/com/ibm/wala/util/functions/VoidFunction.java b/com.ibm.wala.util/src/com/ibm/wala/util/functions/VoidFunction.java new file mode 100644 index 000000000..f3ff46656 --- /dev/null +++ b/com.ibm.wala.util/src/com/ibm/wala/util/functions/VoidFunction.java @@ -0,0 +1,7 @@ +package com.ibm.wala.util.functions; + +public interface VoidFunction { + + void apply(T v); + +} diff --git a/com.ibm.wala.util/src/com/ibm/wala/util/intset/IntSetUtil.java b/com.ibm.wala.util/src/com/ibm/wala/util/intset/IntSetUtil.java index 9bdf498f2..27f2e76cd 100644 --- a/com.ibm.wala.util/src/com/ibm/wala/util/intset/IntSetUtil.java +++ b/com.ibm.wala.util/src/com/ibm/wala/util/intset/IntSetUtil.java @@ -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;