diff --git a/com.ibm.wala.cast.java.jdt.test/launchers/JDTJava15IRTests.launch b/com.ibm.wala.cast.java.jdt.test/launchers/JDTJava15IRTests.launch index 2314e8e51..fdd62d650 100644 --- a/com.ibm.wala.cast.java.jdt.test/launchers/JDTJava15IRTests.launch +++ b/com.ibm.wala.cast.java.jdt.test/launchers/JDTJava15IRTests.launch @@ -1,4 +1,4 @@ - + @@ -11,7 +11,8 @@ - + + @@ -24,6 +25,7 @@ + @@ -31,9 +33,13 @@ + + + + diff --git a/com.ibm.wala.cast.java.jdt.test/launchers/JDTJavaIRTests.launch b/com.ibm.wala.cast.java.jdt.test/launchers/JDTJavaIRTests.launch index 79a80c11e..085e21a68 100644 --- a/com.ibm.wala.cast.java.jdt.test/launchers/JDTJavaIRTests.launch +++ b/com.ibm.wala.cast.java.jdt.test/launchers/JDTJavaIRTests.launch @@ -1,4 +1,4 @@ - + @@ -11,7 +11,8 @@ - + + @@ -24,16 +25,21 @@ + - + + + + + diff --git a/com.ibm.wala.cast.java.polyglot.test/launchers/PolyglotJavaIRTests.launch b/com.ibm.wala.cast.java.polyglot.test/launchers/PolyglotJavaIRTests.launch index b38b725e9..ce61660c2 100644 --- a/com.ibm.wala.cast.java.polyglot.test/launchers/PolyglotJavaIRTests.launch +++ b/com.ibm.wala.cast.java.polyglot.test/launchers/PolyglotJavaIRTests.launch @@ -1,4 +1,4 @@ - + @@ -11,7 +11,9 @@ + + diff --git a/com.ibm.wala.cast.java.test/src/com/ibm/wala/cast/java/test/IRTests.java b/com.ibm.wala.cast.java.test/src/com/ibm/wala/cast/java/test/IRTests.java index bcdf2d1c4..9332aee09 100644 --- a/com.ibm.wala.cast.java.test/src/com/ibm/wala/cast/java/test/IRTests.java +++ b/com.ibm.wala.cast.java.test/src/com/ibm/wala/cast/java/test/IRTests.java @@ -27,6 +27,7 @@ import java.util.jar.JarFile; import org.junit.Assert; +import com.ibm.wala.cast.ir.translator.AstTranslator; import com.ibm.wala.cast.java.client.JavaSourceAnalysisEngine; import com.ibm.wala.cast.java.ipa.callgraph.JavaSourceAnalysisScope; import com.ibm.wala.classLoader.IClass; @@ -282,6 +283,9 @@ public abstract class IRTests { public Pair runTest(Collection sources, List libs, String[] mainClassDescriptors, List ca, boolean assertReachable) { try { + boolean currentState = AstTranslator.NEW_LEXICAL; + AstTranslator.NEW_LEXICAL = false; + JavaSourceAnalysisEngine engine = getAnalysisEngine(mainClassDescriptors); populateScope(engine, sources, libs); @@ -297,6 +301,8 @@ public abstract class IRTests { IRAssertion.check(callGraph); } + AstTranslator.NEW_LEXICAL = currentState; + return Pair.make(callGraph, engine.getPointerAnalysis()); } catch (Exception e) { 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 1a29296f4..1c4963bca 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 @@ -272,7 +272,7 @@ public class AstJavaSSAPropagationCallGraphBuilder extends AstSSAPropagationCall } public void visitJavaInvoke(AstJavaInvokeInstruction instruction) { - visitInvokeInternal(instruction); + visitInvokeInternal(instruction, new DefaultInvariantComputer()); } } diff --git a/com.ibm.wala.cast.js.html.nu_validator/.classpath b/com.ibm.wala.cast.js.html.nu_validator/.classpath index abd692151..9950a85d6 100644 --- a/com.ibm.wala.cast.js.html.nu_validator/.classpath +++ b/com.ibm.wala.cast.js.html.nu_validator/.classpath @@ -2,8 +2,8 @@ - - + + diff --git a/com.ibm.wala.cast.js.rhino/source/com/ibm/wala/cast/js/translator/CAstRhinoTranslator.java b/com.ibm.wala.cast.js.rhino/source/com/ibm/wala/cast/js/translator/CAstRhinoTranslator.java index eb57e918e..b771a8f7e 100644 --- a/com.ibm.wala.cast.js.rhino/source/com/ibm/wala/cast/js/translator/CAstRhinoTranslator.java +++ b/com.ibm.wala.cast.js.rhino/source/com/ibm/wala/cast/js/translator/CAstRhinoTranslator.java @@ -14,13 +14,9 @@ import java.io.IOException; import java.util.LinkedList; import java.util.List; - import com.ibm.wala.cast.ir.translator.TranslatorToCAst; -import com.ibm.wala.cast.js.translator.PropertyReadExpander.ExpanderKey; -import com.ibm.wala.cast.tree.CAst; import com.ibm.wala.cast.tree.CAstEntity; import com.ibm.wala.cast.tree.impl.CAstImpl; -import com.ibm.wala.cast.tree.impl.CAstRewriter; import com.ibm.wala.cast.tree.impl.CAstRewriter.CopyKey; import com.ibm.wala.cast.tree.impl.CAstRewriter.RewriteContext; import com.ibm.wala.cast.tree.impl.CAstRewriterFactory; @@ -35,12 +31,7 @@ public class CAstRhinoTranslator implements TranslatorToCAst { public CAstRhinoTranslator(SourceModule M, boolean replicateForDoLoops) { this.M = M; this.replicateForDoLoops = replicateForDoLoops; - this.addRewriter(new CAstRewriterFactory() { - public CAstRewriter createCAstRewriter(CAst ast) { - return new PropertyReadExpander(ast); - } - }, true); - } + } public , K extends CopyKey> void addRewriter(CAstRewriterFactory factory, boolean prepend) { if(prepend) diff --git a/com.ibm.wala.cast.js.rhino/source/com/ibm/wala/cast/js/translator/RhinoToAstTranslator.java b/com.ibm.wala.cast.js.rhino/source/com/ibm/wala/cast/js/translator/RhinoToAstTranslator.java index cfd298b98..4b33e9fe9 100755 --- a/com.ibm.wala.cast.js.rhino/source/com/ibm/wala/cast/js/translator/RhinoToAstTranslator.java +++ b/com.ibm.wala.cast.js.rhino/source/com/ibm/wala/cast/js/translator/RhinoToAstTranslator.java @@ -168,13 +168,12 @@ public class RhinoToAstTranslator { } } - private static class BaseCollectingContext extends JavaScriptTranslatorToCAst.BaseCollectingContext implements WalkContext { + private static class MemberDestructuringContext extends JavaScriptTranslatorToCAst.MemberDestructuringContext implements WalkContext { + + protected MemberDestructuringContext(WalkContext parent, Node initialBaseFor, int operationIndex) { + super(parent, initialBaseFor, operationIndex); + } - BaseCollectingContext(WalkContext parent, Node initialBaseFor, - String baseVar) { - super(parent, initialBaseFor, baseVar); - } - } private static class BreakContext extends JavaScriptTranslatorToCAst.BreakContext implements WalkContext { @@ -201,6 +200,22 @@ public class RhinoToAstTranslator { } + private String operationReceiverName(int operationIndex) { + return "$$destructure$rcvr" + operationIndex; + } + + private CAstNode operationReceiverVar(int operationIndex) { + return Ast.makeNode(CAstNode.VAR, Ast.makeConstant(operationReceiverName(operationIndex))); + } + + private String operationElementName(int operationIndex) { + return "$$destructure$elt" + operationIndex; + } + + private CAstNode operationElementVar(int operationIndex) { + return Ast.makeNode(CAstNode.VAR, Ast.makeConstant(operationElementName(operationIndex))); + } + private CAstNode translateOpcode(int nodeType) { switch (nodeType) { case Token.POS: @@ -327,7 +342,7 @@ public class RhinoToAstTranslator { int i = 0; CAstNode arguments[] = new CAstNode[nargs]; arguments[i++] = fun; - assert callee.equals(STANDARD_CALL_FN_NAME) || callee.equals(CTOR_CALL_FN_NAME); + // assert callee.equals(STANDARD_CALL_FN_NAME) || callee.equals(CTOR_CALL_FN_NAME); arguments[i++] = Ast.makeConstant(callee); if (thisptr != null) arguments[i++] = thisptr; @@ -718,19 +733,20 @@ public class RhinoToAstTranslator { } private CAstNode visitObjectRead(AstNode n, AstNode objAst, CAstNode elt, WalkContext context) { - CAstNode obj = visit(objAst, context); - String baseVar = context.getBaseVarIfRelevant(n); - - CAstNode get, result; - if (baseVar != null) { - result = Ast.makeNode(CAstNode.BLOCK_EXPR, - Ast.makeNode(CAstNode.ASSIGN, Ast.makeNode(CAstNode.VAR, Ast.makeConstant(baseVar)), obj), - get = Ast.makeNode(CAstNode.OBJECT_REF, Ast.makeNode(CAstNode.VAR, Ast.makeConstant(baseVar)), elt)); - } else { - result = get = Ast.makeNode(CAstNode.OBJECT_REF, obj, elt); - } + CAstNode get, result; + int operationIndex = context.setOperation(n); - if (context.getCatchTarget() != null) { + CAstNode obj = visit(objAst, context); + if (operationIndex != -1) { + get = null; + result = Ast.makeNode(CAstNode.BLOCK_EXPR, + Ast.makeNode(CAstNode.ASSIGN, operationReceiverVar(operationIndex), obj), + Ast.makeNode(CAstNode.ASSIGN, operationElementVar(operationIndex), elt)); + } else { + result = get = Ast.makeNode(CAstNode.OBJECT_REF, obj, elt); + } + + if (get != null && context.getCatchTarget() != null) { context.cfg().map(get, get); context.cfg().add(get, context.getCatchTarget(), JavaScriptTypes.TypeError); } @@ -864,27 +880,34 @@ public class RhinoToAstTranslator { return args; } - private static final String baseVarName = "$$-base-$$"; - @Override public CAstNode visitFunctionCall(FunctionCall n, WalkContext context) { if (!isPrimitiveCall(context, n)) { - CAstNode base = Ast.makeNode(CAstNode.VAR, Ast.makeConstant(baseVarName)); AstNode callee = n.getTarget(); - WalkContext child = new BaseCollectingContext(context, callee, baseVarName); + int thisBaseVarNum = ++baseVarNum; + WalkContext child = new MemberDestructuringContext(context, callee, thisBaseVarNum); CAstNode fun = visit(callee, child); // the first actual parameter appearing within the parentheses of the // call (i.e., possibly excluding the 'this' parameter) CAstNode[] args = gatherCallArguments(n, context); - if (child.foundBase(callee)) - return Ast.makeNode( - CAstNode.LOCAL_SCOPE, - Ast.makeNode(CAstNode.BLOCK_EXPR, - Ast.makeNode(CAstNode.DECL_STMT, Ast.makeConstant(new CAstSymbolImpl(baseVarName)), Ast.makeConstant(null)), - makeCall(fun, base, args, context))); - else - return makeCall(fun, makeVarRef(JSSSAPropagationCallGraphBuilder.GLOBAL_OBJ_VAR_NAME), args, context); + if (child.foundMemberOperation(callee)) + return + Ast.makeNode(CAstNode.LOCAL_SCOPE, + Ast.makeNode(CAstNode.BLOCK_EXPR, + Ast.makeNode(CAstNode.DECL_STMT, + Ast.makeConstant(new CAstSymbolImpl(operationReceiverName(thisBaseVarNum))), + Ast.makeConstant(null)), + Ast.makeNode(CAstNode.DECL_STMT, + Ast.makeConstant(new CAstSymbolImpl(operationElementName(thisBaseVarNum))), + Ast.makeConstant(null)), + fun, + makeCall(operationElementVar(thisBaseVarNum), operationReceiverVar(thisBaseVarNum), args, context, "dispatch"))); + else { + CAstNode globalRef = makeVarRef(JSSSAPropagationCallGraphBuilder.GLOBAL_OBJ_VAR_NAME); + context.cfg().map(globalRef, globalRef); + return makeCall(fun, globalRef, args, context); + } } else { return Ast.makeNode(CAstNode.PRIMITIVE, gatherCallArguments(n, context)); } @@ -992,7 +1015,9 @@ public class RhinoToAstTranslator { switch (node.getType()) { case Token.THIS: { if (arg.top() instanceof ScriptNode && !(arg.top() instanceof FunctionNode)) { - return makeVarRef(JSSSAPropagationCallGraphBuilder.GLOBAL_OBJ_VAR_NAME); + CAstNode globalRef = makeVarRef(JSSSAPropagationCallGraphBuilder.GLOBAL_OBJ_VAR_NAME); + arg.cfg().map(globalRef, globalRef); + return globalRef; } else { return Ast.makeNode(CAstNode.VAR, Ast.makeConstant("this")); } @@ -2249,6 +2274,8 @@ private CAstNode[] walkChildren(final Node n, WalkContext context) { private int anonymousCounter = 0; + private int baseVarNum = 0; + private final DoLoopTranslator doLoopTranslator; public RhinoToAstTranslator(CAst Ast, SourceModule M, String scriptName, boolean replicateForDoLoops) { diff --git a/com.ibm.wala.cast.js.test/examples-src/tests/dispatch.js b/com.ibm.wala.cast.js.test/examples-src/tests/dispatch.js new file mode 100644 index 000000000..6d952aef9 --- /dev/null +++ b/com.ibm.wala.cast.js.test/examples-src/tests/dispatch.js @@ -0,0 +1,33 @@ +var left = { + + inner: function left_inner(x) { + return x+1; + }, + + outer: function left_outer(x) { + return this.inner(x+1); + } + +}; + +var right = { + + inner: function right_inner(x) { + return Math.abs(x); + }, + + outer: function right_outer(x) { + return this.inner(-x); + } + +}; + +var x = 3; +if (x > Math.random()) { + x = left; +} else { + x = right; +} + +x.outer(7); + diff --git a/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/JSCallGraphBuilderUtil.java b/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/JSCallGraphBuilderUtil.java index 9493a3a9c..088a614bd 100755 --- a/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/JSCallGraphBuilderUtil.java +++ b/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/JSCallGraphBuilderUtil.java @@ -111,7 +111,7 @@ public class JSCallGraphBuilderUtil extends com.ibm.wala.cast.js.ipa.callgraph.J IllegalArgumentException, CancelException { PropagationCallGraphBuilder b = makeScriptCGBuilder(dir, name, builderType); CallGraph CG = b.makeCallGraph(b.getOptions()); - dumpCG(b.getPointerAnalysis(), CG); + // dumpCG(b.getPointerAnalysis(), CG); return CG; } @@ -119,7 +119,7 @@ public class JSCallGraphBuilderUtil extends com.ibm.wala.cast.js.ipa.callgraph.J CancelException { PropagationCallGraphBuilder b = makeCGBuilder(makeLoaders(), scripts, builderType, irFactory); CallGraph CG = b.makeCallGraph(b.getOptions()); - dumpCG(b.getPointerAnalysis(), CG); + // dumpCG(b.getPointerAnalysis(), CG); return CG; } 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 271df72d5..43dd91332 100755 --- 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 @@ -19,6 +19,8 @@ import junit.framework.Assert; import org.junit.Test; +import com.ibm.wala.cast.js.ipa.callgraph.JSCFABuilder; +import com.ibm.wala.cast.js.ipa.callgraph.JSCallGraphUtil; import com.ibm.wala.ipa.callgraph.CGNode; import com.ibm.wala.ipa.callgraph.CallGraph; import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; @@ -151,7 +153,10 @@ public abstract class TestSimpleCallGraphShape extends TestJSCallGraphShape { @Test public void testForin() throws IOException, IllegalArgumentException, CancelException { - CallGraph CG = JSCallGraphBuilderUtil.makeScriptCG("tests", "forin.js"); + JSCFABuilder B = JSCallGraphBuilderUtil.makeScriptCGBuilder("tests", "forin.js"); + CallGraph CG = B.makeCallGraph(B.getOptions()); + JSCallGraphUtil.AVOID_DUMP = false; + JSCallGraphUtil.dumpCG(B.getPointerAnalysis(), CG); verifyGraphAssertions(CG, assertionsForForin); } @@ -242,6 +247,8 @@ public abstract class TestSimpleCallGraphShape extends TestJSCallGraphShape { PropagationCallGraphBuilder B = JSCallGraphBuilderUtil.makeScriptCGBuilder("tests", "string-prims.js"); B.getOptions().setTraceStringConstants(true); CallGraph CG = B.makeCallGraph(B.getOptions()); + JSCallGraphUtil.AVOID_DUMP = false; + JSCallGraphUtil.dumpCG(B.getPointerAnalysis(), CG); verifyGraphAssertions(CG, assertionsForStringPrims); } @@ -439,7 +446,10 @@ public abstract class TestSimpleCallGraphShape extends TestJSCallGraphShape { @Test public void testReturnThis() throws IOException, IllegalArgumentException, CancelException { - CallGraph CG = JSCallGraphBuilderUtil.makeScriptCG("tests", "return_this.js"); + PropagationCallGraphBuilder B = JSCallGraphBuilderUtil.makeScriptCGBuilder("tests", "return_this.js"); + CallGraph CG = B.makeCallGraph(B.getOptions()); + JSCallGraphUtil.AVOID_DUMP = false; + JSCallGraphUtil.dumpCG(B.getPointerAnalysis(), CG); verifyGraphAssertions(CG, assertionsForReturnThis); } @@ -522,6 +532,22 @@ public abstract class TestSimpleCallGraphShape extends TestJSCallGraphShape { verifyGraphAssertions(CG, assertionsForNestedParamAssign); } + private static final Object[][] assertionsForDispatch = new Object[][] { + new Object[] { ROOT, new String[] { "tests/dispatch.js" } }, + new Object[] { "tests/dispatch.js", new String[] { "tests/dispatch.js/left_outer", "tests/dispatch.js/right_outer" } }, + new Object[] { "tests/dispatch.js/left_outer", new String[]{ "tests/dispatch.js/left_inner" } }, + new Object[] { "tests/dispatch.js/right_outer", new String[]{ "tests/dispatch.js/right_inner" } } + }; + + @Test + public void testDispatch() throws IOException, IllegalArgumentException, CancelException { + PropagationCallGraphBuilder B = JSCallGraphBuilderUtil.makeScriptCGBuilder("tests", "dispatch.js"); + CallGraph CG = B.makeCallGraph(B.getOptions()); + JSCallGraphUtil.AVOID_DUMP = false; + JSCallGraphUtil.dumpCG(B.getPointerAnalysis(), CG); + verifyGraphAssertions(CG, assertionsForDispatch); + } + protected IVector>> computeIkIdToVns(PointerAnalysis pa) { // Created by reversing the points to mapping for local pointer keys. diff --git a/com.ibm.wala.cast.js/.classpath b/com.ibm.wala.cast.js/.classpath index f0389962a..c5302b396 100644 --- a/com.ibm.wala.cast.js/.classpath +++ b/com.ibm.wala.cast.js/.classpath @@ -2,8 +2,8 @@ + - diff --git a/com.ibm.wala.cast.js/dat/prologue.js b/com.ibm.wala.cast.js/dat/prologue.js index 8ac292b27..63c83dd34 100755 --- a/com.ibm.wala.cast.js/dat/prologue.js +++ b/com.ibm.wala.cast.js/dat/prologue.js @@ -3,11 +3,16 @@ primitive = new Primitives(); // core definitions needed to make anything work, even what follows Object = primitive("NewObject"); -Function = primitive("NewFunction"); -Array = primitive("NewArray"); -String = primitive("NewString"); -Number = primitive("NewNumber"); -RegExp = primitive("NewRegExp"); +var local_function = primitive("NewFunction"); +Function = local_function; +var local_array = primitive("NewArray"); +Array = local_array; +var local_string = primitive("NewString"); +String = local_string; +var local_number = primitive("NewNumber"); +Number = local_number; +var local_regexp = primitive("NewRegExp"); +RegExp = local_regexp; /************************************************************************/ /* Global properties, see spec 15.1 */ @@ -104,7 +109,7 @@ Object.prototype = { /* Function properties, see spec 15.3 */ /************************************************************************/ -Function.prototype = { +local_function.prototype = { constructor: Function, @@ -124,15 +129,15 @@ Function.prototype = { } }; -Function.__proto__ = Function.prototype; +local_function.__proto__ = Function.prototype; /************************************************************************/ /* Array properties, see spec 15.4 */ /************************************************************************/ -Array.__proto__ = Function.prototype; +local_array.__proto__ = Function.prototype; -Array.prototype = { +local_array.prototype = { __proto__: Object.prototype, @@ -251,9 +256,9 @@ Array.prototype = { /* String properties, see spec 15.4 */ /************************************************************************/ -String.__proto__ = Function.prototype; +local_string.__proto__ = Function.prototype; -String.prototype = { +local_string.prototype = { __proto__: Object.prototype, @@ -329,9 +334,9 @@ String.prototype = { /* Number properties, see spec 15.7 */ /************************************************************************/ -Number.__proto__ = Function.prototype; +local_number.__proto__ = Function.prototype; -Number.prototype = { +local_number.prototype = { __proto__: Object.prototype, @@ -419,9 +424,9 @@ Math = { /* RegExp properties, see spec 15.10 */ /************************************************************************/ -RegExp.__proto__ = Function.prototype; +local_regexp.__proto__ = Function.prototype; -RegExp.prototype = { +local_regexp.prototype = { __proto__: Object.prototype, diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/analysis/typeInference/JSTypeInference.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/analysis/typeInference/JSTypeInference.java index 23dd70830..3bb968ead 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/analysis/typeInference/JSTypeInference.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/analysis/typeInference/JSTypeInference.java @@ -22,6 +22,8 @@ import com.ibm.wala.cast.js.ssa.JavaScriptPropertyRead; import com.ibm.wala.cast.js.ssa.JavaScriptPropertyWrite; import com.ibm.wala.cast.js.ssa.JavaScriptTypeOfInstruction; import com.ibm.wala.cast.js.ssa.JavaScriptWithRegion; +import com.ibm.wala.cast.js.ssa.PrototypeLookup; +import com.ibm.wala.cast.js.ssa.SetPrototype; import com.ibm.wala.cast.js.types.JavaScriptTypes; import com.ibm.wala.fixpoint.IVariable; import com.ibm.wala.ipa.cha.IClassHierarchy; @@ -36,7 +38,7 @@ public class JSTypeInference extends AstTypeInference { } protected void initialize() { - class JSTypeOperatorFactory extends AstTypeOperatorFactory implements com.ibm.wala.cast.js.ssa.InstructionVisitor { + class JSTypeOperatorFactory extends AstTypeOperatorFactory implements com.ibm.wala.cast.js.ssa.JSInstructionVisitor { public void visitJavaScriptInvoke(JavaScriptInvoke inst) { result = new DeclaredTypeOperator(new ConeType(cha.getRootClass())); } @@ -61,6 +63,15 @@ public class JSTypeInference extends AstTypeInference { public void visitWithRegion(JavaScriptWithRegion instruction) { } + + @Override + public void visitSetPrototype(SetPrototype instruction) { + } + + @Override + public void visitPrototypeLookup(PrototypeLookup instruction) { + result = new DeclaredTypeOperator(new ConeType(cha.getRootClass())); + } } ; diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/cfg/JSInducedCFG.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/cfg/JSInducedCFG.java index da174dd45..0ff1d75ea 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/cfg/JSInducedCFG.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/cfg/JSInducedCFG.java @@ -11,7 +11,7 @@ package com.ibm.wala.cast.js.cfg; import com.ibm.wala.cast.ir.cfg.AstInducedCFG; -import com.ibm.wala.cast.js.ssa.InstructionVisitor; +import com.ibm.wala.cast.js.ssa.JSInstructionVisitor; import com.ibm.wala.cast.js.ssa.JavaScriptCheckReference; import com.ibm.wala.cast.js.ssa.JavaScriptInstanceOf; import com.ibm.wala.cast.js.ssa.JavaScriptInvoke; @@ -19,6 +19,8 @@ import com.ibm.wala.cast.js.ssa.JavaScriptPropertyRead; import com.ibm.wala.cast.js.ssa.JavaScriptPropertyWrite; import com.ibm.wala.cast.js.ssa.JavaScriptTypeOfInstruction; import com.ibm.wala.cast.js.ssa.JavaScriptWithRegion; +import com.ibm.wala.cast.js.ssa.PrototypeLookup; +import com.ibm.wala.cast.js.ssa.SetPrototype; import com.ibm.wala.classLoader.IMethod; import com.ibm.wala.ipa.callgraph.Context; import com.ibm.wala.ssa.SSAInstruction; @@ -29,7 +31,7 @@ public class JSInducedCFG extends AstInducedCFG { super(instructions, method, context); } - class JSPEIVisitor extends AstPEIVisitor implements InstructionVisitor { + class JSPEIVisitor extends AstPEIVisitor implements JSInstructionVisitor { JSPEIVisitor(boolean[] r) { super(r); @@ -59,9 +61,17 @@ public class JSInducedCFG extends AstInducedCFG { public void visitWithRegion(JavaScriptWithRegion instruction) { } + + @Override + public void visitSetPrototype(SetPrototype instruction) { + } + + @Override + public void visitPrototypeLookup(PrototypeLookup instruction) { + } } - class JSBranchVisitor extends AstBranchVisitor implements InstructionVisitor { + class JSBranchVisitor extends AstBranchVisitor implements JSInstructionVisitor { JSBranchVisitor(boolean[] r) { super(r); @@ -87,6 +97,14 @@ public class JSInducedCFG extends AstInducedCFG { public void visitWithRegion(JavaScriptWithRegion instruction) { } + + @Override + public void visitSetPrototype(SetPrototype instruction) { + } + + @Override + public void visitPrototypeLookup(PrototypeLookup instruction) { + } } protected BranchVisitor makeBranchVisitor(boolean[] r) { diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/ArgumentSpecialization.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/ArgumentSpecialization.java index e3b057db5..fc7d37cb4 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/ArgumentSpecialization.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/ArgumentSpecialization.java @@ -1,8 +1,9 @@ package com.ibm.wala.cast.js.ipa.callgraph; +import java.util.ArrayList; +import java.util.List; import java.util.Map; - -import java.util.regex.*; +import java.util.regex.Pattern; import com.ibm.wala.cast.ipa.callgraph.AstContextInsensitiveSSAContextInterpreter; import com.ibm.wala.cast.ir.ssa.AstIRFactory; @@ -17,6 +18,8 @@ import com.ibm.wala.cast.tree.CAstEntity; import com.ibm.wala.cast.tree.CAstNode; import com.ibm.wala.cast.tree.impl.CAstBasicRewriter; import com.ibm.wala.cast.tree.impl.CAstImpl; +import com.ibm.wala.cast.util.CAstPattern; +import com.ibm.wala.cast.util.CAstPattern.Segments; import com.ibm.wala.cfg.AbstractCFG; import com.ibm.wala.cfg.ControlFlowGraph; import com.ibm.wala.classLoader.CallSiteReference; @@ -36,12 +39,13 @@ import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; import com.ibm.wala.ssa.SSAOptions; import com.ibm.wala.ssa.SymbolTable; import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.collections.HashMapFactory; import com.ibm.wala.util.collections.Pair; import com.ibm.wala.util.intset.IntSet; public class ArgumentSpecialization { - private static final Pattern baseNameRegex = Pattern.compile("[$-]*base[$-]*[0-9]*"); + private static final Pattern baseNameRegex = Pattern.compile("[$]+destructuring[$]rcvr*[0-9]*"); public static class ArgumentSpecializationContextIntepreter extends AstContextInsensitiveSSAContextInterpreter { @@ -136,6 +140,12 @@ public class ArgumentSpecialization { } public static class ArgumentCountIRFactory extends AstIRFactory.AstDefaultIRFactory { + private static final CAstPattern directAccessPattern = CAstPattern.parse("|(ARRAY_REF(VAR(\"arguments\"),*)||OBJECT_REF(VAR(\"arguments\"),*))|"); + + private static final CAstPattern destructuredAccessPattern = CAstPattern.parse("BLOCK_EXPR(ASSIGN(VAR(/[$][$]destructure[$]rcvr[0-9]+/),VAR(\"arguments\")),ASSIGN(VAR(/[$][$]destructure[$]elt[0-9]+/),*))"); + + private static final CAstPattern destructuredCallPattern = CAstPattern.parse("CALL(VAR(/[$][$]destructure[$]elt[0-9]+/),\"dispatch\",VAR(/[$][$]destructure[$]rcvr[0-9]+/),**)"); + private final SSAOptions defaultOptions; public ArgumentCountIRFactory(SSAOptions defaultOptions) { @@ -155,78 +165,21 @@ public class ArgumentSpecialization { final Retranslatable m = (Retranslatable)method; if (v != null) { final JavaScriptLoader myloader = (JavaScriptLoader) method.getDeclaringClass().getClassLoader(); - + class FixedArgumentsRewriter extends CAstBasicRewriter { - private final CAstEntity e = m.getEntity(); - + private final CAstEntity e; + Map argRefs = HashMapFactory.make(); + public FixedArgumentsRewriter(CAst Ast) { super(Ast, false); - } - - private boolean isNamedVar(CAstNode n, String name) { - if (n.getKind() == CAstNode.VAR) { - String nm = (String) n.getChild(0).getValue(); - return nm.equals(name); - } - - return false; - } - - private boolean isNamedVar(CAstNode n, Pattern namePattern) { - if (n.getKind() == CAstNode.VAR) { - String nm = (String) n.getChild(0).getValue(); - return namePattern.matcher(nm).matches(); - } - - return false; - } - - private Object getIndexFromArgumentRef(CAstNode n) { - if (n.getKind() == CAstNode.OBJECT_REF || n.getKind() == CAstNode.ARRAY_REF) { - if (isNamedVar(n.getChild(0), "arguments")) { - return n.getChild(1).getValue(); - } - } - - return null; - } - - private Object getIndexFromBaseVar(CAstNode n) { - if (n.getKind() == CAstNode.BLOCK_EXPR) { - if (n.getChildCount() == 2) { - - CAstNode c1 = n.getChild(0); - if (c1.getKind() == CAstNode.ASSIGN) { - if (isNamedVar(c1.getChild(0), baseNameRegex)) { - if (isNamedVar(c1.getChild(1), "arguments")) { - - CAstNode c2 = n.getChild(1); - if (c2.getKind() == CAstNode.OBJECT_REF || c2.getKind() == CAstNode.ARRAY_REF) { - if (isNamedVar(c2.getChild(0), baseNameRegex)) { - return c2.getChild(1).getValue(); - } - } - } - } - } - } - } - - return null; - } - - private Object getStaticArgumentIndex(CAstNode n) { - Object x = getIndexFromArgumentRef(n); - if (x != null) { - return x; - } else { - return getIndexFromBaseVar(n); + this.e = m.getEntity(); + for(Segments s : CAstPattern.findAll(destructuredAccessPattern, m.getEntity())) { + argRefs.put(s.getSingle("name").getValue().toString(), s.getSingle("value")); } } - private CAstNode handleArgumentRef(CAstNode n) { - Object x = getStaticArgumentIndex(n); + Object x = n.getValue(); if (x != null) { if (x instanceof Number && ((Number)x).intValue() < v.getValue()-2) { int arg = ((Number)x).intValue() + 2; @@ -250,18 +203,31 @@ public class ArgumentSpecialization { Map, CAstNode> nodeMap) { CAstNode result = null; - if (root.getKind() == CAstNode.ARRAY_REF - || root.getKind() == CAstNode.OBJECT_REF - || root.getKind() == CAstNode.BLOCK_EXPR) - { - result = handleArgumentRef(root); + Segments s; + + if ((s = CAstPattern.match(directAccessPattern, root)) != null) { + result = handleArgumentRef(s.getSingle("value")); + + } else if ((s = CAstPattern.match(destructuredCallPattern, root)) != null) { + if (argRefs.containsKey(s.getSingle("name").getValue().toString())) { + List x = new ArrayList(); + CAstNode ref = handleArgumentRef(argRefs.get(s.getSingle("name").getValue().toString())); + if (ref != null) { + x.add(ref); + x.add(Ast.makeConstant("do")); + x.add(Ast.makeNode(CAstNode.VAR, Ast.makeConstant("arguments"))); + for (CAstNode c : s.getMultiple("args")) { + x.add(copyNodes(c, cfg, context, nodeMap)); + } + result = Ast.makeNode(CAstNode.CALL, x.toArray(new CAstNode[ x.size() ])); + } + } } else if (root.getKind() == CAstNode.CONSTANT) { result = Ast.makeConstant(root.getValue()); } else if (root.getKind() == CAstNode.OPERATOR) { result = root; - } if (result == null) { @@ -280,7 +246,6 @@ public class ArgumentSpecialization { nodeMap.put(Pair.make(root, context.key()), result); return result; - } } 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 ce8f4ef0a..7b8028a7c 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 @@ -10,6 +10,7 @@ *****************************************************************************/ package com.ibm.wala.cast.js.ipa.callgraph; +import java.io.UnsupportedEncodingException; import java.net.URL; import java.util.Set; @@ -21,7 +22,7 @@ import com.ibm.wala.cast.ir.ssa.AstIsDefinedInstruction; import com.ibm.wala.cast.ir.ssa.EachElementHasNextInstruction; import com.ibm.wala.cast.js.analysis.typeInference.JSTypeInference; import com.ibm.wala.cast.js.ipa.callgraph.JSSSAPropagationCallGraphBuilder.JSPointerAnalysisImpl.JSImplicitPointsToSetVisitor; -import com.ibm.wala.cast.js.ssa.InstructionVisitor; +import com.ibm.wala.cast.js.ssa.JSInstructionVisitor; import com.ibm.wala.cast.js.ssa.JavaScriptCheckReference; import com.ibm.wala.cast.js.ssa.JavaScriptInstanceOf; import com.ibm.wala.cast.js.ssa.JavaScriptInvoke; @@ -29,6 +30,9 @@ import com.ibm.wala.cast.js.ssa.JavaScriptPropertyRead; import com.ibm.wala.cast.js.ssa.JavaScriptPropertyWrite; import com.ibm.wala.cast.js.ssa.JavaScriptTypeOfInstruction; import com.ibm.wala.cast.js.ssa.JavaScriptWithRegion; +import com.ibm.wala.cast.js.ssa.PrototypeLookup; +import com.ibm.wala.cast.js.ssa.SetPrototype; +import com.ibm.wala.cast.js.types.JavaScriptMethods; import com.ibm.wala.cast.js.types.JavaScriptTypes; import com.ibm.wala.cast.loader.AstMethod; import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position; @@ -36,11 +40,13 @@ import com.ibm.wala.classLoader.IClass; import com.ibm.wala.classLoader.IField; import com.ibm.wala.classLoader.IMethod; import com.ibm.wala.fixpoint.AbstractOperator; +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; import com.ibm.wala.ipa.callgraph.CallGraph; import com.ibm.wala.ipa.callgraph.impl.ExplicitCallGraph; +import com.ibm.wala.ipa.callgraph.propagation.AbstractFieldPointerKey; import com.ibm.wala.ipa.callgraph.propagation.ConcreteTypeKey; import com.ibm.wala.ipa.callgraph.propagation.ConstantKey; import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey; @@ -191,7 +197,7 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph system.newConstraint(exceptionVar, assignOperator, e); } - public static class JSInterestingVisitor extends AstInterestingVisitor implements com.ibm.wala.cast.js.ssa.InstructionVisitor { + public static class JSInterestingVisitor extends AstInterestingVisitor implements com.ibm.wala.cast.js.ssa.JSInstructionVisitor { public JSInterestingVisitor(int vn) { super(vn); } @@ -227,6 +233,16 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph public void visitWithRegion(JavaScriptWithRegion instruction) { } + + @Override + public void visitSetPrototype(SetPrototype instruction) { + bingo = true; + } + + @Override + public void visitPrototypeLookup(PrototypeLookup instruction) { + bingo = true; + } } protected InterestingVisitor makeInterestingVisitor(CGNode node, int vn) { @@ -247,7 +263,7 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph } public static class JSImplicitPointsToSetVisitor extends AstImplicitPointsToSetVisitor implements - com.ibm.wala.cast.js.ssa.InstructionVisitor { + com.ibm.wala.cast.js.ssa.JSInstructionVisitor { public JSImplicitPointsToSetVisitor(AstPointerAnalysisImpl analysis, LocalPointerKey lpk) { super(analysis, lpk); @@ -301,6 +317,14 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph pointsToSet = new OrdinalSet(S, analysis.getInstanceKeyMapping()); } + @Override + public void visitSetPrototype(SetPrototype instruction) { + } + + @Override + public void visitPrototypeLookup(PrototypeLookup instruction) { + } + }; protected ImplicitPointsToSetVisitor makeImplicitPointsToVisitor(LocalPointerKey lpk) { @@ -346,7 +370,7 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph return null; } - public static class JSConstraintVisitor extends AstConstraintVisitor implements InstructionVisitor { + public static class JSConstraintVisitor extends AstConstraintVisitor implements JSInstructionVisitor { public JSConstraintVisitor(AstSSAPropagationCallGraphBuilder builder, CGNode node) { super(builder, node); @@ -479,9 +503,135 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph } public void visitJavaScriptInvoke(JavaScriptInvoke instruction) { - visitInvokeInternal(instruction); + if (instruction.getDeclaredTarget().equals(JavaScriptMethods.dispatchReference)) { + handleJavascriptDispatch(instruction); + } else { + visitInvokeInternal(instruction, new DefaultInvariantComputer()); + } } + private void handleJavascriptDispatch(final JavaScriptInvoke instruction, final InstanceKey receiverType) { + int functionVn = instruction.getFunction(); + + ReflectedFieldAction fieldDispatchAction = new ReflectedFieldAction() { + @Override + public void action(final AbstractFieldPointerKey fieldKey) { + class FieldValueDispatch extends UnaryOperator { + private JavaScriptInvoke getInstruction() { return instruction; } + private InstanceKey getReceiver() { return receiverType; } + private AbstractFieldPointerKey getProperty() { return fieldKey; } + + @Override + public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable ptrs) { + if (ptrs.getValue() != null) { + ptrs.getValue().foreach(new IntSetAction() { + @Override + public void act(int x) { + final InstanceKey functionObj = system.getInstanceKey(x); + visitInvokeInternal(instruction, new DefaultInvariantComputer() { + @Override + public InstanceKey[][] computeInvariantParameters(SSAAbstractInvokeInstruction call) { + InstanceKey[][] x = super.computeInvariantParameters(call); + if (x == null) { + x = new InstanceKey[call.getNumberOfUses()][]; + } + x[0] = new InstanceKey[]{ functionObj }; + x[1] = new InstanceKey[]{ receiverType }; + return x; + } + }); + } + }); + } + return NOT_CHANGED; + } + @Override + public int hashCode() { + return instruction.hashCode() * fieldKey.hashCode() * receiverType.hashCode(); + } + @Override + public boolean equals(Object o) { + return o instanceof FieldValueDispatch && + ((FieldValueDispatch)o).getInstruction() == instruction && + ((FieldValueDispatch)o).getProperty().equals(fieldKey) && + ((FieldValueDispatch)o).getReceiver().equals(receiverType); + } + @Override + public String toString() { + return "sub-dispatch for " + instruction + ": " + receiverType + ", " + fieldKey; + } + }; + + system.newSideEffect(new FieldValueDispatch(), fieldKey); + } + @Override + public void dump(AbstractFieldPointerKey fieldKey, boolean constObj, boolean constProp) { + System.err.println("dispatch to " + receiverType + "." + fieldKey + " for " + instruction); + } + }; + + TransitivePrototypeKey prototypeObjs = new TransitivePrototypeKey(receiverType); + InstanceKey[] objKeys = new InstanceKey[]{ receiverType }; + if (contentsAreInvariant(symbolTable, du, functionVn)) { + InstanceKey[] fieldsKeys = getInvariantContents(functionVn); + newFieldOperationObjectAndFieldConstant(true, fieldDispatchAction, objKeys, fieldsKeys); + newFieldOperationOnlyFieldConstant(true, fieldDispatchAction, prototypeObjs, fieldsKeys); + } else { + PointerKey fieldKey = getPointerKeyForLocal(functionVn); + newFieldOperationOnlyObjectConstant(true, fieldDispatchAction, fieldKey, objKeys); + newFieldFullOperation(true, fieldDispatchAction, prototypeObjs, fieldKey); + } + } + + private void handleJavascriptDispatch(final JavaScriptInvoke instruction) { + int receiverVn = instruction.getUse(1); + PointerKey receiverKey = getPointerKeyForLocal(receiverVn); + if (contentsAreInvariant(symbolTable, du, receiverVn)) { + system.recordImplicitPointsToSet(receiverKey); + InstanceKey[] ik = getInvariantContents(receiverVn); + for (int i = 0; i < ik.length; i++) { + handleJavascriptDispatch(instruction, ik[i]); + } + } else { + class ReceiverForDispatchOp extends UnaryOperator { + private JavaScriptInvoke getInstruction() { + return instruction; + } + + @Override + public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) { + if (rhs.getValue() != null) { + rhs.getValue().foreach(new IntSetAction() { + @Override + public void act(int x) { + InstanceKey ik = system.getInstanceKey(x); + handleJavascriptDispatch(instruction, ik); + } + }); + } + return NOT_CHANGED; + } + + @Override + public int hashCode() { + return instruction.hashCode(); + } + + @Override + public boolean equals(Object o) { + return o instanceof ReceiverForDispatchOp && ((ReceiverForDispatchOp)o).getInstruction()==getInstruction(); + } + + @Override + public String toString() { + return "receiver for dispatch: " + instruction; + } + } + + system.newSideEffect(new ReceiverForDispatchOp(), receiverKey); + } + } + // /////////////////////////////////////////////////////////////////////////// // // string manipulation handling for binary operators @@ -637,6 +787,98 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph // TODO Auto-generated method stub } + + private final UnaryOperator transitivePrototypeOp = new UnaryOperator() { + @Override + public byte evaluate(final PointsToSetVariable lhs, PointsToSetVariable rhs) { + class Op implements IntSetAction { + private boolean changed = false; + + @Override + public void act(int x) { + InstanceKey protoObj = system.getInstanceKey(x); + PointerKey protoObjKey = new TransitivePrototypeKey(protoObj); + changed |= system.newStatement(lhs, assignOperator, system.findOrCreatePointsToSet(protoObjKey), true, true); + } + } + + if (rhs.getValue() != null) { + Op op = new Op(); + rhs.getValue().foreach(op); + return (op.changed? CHANGED: NOT_CHANGED); + } + return NOT_CHANGED; + } + + @Override + public int hashCode() { + return -896435647; + } + + @Override + public boolean equals(Object o) { + return o == this; + } + + @Override + public String toString() { + return "transitivePrototypeOp"; + } + + }; + + private final FieldReference prototypeRef; + { + FieldReference x = null; + try { + byte[] utf8 = "__proto__".getBytes("UTF-8"); + x = FieldReference.findOrCreate(JavaScriptTypes.Root, Atom.findOrCreate(utf8, 0, utf8.length), JavaScriptTypes.Root); + } catch (UnsupportedEncodingException e) { + assert false; + } + prototypeRef = x; + } + + @Override + public void visitSetPrototype(SetPrototype instruction) { + visitPutInternal(instruction.getUse(1), instruction.getUse(0), false, prototypeRef); + + assert contentsAreInvariant(symbolTable, du, instruction.getUse(0)); + if (contentsAreInvariant(symbolTable, du, instruction.getUse(1))) { + for(InstanceKey newObj : getInvariantContents(instruction.getUse(0))) { + PointerKey newObjKey = new TransitivePrototypeKey(newObj); + for(InstanceKey protoObj : getInvariantContents(instruction.getUse(1))) { + system.newConstraint(newObjKey, protoObj); + system.newConstraint(newObjKey, assignOperator, new TransitivePrototypeKey(protoObj)); + } + } + } else { + for(InstanceKey newObj : getInvariantContents(instruction.getUse(0))) { + PointerKey newObjKey = new TransitivePrototypeKey(newObj); + system.newConstraint(newObjKey, assignOperator, getPointerKeyForLocal(instruction.getUse(1))); + system.newConstraint(newObjKey, transitivePrototypeOp, getPointerKeyForLocal(instruction.getUse(1))); + } + } + } + + @Override + public void visitPrototypeLookup(PrototypeLookup instruction) { + if (contentsAreInvariant(symbolTable, du, instruction.getUse(0))) { + for(InstanceKey rhsObj : getInvariantContents(instruction.getUse(0))) { + // property can come from object itself... + system.newConstraint(getPointerKeyForLocal(instruction.getDef(0)), rhsObj); + + // ...or prototype objects + system.newConstraint(getPointerKeyForLocal(instruction.getDef(0)), assignOperator, new TransitivePrototypeKey(rhsObj)); + } + } else { + // property can come from object itself... + system.newConstraint(getPointerKeyForLocal(instruction.getDef(0)), assignOperator, getPointerKeyForLocal(instruction.getUse(0))); + + // ...or prototype objects + system.newConstraint(getPointerKeyForLocal(instruction.getDef(0)), transitivePrototypeOp, getPointerKeyForLocal(instruction.getUse(0))); + } + } } // /////////////////////////////////////////////////////////////////////////// diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/JavaScriptConstructTargetSelector.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/JavaScriptConstructTargetSelector.java index d38726d2d..b99f679a6 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/JavaScriptConstructTargetSelector.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/JavaScriptConstructTargetSelector.java @@ -92,7 +92,8 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector { S.addStatement(insts.NewInstruction(5, NewSiteReference.make(S.getNextProgramCounter(), cls.getReference()))); - S.addStatement(insts.PutInstruction(5, 4, "__proto__")); + S.addStatement(insts.SetPrototype(5, 4)); + //S.addStatement(insts.PutInstruction(5, 4, "__proto__")); S.getNextProgramCounter(); S.addConstant(new Integer(8), new ConstantValue(value)); @@ -102,6 +103,8 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector { S.addStatement(insts.ReturnInstruction(5, false)); S.getNextProgramCounter(); + //S.addConstant(9, new ConstantValue("__proto__")); + return new JavaScriptConstructor(ref, S, cls); } @@ -115,7 +118,8 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector { S.addStatement(insts.NewInstruction(6, NewSiteReference.make(S.getNextProgramCounter(), cls.getReference()))); - S.addStatement(insts.PutInstruction(6, 5, "__proto__")); + S.addStatement(insts.SetPrototype(6, 5)); + //S.addStatement(insts.PutInstruction(6, 5, "__proto__")); S.getNextProgramCounter(); S.addStatement(insts.PutInstruction(6, 2, "$value")); @@ -123,7 +127,9 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector { S.addStatement(insts.ReturnInstruction(6, false)); S.getNextProgramCounter(); - + + //S.addConstant(7, new ConstantValue("__proto__")); + return new JavaScriptConstructor(ref, S, cls); } @@ -155,12 +161,15 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector { S.addStatement(insts.NewInstruction(5, NewSiteReference.make(S.getNextProgramCounter(), JavaScriptTypes.Object))); - S.addStatement(insts.PutInstruction(5, 4, "__proto__")); + S.addStatement(insts.SetPrototype(5, 4)); + //S.addStatement(insts.PutInstruction(5, 4, "__proto__")); S.getNextProgramCounter(); S.addStatement(insts.ReturnInstruction(5, false)); S.getNextProgramCounter(); + //S.addConstant(6, new ConstantValue("__proto__")); + return new JavaScriptConstructor(ref, S, cls); } @@ -212,7 +221,8 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector { S.addStatement(insts.NewInstruction(6, NewSiteReference.make(S.getNextProgramCounter(), JavaScriptTypes.Array))); - S.addStatement(insts.PutInstruction(6, 5, "__proto__")); + S.addStatement(insts.SetPrototype(6, 5)); + //S.addStatement(insts.PutInstruction(6, 5, "__proto__")); S.getNextProgramCounter(); S.addStatement(insts.PutInstruction(6, 2, "length")); @@ -220,7 +230,9 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector { S.addStatement(insts.ReturnInstruction(6, false)); S.getNextProgramCounter(); - + + //S.addConstant(7, new ConstantValue("__proto__")); + return new JavaScriptConstructor(ref, S, cls); } @@ -237,7 +249,8 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector { insts.NewInstruction(nargs + 5, NewSiteReference.make(S.getNextProgramCounter(), JavaScriptTypes.Array))); - S.addStatement(insts.PutInstruction(nargs + 5, nargs + 4, "__proto__")); + S.addStatement(insts.SetPrototype(nargs + 5, nargs + 4)); + //S.addStatement(insts.PutInstruction(nargs + 5, nargs + 4, "__proto__")); S.getNextProgramCounter(); S.addConstant(new Integer(nargs + 7), new ConstantValue(nargs)); @@ -254,6 +267,8 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector { S.addStatement(insts.ReturnInstruction(5, false)); S.getNextProgramCounter(); + //S.addConstant(vn, new ConstantValue("__proto__")); + return new JavaScriptConstructor(ref, S, cls); } @@ -362,7 +377,8 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector { S.addStatement(insts.NewInstruction(7, NewSiteReference.make(S.getNextProgramCounter(), JavaScriptTypes.Object))); - S.addStatement(insts.PutInstruction(5, 4, "__proto__")); + S.addStatement(insts.SetPrototype(5, 4)); + //S.addStatement(insts.PutInstruction(5, 4, "__proto__")); S.getNextProgramCounter(); S.addStatement(insts.PutInstruction(5, 7, "prototype")); @@ -375,6 +391,8 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector { S.addStatement(insts.ReturnInstruction(5, false)); S.getNextProgramCounter(); + //S.addConstant(8, new ConstantValue("__proto__")); + if (receiver != cls) return record(tableKey, new JavaScriptConstructor(ref, S, receiver, "(" + cls.getReference().getName() + ")")); else @@ -465,7 +483,6 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector { MethodReference ref = JavaScriptMethods.makeCtorReference(cls.getReference()); JavaScriptSummary S = new JavaScriptSummary(ref, nargs + 1); - S.addStatement(insts.GetInstruction(nargs + 4, 1, "prototype")); S.getNextProgramCounter(); @@ -474,7 +491,8 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector { NewSiteReference.make(S.getNextProgramCounter(), JavaScriptTypes.Object))); - S.addStatement(insts.PutInstruction(nargs + 5, nargs + 4, "__proto__")); + S.addStatement(insts.SetPrototype(nargs + 5, nargs + 4)); + //S.addStatement(insts.PutInstruction(nargs + 5, nargs + 4, "__proto__")); S.getNextProgramCounter(); CallSiteReference cs = new JSCallSiteReference(S.getNextProgramCounter()); @@ -490,6 +508,8 @@ public class JavaScriptConstructTargetSelector implements MethodTargetSelector { S.addStatement(insts.ReturnInstruction(nargs + 5, false)); S.getNextProgramCounter(); + //S.addConstant(nargs + 9, new ConstantValue("__proto__")); + return record(key, new JavaScriptConstructor(ref, S, cls)); } diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/TransitivePrototypeKey.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/TransitivePrototypeKey.java new file mode 100644 index 000000000..d5a85293c --- /dev/null +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/TransitivePrototypeKey.java @@ -0,0 +1,38 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.js.ipa.callgraph; + +import com.ibm.wala.ipa.callgraph.propagation.AbstractFieldPointerKey; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; + +public class TransitivePrototypeKey extends AbstractFieldPointerKey { + + public String getName() { + return "transitive prototype of "+getInstanceKey().toString(); + } + + public TransitivePrototypeKey(InstanceKey object) { + super(object); + } + + public boolean equals(Object x) { + return (x instanceof TransitivePrototypeKey) && + ((TransitivePrototypeKey)x).getInstanceKey().equals(getInstanceKey()); + } + + public int hashCode() { + return getInstanceKey().hashCode(); + } + + public String toString() { + return ""; + } +} 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 0c2936c36..0126a4d1e 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 @@ -45,6 +45,8 @@ import com.ibm.wala.cast.js.ssa.JavaScriptPropertyRead; import com.ibm.wala.cast.js.ssa.JavaScriptPropertyWrite; import com.ibm.wala.cast.js.ssa.JavaScriptTypeOfInstruction; import com.ibm.wala.cast.js.ssa.JavaScriptWithRegion; +import com.ibm.wala.cast.js.ssa.PrototypeLookup; +import com.ibm.wala.cast.js.ssa.SetPrototype; import com.ibm.wala.cast.js.translator.JSAstTranslator; import com.ibm.wala.cast.js.translator.JavaScriptTranslatorFactory; import com.ibm.wala.cast.js.types.JavaScriptTypes; @@ -517,6 +519,16 @@ public class JavaScriptLoader extends CAstAbstractModuleLoader { throw new UnsupportedOperationException(); } + @Override + public PrototypeLookup PrototypeLookup(int lval, int object) { + return new PrototypeLookup(lval, object); + } + + @Override + public SetPrototype SetPrototype(int object, int prototype) { + return new SetPrototype(object, prototype); + } + }; } diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/AbstractInstructionVisitor.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JSAbstractInstructionVisitor.java similarity index 83% rename from com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/AbstractInstructionVisitor.java rename to com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JSAbstractInstructionVisitor.java index d3c3745d9..2b4c7bc12 100755 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/AbstractInstructionVisitor.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JSAbstractInstructionVisitor.java @@ -12,9 +12,9 @@ package com.ibm.wala.cast.js.ssa; import com.ibm.wala.cast.ir.ssa.AstAbstractInstructionVisitor; -public class AbstractInstructionVisitor +public class JSAbstractInstructionVisitor extends AstAbstractInstructionVisitor - implements InstructionVisitor + implements JSInstructionVisitor { public void visitJavaScriptInvoke(JavaScriptInvoke instruction) { @@ -45,5 +45,15 @@ public class AbstractInstructionVisitor } + @Override + public void visitSetPrototype(SetPrototype instruction) { + + } + + @Override + public void visitPrototypeLookup(PrototypeLookup instruction) { + + } + } diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JSInstructionFactory.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JSInstructionFactory.java index 981742669..2bdca272a 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JSInstructionFactory.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JSInstructionFactory.java @@ -32,4 +32,8 @@ public interface JSInstructionFactory extends AstInstructionFactory { JavaScriptWithRegion WithRegion(int expr, boolean isEnter); + PrototypeLookup PrototypeLookup(int lval, int object); + + SetPrototype SetPrototype(int object, int prototype); + } diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/InstructionVisitor.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JSInstructionVisitor.java similarity index 85% rename from com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/InstructionVisitor.java rename to com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JSInstructionVisitor.java index d35a057de..347f18d8e 100755 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/InstructionVisitor.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JSInstructionVisitor.java @@ -12,7 +12,7 @@ package com.ibm.wala.cast.js.ssa; import com.ibm.wala.cast.ir.ssa.AstInstructionVisitor; -public interface InstructionVisitor extends AstInstructionVisitor { +public interface JSInstructionVisitor extends AstInstructionVisitor { public void visitJavaScriptInvoke(JavaScriptInvoke instruction); @@ -28,5 +28,9 @@ public interface InstructionVisitor extends AstInstructionVisitor { public void visitCheckRef(JavaScriptCheckReference instruction); + public void visitSetPrototype(SetPrototype instruction); + + public void visitPrototypeLookup(PrototypeLookup instruction); + } diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptCheckReference.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptCheckReference.java index d5b676be6..ce2d6e8b1 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptCheckReference.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptCheckReference.java @@ -43,7 +43,7 @@ public class JavaScriptCheckReference extends SSAInstruction { @Override public void visit(IVisitor v) { - ((InstructionVisitor)v).visitCheckRef(this); + ((JSInstructionVisitor)v).visitCheckRef(this); } public boolean isPEI() { diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptInstanceOf.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptInstanceOf.java index 53fd17038..68b90a925 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptInstanceOf.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptInstanceOf.java @@ -56,7 +56,7 @@ public class JavaScriptInstanceOf extends SSAInstruction { @Override public void visit(IVisitor v) { - ((InstructionVisitor)v).visitJavaScriptInstanceOf(this); + ((JSInstructionVisitor)v).visitJavaScriptInstanceOf(this); } public int getNumberOfDefs() { diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptInvoke.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptInvoke.java index 9ca605911..5a63aa0a1 100755 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptInvoke.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptInvoke.java @@ -104,6 +104,8 @@ public class JavaScriptInvoke extends AbstractLexicalInvoke { } if (site.getDeclaredTarget().equals(JavaScriptMethods.ctorReference)) s.append("construct "); + else if (site.getDeclaredTarget().equals(JavaScriptMethods.dispatchReference)) + s.append("dispatch "); else s.append("invoke "); s.append(getValueString(symbolTable, function)); @@ -151,8 +153,8 @@ public class JavaScriptInvoke extends AbstractLexicalInvoke { * @see com.ibm.domo.ssa.Instruction#visit(Visitor) */ public void visit(IVisitor v) { - assert v instanceof InstructionVisitor; - ((InstructionVisitor) v).visitJavaScriptInvoke(this); + assert v instanceof JSInstructionVisitor; + ((JSInstructionVisitor) v).visitJavaScriptInvoke(this); } public int getNumberOfParameters() { diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptPropertyRead.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptPropertyRead.java index 66dfd6de6..0a37fac4e 100755 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptPropertyRead.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptPropertyRead.java @@ -49,7 +49,7 @@ public class JavaScriptPropertyRead extends AbstractReflectiveGet { * @see com.ibm.domo.ssa.SSAInstruction#visit(com.ibm.domo.ssa.SSAInstruction.Visitor) */ public void visit(IVisitor v) { - assert v instanceof InstructionVisitor; - ((InstructionVisitor)v).visitJavaScriptPropertyRead(this); + assert v instanceof JSInstructionVisitor; + ((JSInstructionVisitor)v).visitJavaScriptPropertyRead(this); } } diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptPropertyWrite.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptPropertyWrite.java index 00a8372b2..86323b260 100755 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptPropertyWrite.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptPropertyWrite.java @@ -37,8 +37,8 @@ public class JavaScriptPropertyWrite extends AbstractReflectivePut { * @see com.ibm.domo.ssa.Instruction#visit(Visitor) */ public void visit(IVisitor v) { - assert v instanceof InstructionVisitor; - ((InstructionVisitor) v).visitJavaScriptPropertyWrite(this); + assert v instanceof JSInstructionVisitor; + ((JSInstructionVisitor) v).visitJavaScriptPropertyWrite(this); } /* diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptTypeOfInstruction.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptTypeOfInstruction.java index 89b1e9696..5855a3acf 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptTypeOfInstruction.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptTypeOfInstruction.java @@ -33,7 +33,7 @@ public class JavaScriptTypeOfInstruction extends SSAAbstractUnaryInstruction { } public void visit(IVisitor v) { - ((InstructionVisitor) v).visitTypeOf(this); + ((JSInstructionVisitor) v).visitTypeOf(this); } public Collection getExceptionTypes() { diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptWithRegion.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptWithRegion.java index fce47e1e3..e985b2988 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptWithRegion.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/JavaScriptWithRegion.java @@ -43,7 +43,7 @@ public class JavaScriptWithRegion extends SSAInstruction { @Override public void visit(IVisitor v) { - ((InstructionVisitor)v).visitWithRegion(this); + ((JSInstructionVisitor)v).visitWithRegion(this); } public int getNumberOfUses() { diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/PrototypeLookup.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/PrototypeLookup.java new file mode 100644 index 000000000..8d1229d74 --- /dev/null +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/PrototypeLookup.java @@ -0,0 +1,29 @@ +package com.ibm.wala.cast.js.ssa; + +import com.ibm.wala.ssa.SSAAbstractUnaryInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAInstructionFactory; +import com.ibm.wala.ssa.SymbolTable; + +public class PrototypeLookup extends SSAAbstractUnaryInstruction { + + public PrototypeLookup(int result, int val) { + super(result, val); + } + + @Override + public SSAInstruction copyForSSA(SSAInstructionFactory insts, int[] defs, int[] uses) { + return ((JSInstructionFactory)insts).PrototypeLookup((defs != null ? defs[0] : getDef(0)), (uses != null ? uses[0] : getUse(0))); + } + + @Override + public String toString(SymbolTable symbolTable) { + return getValueString(symbolTable, getDef(0)) + " = prototype_values(" + getValueString(symbolTable, getUse(0)) + ")"; + } + + @Override + public void visit(IVisitor v) { + ((JSInstructionVisitor)v).visitPrototypeLookup(this); + } + +} diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/SetPrototype.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/SetPrototype.java new file mode 100644 index 000000000..456860779 --- /dev/null +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ssa/SetPrototype.java @@ -0,0 +1,56 @@ +package com.ibm.wala.cast.js.ssa; + +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAInstructionFactory; +import com.ibm.wala.ssa.SymbolTable; + +public class SetPrototype extends SSAInstruction { + private final int object; + private final int prototype; + + public SetPrototype(int object, int prototype) { + this.object = object; + this.prototype = prototype; + } + + @Override + public int getNumberOfUses() { + return 2; + } + + @Override + public int getUse(int j) throws UnsupportedOperationException { + assert j >= 0 && j <= 1; + return (j==0)? object: prototype; + } + + @Override + public SSAInstruction copyForSSA(SSAInstructionFactory insts, int[] defs, int[] uses) { + return ((JSInstructionFactory)insts).SetPrototype((uses != null ? uses[0] : object), (uses != null ? uses[1] : prototype)); + } + + @Override + public String toString(SymbolTable symbolTable) { + return "set_prototype(" + getValueString(symbolTable, object) + ", " + getValueString(symbolTable, prototype) + ")"; + } + + @Override + public void visit(IVisitor v) { + ((JSInstructionVisitor)v).visitSetPrototype(this); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + object; + result = prime * result + prototype; + return result; + } + + @Override + public boolean isFallThrough() { + return true; + } + +} diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/translator/JSAstTranslator.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/translator/JSAstTranslator.java index 4c2ef6ce2..dc7ecf2ac 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/translator/JSAstTranslator.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/translator/JSAstTranslator.java @@ -49,6 +49,10 @@ public class JSAstTranslator extends AstTranslator { super(loader); } + private boolean isPrologueScript(WalkContext context) { + return JavaScriptLoader.bootstrapFileNames.contains( context.getModule().getName() ); + } + protected boolean useDefaultInitValues() { return false; } @@ -112,7 +116,7 @@ public class JSAstTranslator extends AstTranslator { } protected void defineField(CAstEntity topEntity, WalkContext wc, CAstEntity n) { - Assertions.UNREACHABLE("JavaScript doesn't have fields, numb-nuts!"); + Assertions.UNREACHABLE("JavaScript doesn't have fields"); } protected String composeEntityName(WalkContext parent, CAstEntity f) { @@ -152,12 +156,14 @@ public class JSAstTranslator extends AstTranslator { } protected void doCall(WalkContext context, CAstNode call, int result, int exception, CAstNode name, int receiver, int[] arguments) { - MethodReference ref = name.getValue().equals("ctor") ? JavaScriptMethods.ctorReference : AstMethodReference - .fnReference(JavaScriptTypes.CodeBody); + MethodReference ref = + name.getValue().equals("ctor") ? JavaScriptMethods.ctorReference + : name.getValue().equals("dispatch") ? JavaScriptMethods.dispatchReference + : AstMethodReference.fnReference(JavaScriptTypes.CodeBody); context.cfg().addInstruction( - ((JSInstructionFactory) insts).Invoke(receiver, result, arguments, exception, new JSCallSiteReference(ref, context.cfg() - .getCurrentInstruction()))); + ((JSInstructionFactory) insts).Invoke(receiver, result, arguments, exception, + new JSCallSiteReference(ref, context.cfg().getCurrentInstruction()))); context.cfg().addPreNode(call, context.getUnwindState()); @@ -202,6 +208,8 @@ public class JSAstTranslator extends AstTranslator { context.cfg().addInstruction(((JSInstructionFactory) insts).AssignInstruction(x, receiver)); + context.cfg().addInstruction(((JSInstructionFactory) insts).PrototypeLookup(x, x)); + if (elt.getKind() == CAstNode.CONSTANT && elt.getValue() instanceof String) { String field = (String) elt.getValue(); // symtab needs to have this value @@ -228,14 +236,18 @@ public class JSAstTranslator extends AstTranslator { this.visit(elt, context, this); if (elt.getKind() == CAstNode.CONSTANT && elt.getValue() instanceof String) { String field = (String) elt.getValue(); - context.currentScope().getConstantValue(field); - SSAPutInstruction put = ((JSInstructionFactory) insts).PutInstruction(receiver, rval, field); - try { - assert field.equals(put.getDeclaredField().getName().toUnicodeString()); - } catch (UTFDataFormatException e) { - Assertions.UNREACHABLE(); + if (isPrologueScript(context) && "__proto__".equals(field)) { + context.cfg().addInstruction(((JSInstructionFactory) insts).SetPrototype(receiver, rval)); + } else { + context.currentScope().getConstantValue(field); + SSAPutInstruction put = ((JSInstructionFactory) insts).PutInstruction(receiver, rval, field); + try { + assert field.equals(put.getDeclaredField().getName().toUnicodeString()); + } catch (UTFDataFormatException e) { + Assertions.UNREACHABLE(); + } + context.cfg().addInstruction(put); } - context.cfg().addInstruction(put); } else { context.cfg().addInstruction(((JSInstructionFactory) insts).PropertyWrite(receiver, context.getValue(elt), rval)); } diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/translator/JavaScriptTranslatorToCAst.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/translator/JavaScriptTranslatorToCAst.java index ed2203199..c193d3cda 100644 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/translator/JavaScriptTranslatorToCAst.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/translator/JavaScriptTranslatorToCAst.java @@ -35,11 +35,11 @@ public interface JavaScriptTranslatorToCAst extends TranslatorToCAst { CAstNode getCatchTarget(); - String getBaseVarIfRelevant(T node); + int setOperation(T node); - boolean foundBase(T node); + boolean foundMemberOperation(T node); - void updateBase(T from, T to); + void copyOperation(T from, T to); } @@ -66,11 +66,21 @@ public interface JavaScriptTranslatorToCAst extends TranslatorToCAst { return null; } - public String getBaseVarIfRelevant(T node) { return null; } + @Override + public int setOperation(T node) { + return -1; + } - public boolean foundBase(T node) { return false; } + @Override + public boolean foundMemberOperation(T node) { + return false; + } + + @Override + public void copyOperation(T from, T to) { + Assertions.UNREACHABLE(); + } - public void updateBase(T from, T to) { } } class DelegatingContext, T> extends TranslatorToCAst.DelegatingContext implements WalkContext { @@ -99,16 +109,19 @@ public interface JavaScriptTranslatorToCAst extends TranslatorToCAst { return parent.getCatchTarget(); } - public String getBaseVarIfRelevant(T node) { - return parent.getBaseVarIfRelevant(node); + @Override + public int setOperation(T node) { + return parent.setOperation(node); } - public boolean foundBase(T node) { - return parent.foundBase(node); + @Override + public boolean foundMemberOperation(T node) { + return parent.foundMemberOperation(node); } - public void updateBase(T from, T to) { - parent.updateBase(from, to); + @Override + public void copyOperation(T from, T to) { + parent.copyOperation(from, to); } } @@ -220,7 +233,7 @@ public interface JavaScriptTranslatorToCAst extends TranslatorToCAst { * 'this' parameter in baseVar, and then to use baseVar as the actual argument * sub-node for the CAst call node */ - public class BaseCollectingContext, T> extends DelegatingContext { + public class MemberDestructuringContext, T> extends DelegatingContext { /** * node for which we actually care about what the base pointer is. this @@ -229,49 +242,33 @@ public interface JavaScriptTranslatorToCAst extends TranslatorToCAst { */ private final Set baseFor = new HashSet(); - /** - * the variable to be used to store the value of the expression passed as - * the 'this' parameter - */ - private final String baseVar; - + private int operationIndex; + /** * have we discovered a value to be passed as the 'this' parameter? */ private boolean foundBase = false; - protected BaseCollectingContext(C parent, T initialBaseFor, String baseVar) { + protected MemberDestructuringContext(C parent, T initialBaseFor, int operationIndex) { super(parent); baseFor.add( initialBaseFor ); - this.baseVar = baseVar; + this.operationIndex = operationIndex; } - /** - * if node is one that we care about, return baseVar, and as a side effect - * set foundBase to true. Otherwise, return null. - */ - @Override - public String getBaseVarIfRelevant(T node) { + public int setOperation(T node) { if (baseFor.contains( node )) { foundBase = true; - return baseVar; + return operationIndex; } else { - return null; + return -1; } } - - @Override - public boolean foundBase(T node) { + + public boolean foundMemberOperation(T node) { return foundBase; } - /** - * if we currently care about the base pointer of from, switch to searching - * for the base pointer of to. Used for cases like comma expressions: if we - * have (x,y.f)(), we want to assign y to baseVar - */ - @Override - public void updateBase(T from, T to) { + public void copyOperation(T from, T to) { if (baseFor.contains(from)) baseFor.add(to); } } diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/types/JavaScriptMethods.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/types/JavaScriptMethods.java index 09204686f..2bba2eb30 100755 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/types/JavaScriptMethods.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/types/JavaScriptMethods.java @@ -30,4 +30,11 @@ public class JavaScriptMethods extends AstMethodReference { return MethodReference.findOrCreate(cls, ctorAtom, ctorDesc); } + public final static String dispatchAtomStr = "dispatch"; + public final static Atom dispatchAtom = Atom.findOrCreateUnicodeAtom(dispatchAtomStr); + public final static String dispatchDescStr = "()LRoot;"; + public final static Descriptor dispatchDesc = Descriptor.findOrCreateUTF8(JavaScriptLoader.JS, dispatchDescStr); + public final static MethodReference dispatchReference = + MethodReference.findOrCreate(JavaScriptTypes.CodeBody, dispatchAtom, dispatchDesc); + } 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 f62fb4baa..3cb7492cb 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 @@ -516,8 +516,8 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa } - protected void visitInvokeInternal(final SSAAbstractInvokeInstruction instruction) { - super.visitInvokeInternal(instruction); + protected void visitInvokeInternal(final SSAAbstractInvokeInstruction instruction, InvariantComputer invs) { + super.visitInvokeInternal(instruction, invs); if (instruction instanceof AbstractLexicalInvoke) { AbstractLexicalInvoke I = (AbstractLexicalInvoke) instruction; for (int wi = 0; wi < I.getNumberOfDefs(); wi++) { @@ -981,7 +981,7 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa // // ///////////////////////////////////////////////////////////////////////// - private interface ReflectedFieldAction { + protected interface ReflectedFieldAction { void action(AbstractFieldPointerKey fieldKey); void dump(AbstractFieldPointerKey fieldKey, boolean constObj, boolean constProp); @@ -1090,7 +1090,7 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa } - private void newFieldFullOperation(final boolean isLoadOperation, final ReflectedFieldAction action, PointerKey objKey, + protected void newFieldFullOperation(final boolean isLoadOperation, final ReflectedFieldAction action, PointerKey objKey, final PointerKey fieldKey) { system.newSideEffect(new AbstractOperator() { private final MutableIntSet doneReceiver = IntSetUtil.make(); @@ -1148,7 +1148,7 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa }, objKey, fieldKey); } - private void newFieldOperationOnlyFieldConstant(final boolean isLoadOperation, final ReflectedFieldAction action, + protected void newFieldOperationOnlyFieldConstant(final boolean isLoadOperation, final ReflectedFieldAction action, final PointerKey objKey, final InstanceKey[] fieldsKeys) { system.newSideEffect(new UnaryOperator() { public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) { @@ -1198,7 +1198,7 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa }, objKey); } - private void newFieldOperationOnlyObjectConstant(final boolean isLoadOperation, final ReflectedFieldAction action, + protected void newFieldOperationOnlyObjectConstant(final boolean isLoadOperation, final ReflectedFieldAction action, final PointerKey fieldKey, final InstanceKey[] objKeys) { if (!isLoadOperation) { for (int o = 0; o < objKeys.length; o++) { @@ -1245,7 +1245,7 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa }, fieldKey); } - private void newFieldOperationObjectAndFieldConstant(final boolean isLoadOperation, final ReflectedFieldAction action, + protected void newFieldOperationObjectAndFieldConstant(final boolean isLoadOperation, final ReflectedFieldAction action, final InstanceKey[] objKeys, InstanceKey[] fieldsKeys) { for (int o = 0; o < objKeys.length; o++) { PointerKey objCatalog = getPointerKeyForObjectCatalog(objKeys[o]); diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/translator/AstTranslator.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/translator/AstTranslator.java index adb82a01c..76941ff06 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/translator/AstTranslator.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/translator/AstTranslator.java @@ -95,7 +95,7 @@ public abstract class AstTranslator extends CAstVisitor { case CAstNode.PRIMITIVE: { if (visitor.visitPrimitive(n, context, visitor)) break; + visitor.visitAllChildren(n, context, visitor); visitor.leavePrimitive(n, context, visitor); break; } diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/util/CAstPattern.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/util/CAstPattern.java index e8de9d2d0..d42135aa0 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/util/CAstPattern.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/util/CAstPattern.java @@ -12,14 +12,20 @@ package com.ibm.wala.cast.util; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeMap; +import java.util.regex.Pattern; +import com.ibm.wala.cast.tree.CAstEntity; import com.ibm.wala.cast.tree.CAstNode; +import com.ibm.wala.cast.tree.visit.CAstVisitor; +import com.ibm.wala.cast.tree.visit.CAstVisitor.Context; import com.ibm.wala.util.collections.HashMapFactory; +import com.ibm.wala.util.collections.HashSetFactory; import com.ibm.wala.util.debug.Assertions; public class CAstPattern { @@ -38,14 +44,14 @@ public class CAstPattern { private final static int OPTIONAL_PATTERN_KIND = -5; private final static int REFERENCE_PATTERN_KIND = -6; - + private final static int IGNORE_KIND = -99; private final String name; private final int kind; - private final String value; + private final Object value; private final CAstPattern[] children; @@ -59,16 +65,16 @@ public class CAstPattern { } @SuppressWarnings("unchecked") - public List getMultiple(String name) { + public List getMultiple(String name) { if (!containsKey(name)) { return Collections.emptyList(); } else { Object o = get(name); if (o instanceof CAstNode) { - return Collections.singletonList(o); + return Collections.singletonList((CAstNode)o); } else { assert o instanceof List; - return (List) o; + return (List) o; } } } @@ -114,7 +120,7 @@ public class CAstPattern { this.references = null; } - public CAstPattern(String name, String value) { + public CAstPattern(String name, Object value) { this.name = name; this.kind = IGNORE_KIND; this.value = value; @@ -140,6 +146,8 @@ public class CAstPattern { if (value != null) { if (kind == REFERENCE_PATTERN_KIND) { sb.append("ref:").append(value); + } else if (value instanceof Pattern) { + sb.append("/").append(value).append("/"); } else { sb.append("literal:").append(value); } @@ -296,8 +304,12 @@ public class CAstPattern { return false; } else { - if ((value == null) ? tree.getKind() != kind : (tree.getKind() != CAstNode.CONSTANT || !value.equals(tree.getValue() - .toString()))) { + if ((value == null) ? tree.getKind() != kind : + (tree.getKind() != CAstNode.CONSTANT || + (value instanceof Pattern + ? !((Pattern)value).matcher(tree.getValue().toString()).matches() + : !value.equals(tree.getValue().toString())))) + { if (DEBUG_MATCH) { System.err.println("match failed (b)"); } @@ -364,6 +376,29 @@ public class CAstPattern { } } + public static Collection findAll(final CAstPattern p, final CAstEntity e) { + final Collection result = HashSetFactory.make(); + CAstVisitor v = new CAstVisitor() { + + @Override + public void leaveNode(CAstNode n, Context c, CAstVisitor visitor) { + Segments s = match(p, n); + if (s != null) { + result.add(s); + } + } + + }; + + v.visit(e.getAST(), new Context() { + public CAstEntity top() { + return e; + } + }, v); + + return result; + } + private static class Parser { private final Map namedPatterns = HashMapFactory.make(); @@ -414,6 +449,11 @@ public class CAstPattern { end = strEnd + 1; result = new CAstPattern(name, patternString.substring(start + 1, strEnd)); + } else if (patternString.charAt(start) == '/') { + int strEnd = patternString.indexOf('/', start + 1); + end = strEnd + 1; + result = new CAstPattern(name, Pattern.compile(patternString.substring(start + 1, strEnd))); + } else if (patternString.startsWith("**", start)) { end = start + 2; result = new CAstPattern(name, CHILDREN_KIND, null); 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 e25c40ef1..5642d6dad 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 @@ -203,6 +203,10 @@ public class PropagationSystem extends DefaultFixedPointSolver op, PointerKey rhs) { + public boolean newConstraint(PointerKey lhs, AbstractOperator op, PointerKey rhs) { if (lhs == null) { throw new IllegalArgumentException("lhs null"); } @@ -357,10 +361,10 @@ public class PropagationSystem extends DefaultFixedPointSolver op, PointerKey rhs1, PointerKey rhs2) { + public boolean newConstraint(PointerKey lhs, AbstractOperator op, PointerKey rhs1, PointerKey rhs2) { if (lhs == null) { throw new IllegalArgumentException("null lhs"); } @@ -382,7 +386,7 @@ public class PropagationSystem extends DefaultFixedPointSolver pks = new ArrayList(params.size()); params.foreach(new IntSetAction() { public void act(int x) { - if (! contentsAreInvariant(symbolTable, du, instruction.getUse(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, params); + invariantParameters, uniqueCatch, params); system.newSideEffect(dispatchOperator, pks.toArray(new PointerKey[pks.size()])); } } @@ -1326,13 +1329,20 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap basicBlock = block; } + protected interface InvariantComputer { + + InstanceKey[][] computeInvariantParameters(SSAAbstractInvokeInstruction call); + + } + + public class DefaultInvariantComputer implements InvariantComputer { /** * Side effect: records invariant parameters as implicit points-to-sets. * * @return if non-null, then result[i] holds the set of instance keys which may be passed as the ith parameter. (which must be * invariant) */ - protected InstanceKey[][] computeInvariantParameters(SSAAbstractInvokeInstruction call) { + public InstanceKey[][] computeInvariantParameters(SSAAbstractInvokeInstruction call) { InstanceKey[][] constParams = null; for (int i = 0; i < call.getNumberOfUses(); i++) { // not sure how getUse(i) <= 0 .. dead code? @@ -1352,7 +1362,8 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap } return constParams; } - + } + @Override public void visitLoadMetadata(SSALoadMetadataInstruction instruction) { PointerKey def = getPointerKeyForLocal(instruction.getDef()); @@ -1592,10 +1603,17 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap public byte evaluate(PointsToSetVariable lhs, final PointsToSetVariable[] rhs) { assert dispatchIndices.length >= rhs.length : "bad operator at " + call; final MutableBoolean sideEffect = new MutableBoolean(); - // NOTE: we allow the value of points-to set variables other than rhs[0] - // to be null. rhs[0] is the receiver, so to avoid an exception it must be - // non-empty, but empty points-to sets in other slots are allowed. - final MutableIntSet receiverVals = rhs[0].getValue(); + + final MutableIntSet receiverVals; + if (constParams != null && constParams[0] != null) { + receiverVals = IntSetUtil.make(); + for(InstanceKey ik : constParams[0]) { + receiverVals.add(system.getInstanceIndex(ik)); + } + } else { + receiverVals = rhs[0].getValue(); + } + if (receiverVals == null) { // this constraint was put on the work list, probably by // initialization, @@ -1618,7 +1636,7 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap boolean newReceiver = !receiverVals.isSubset(previousPtrs[0]); // keep separate rhsIndex, since it doesn't advance for constant // parameters - int rhsIndex = 1; + int rhsIndex = (constParams != null && constParams[0] != null)? 0: 1; // we start at index 1 since we need to handle the receiver specially; see // below for (int index = 1; index < dispatchIndices.length; index++) { @@ -1738,7 +1756,7 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap // instanceof is OK because this class is final if (o instanceof DispatchOperator) { DispatchOperator other = (DispatchOperator) o; - return node.equals(other.node) && call.equals(other.call); + return node.equals(other.node) && call.equals(other.call) && Arrays.deepEquals(constParams, other.constParams); } else { return false; } @@ -1752,7 +1770,7 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap } } - protected void iterateCrossProduct(final CGNode caller, final CallSiteReference site, IntSet parameters, final VoidFunction f) { + protected void iterateCrossProduct(final CGNode caller, final CallSiteReference site, IntSet parameters, final InstanceKey[][] invariants, final VoidFunction f) { final IR ir = caller.getIR(); final int params[] = IntSetUtil.toArray(parameters); for (final SSAAbstractInvokeInstruction call : ir.getCalls(site)) { @@ -1765,21 +1783,20 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap 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); + InstanceKey[] ik = invariants!=null? invariants[p]: null; + if (ik != null) { + if (ik.length > 0) { + for (int i = 0; i < ik.length; i++) { + system.findOrCreateIndexForInstanceKey(ik[i]); + keys[p] = ik[i]; + rec(pi+1); + } + } else { + if (!site.isDispatch() || p != 0) { + keys[p] = null; + rec(pi+1); + } } - } else { - if (!site.isDispatch() || p != 0) { - keys[p] = null; - rec(pi+1); - } - } } else { IntSet s = system.findOrCreatePointsToSet(var).getValue(); if (s != null && !s.isEmpty()) { @@ -1802,7 +1819,7 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap } } - protected Set getTargetsForCall(final CGNode caller, final CallSiteReference site) { + protected Set getTargetsForCall(final CGNode caller, final CallSiteReference site, InstanceKey[][] invs) { IntSet params = contextSelector.getRelevantParameters(caller, site); if (!site.isStatic() && !params.contains(0)) { params = IntSetUtil.makeMutableCopy(params); @@ -1821,7 +1838,7 @@ public abstract class SSAPropagationCallGraphBuilder extends PropagationCallGrap } } }; - iterateCrossProduct(caller, site, params, f); + iterateCrossProduct(caller, site, params, invs, f); return targets; } 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 7c97529d1..8c10ce6fc 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 @@ -265,7 +265,7 @@ public abstract class AbstractFixedPointSolver> implement * @param operator the step operator * @throws IllegalArgumentException if lhs is null */ - public void newStatement(final T lhs, final NullaryOperator operator, final boolean toWorkList, final boolean eager) { + public boolean newStatement(final T lhs, final NullaryOperator operator, final boolean toWorkList, final boolean eager) { if (lhs == null) { throw new IllegalArgumentException("lhs is null"); } @@ -273,12 +273,13 @@ public abstract class AbstractFixedPointSolver> implement lhs.setOrderNumber(nextOrderNumber++); final NullaryStatement s = new BasicNullaryStatement(lhs, operator); if (getFixedPointSystem().containsStatement(s)) { - return; + return false; } nCreated++; getFixedPointSystem().addStatement(s); incorporateNewStatement(toWorkList, eager, s); topologicalCounter++; + return true; } @SuppressWarnings("unchecked") @@ -366,12 +367,12 @@ public abstract class AbstractFixedPointSolver> implement * @param op1 first operand on the rhs * @param op2 second operand on the rhs */ - public void newStatement(T lhs, AbstractOperator operator, T op1, T op2, boolean toWorkList, boolean eager) { + public boolean newStatement(T lhs, AbstractOperator operator, T op1, T op2, boolean toWorkList, boolean eager) { // add to the list of graph GeneralStatement s = new Statement(lhs, operator, op1, op2); if (getFixedPointSystem().containsStatement(s)) { - return; + return false; } if (lhs != null) { lhs.setOrderNumber(nextOrderNumber++); @@ -380,6 +381,7 @@ public abstract class AbstractFixedPointSolver> implement getFixedPointSystem().addStatement(s); incorporateNewStatement(toWorkList, eager, s); topologicalCounter++; + return true; } /** @@ -392,7 +394,7 @@ public abstract class AbstractFixedPointSolver> implement * @param op3 third operand on the rhs * @throws IllegalArgumentException if lhs is null */ - public void newStatement(T lhs, AbstractOperator operator, T op1, T op2, T op3, boolean toWorkList, boolean eager) { + public boolean newStatement(T lhs, AbstractOperator operator, T op1, T op2, T op3, boolean toWorkList, boolean eager) { if (lhs == null) { throw new IllegalArgumentException("lhs is null"); } @@ -401,13 +403,14 @@ public abstract class AbstractFixedPointSolver> implement GeneralStatement s = new Statement(lhs, operator, op1, op2, op3); if (getFixedPointSystem().containsStatement(s)) { nextOrderNumber--; - return; + return false; } nCreated++; getFixedPointSystem().addStatement(s); incorporateNewStatement(toWorkList, eager, s); topologicalCounter++; + return true; } /** @@ -417,19 +420,20 @@ public abstract class AbstractFixedPointSolver> implement * @param operator the operator * @param rhs the operands on the rhs */ - public void newStatement(T lhs, AbstractOperator operator, T[] rhs, boolean toWorkList, boolean eager) { + public boolean 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 Statement(lhs, operator, rhs); if (getFixedPointSystem().containsStatement(s)) { nextOrderNumber--; - return; + return false; } nCreated++; getFixedPointSystem().addStatement(s); incorporateNewStatement(toWorkList, eager, s); topologicalCounter++; + return true; } /**