diff --git a/com.ibm.wala.cast.java.test.data/src/javaonepointfive/AnonymousGenerics.java b/com.ibm.wala.cast.java.test.data/src/javaonepointfive/AnonymousGenerics.java index d518478d8..1ab55e264 100644 --- a/com.ibm.wala.cast.java.test.data/src/javaonepointfive/AnonymousGenerics.java +++ b/com.ibm.wala.cast.java.test.data/src/javaonepointfive/AnonymousGenerics.java @@ -83,5 +83,9 @@ public class AnonymousGenerics { Ops hack = ops; hack.unary("whatever"); + hack.nullary(); + hack = strQuadrupler; + hack.unary("whatever"); + hack.nullary(); } } diff --git a/com.ibm.wala.cast.js.rhino.test/harness-src/com/ibm/wala/cast/js/vis/JsViewerDriver.java b/com.ibm.wala.cast.js.rhino.test/harness-src/com/ibm/wala/cast/js/vis/JsViewerDriver.java index 370e1a562..58d527391 100644 --- a/com.ibm.wala.cast.js.rhino.test/harness-src/com/ibm/wala/cast/js/vis/JsViewerDriver.java +++ b/com.ibm.wala.cast.js.rhino.test/harness-src/com/ibm/wala/cast/js/vis/JsViewerDriver.java @@ -9,6 +9,7 @@ import com.ibm.wala.cast.js.html.DomLessSourceExtractor; import com.ibm.wala.cast.js.html.IdentityUrlResolver; import com.ibm.wala.cast.js.html.JSSourceExtractor; import com.ibm.wala.cast.js.html.MappedSourceModule; +import com.ibm.wala.cast.js.html.WebPageLoaderFactory; import com.ibm.wala.cast.js.html.WebUtil; import com.ibm.wala.cast.js.html.jericho.JerichoHtmlParser; import com.ibm.wala.cast.js.ipa.callgraph.JSCFABuilder; @@ -22,7 +23,7 @@ import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; import com.ibm.wala.ipa.cha.ClassHierarchyException; import com.ibm.wala.util.CancelException; -public class JsViewerDriver { +public class JsViewerDriver extends Util { public static void main(String args[]) throws ClassHierarchyException, IllegalArgumentException, IOException, CancelException { if (args.length != 1){ @@ -39,7 +40,7 @@ public class JsViewerDriver { SourceModule[] sources = getSources(domless, url); - JSCFABuilder builder = Util.makeCGBuilder(sources, false); + JSCFABuilder builder = makeCGBuilder(new WebPageLoaderFactory(translatorFactory), sources, false); builder.setBaseURL(url); CallGraph cg = builder.makeCallGraph(builder.getOptions()); diff --git a/com.ibm.wala.cast.js.rhino.test/launchers/TestForInLoopHackRhino.launch b/com.ibm.wala.cast.js.rhino.test/launchers/TestForInLoopHackRhino.launch new file mode 100644 index 000000000..79d51bc9d --- /dev/null +++ b/com.ibm.wala.cast.js.rhino.test/launchers/TestForInLoopHackRhino.launch @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/com.ibm.wala.cast.js.rhino.test/launchers/TestMozillaBugPagesRhino.launch b/com.ibm.wala.cast.js.rhino.test/launchers/TestMozillaBugPagesRhino.launch new file mode 100644 index 000000000..b3f21cb55 --- /dev/null +++ b/com.ibm.wala.cast.js.rhino.test/launchers/TestMozillaBugPagesRhino.launch @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/com.ibm.wala.cast.js.test/examples-src/pages/jquery.html b/com.ibm.wala.cast.js.test/examples-src/pages/jquery.html new file mode 100644 index 000000000..2bae2851f --- /dev/null +++ b/com.ibm.wala.cast.js.test/examples-src/pages/jquery.html @@ -0,0 +1,263 @@ + + + + + Untitled Document + + diff --git a/com.ibm.wala.cast.js.test/examples-src/pages/jquery_hacked.html b/com.ibm.wala.cast.js.test/examples-src/pages/jquery_hacked.html new file mode 100644 index 000000000..a37b6e147 --- /dev/null +++ b/com.ibm.wala.cast.js.test/examples-src/pages/jquery_hacked.html @@ -0,0 +1,288 @@ + + + + + Untitled Document + + diff --git a/com.ibm.wala.cast.js.test/examples-src/pages/windowx.html b/com.ibm.wala.cast.js.test/examples-src/pages/windowx.html new file mode 100644 index 000000000..3f508f7f3 --- /dev/null +++ b/com.ibm.wala.cast.js.test/examples-src/pages/windowx.html @@ -0,0 +1,33 @@ + + +Welcome! + +Hi + + + +
+Welcome to our system + + diff --git a/com.ibm.wala.cast.js.test/examples-src/tests/simple-lexical.js b/com.ibm.wala.cast.js.test/examples-src/tests/simple-lexical.js index 6fe192159..8eebe49af 100644 --- a/com.ibm.wala.cast.js.test/examples-src/tests/simple-lexical.js +++ b/com.ibm.wala.cast.js.test/examples-src/tests/simple-lexical.js @@ -69,4 +69,46 @@ function outer( x ) { return x+z; } +function c2() { + +} + +function c3() { + +} + +function fa2(x) { + x(); +} + +function fa3(x) { + x(); +} + +function aa() { + var c1 = function _c1() { + + } + + var fa = function _fa1(x) { + x(); + } + + function bb(x) { + fa = x; + } + + fa(c1); + + bb(fa2); + + fa(c2); + + bb(fa3); + + fa(c3); +} + var result = outer( 5 ); + +aa(); 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 index 20fe4c5a6..b916973bc 100644 --- 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 @@ -45,6 +45,24 @@ public class TestForInLoopHack extends TestJSCallGraphShape { Util.dumpCG(builder.getPointerAnalysis(), CG); } + @Test public void testJQueryWithHack() throws IOException, IllegalArgumentException, CancelException { + URL url = getClass().getClassLoader().getResource("pages/jquery_hacked.html"); + JSCFABuilder builder = Util.makeHTMLCGBuilder(url); + addHackedForInLoopSensitivity(builder); + CallGraph CG = builder.makeCallGraph(builder.getOptions()); + Util.dumpCG(builder.getPointerAnalysis(), CG); + } + + /* + @Test public void testJQueryEx1WithHack() throws IOException, IllegalArgumentException, CancelException { + URL url = getClass().getClassLoader().getResource("pages/jquery/ex1.html"); + JSCFABuilder builder = Util.makeHTMLCGBuilder(url); + addHackedForInLoopSensitivity(builder); + CallGraph CG = builder.makeCallGraph(builder.getOptions()); + Util.dumpCG(builder.getPointerAnalysis(), CG); + } + */ + private static final Object[][] assertionsForBadForin = new Object[][] { new Object[] { ROOT, new String[] { "tests/badforin.js" } }, diff --git a/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestMediawikiCallGraphShape.java b/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestMediawikiCallGraphShape.java index 4370272a0..85eea6497 100644 --- a/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestMediawikiCallGraphShape.java +++ b/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestMediawikiCallGraphShape.java @@ -32,6 +32,7 @@ public abstract class TestMediawikiCallGraphShape extends TestJSCallGraphShape { URL url = new URL("http://en.wikipedia.org/wiki/2009_swine_flu_outbreak"); CallGraph CG = Util.makeHTMLCG(url); verifyGraphAssertions(CG, assertionsForSwineFlu); + System.err.println(CG); } } diff --git a/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestSimplePageCallGraphShape.java b/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestSimplePageCallGraphShape.java index 7488e368d..48e2e5eb4 100644 --- a/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestSimplePageCallGraphShape.java +++ b/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestSimplePageCallGraphShape.java @@ -281,12 +281,31 @@ public abstract class TestSimplePageCallGraphShape extends TestJSCallGraphShape Util.makeHTMLCG(url); } + private static final Object[][] assertionsForWindowx = new Object[][] { + new Object[] { ROOT, new String[] { "windowx.html" } }, + new Object[] { "windowx.html", new String[] { "windowx.html/__WINDOW_MAIN__" } }, + new Object[] { "windowx.html/__WINDOW_MAIN__", new String[] { "windowx.html/__WINDOW_MAIN__/_f2", "windowx.html/__WINDOW_MAIN__/_f4" } }, + new Object[] { "windowx.html/__WINDOW_MAIN__/_f2", new String[] { "windowx.html/__WINDOW_MAIN__/_f1" } }, + new Object[] { "windowx.html/__WINDOW_MAIN__/_f4", new String[] { "windowx.html/__WINDOW_MAIN__/_f3" } } + + }; + + @Test public void testWindowx() throws IOException, IllegalArgumentException, CancelException { + URL url = getClass().getClassLoader().getResource("pages/windowx.html"); + JSCFABuilder builder = Util.makeHTMLCGBuilder(url); + CallGraph CG = builder.makeCallGraph(builder.getOptions()); + Util.dumpCG(builder.getPointerAnalysis(), CG); + verifyGraphAssertions(CG, assertionsForWindowx); + } + /* @Test public void testJQuery() throws IOException, IllegalArgumentException, CancelException { URL url = getClass().getClassLoader().getResource("pages/jquery.html"); CallGraph CG = Util.makeHTMLCG(url); } + */ + /* @Test public void testDojoTest() throws IllegalArgumentException, IOException, CancelException { URL url = getClass().getClassLoader().getResource("pages/dojo/test.html"); CallGraph CG = Util.makeHTMLCG(url); diff --git a/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/Util.java b/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/Util.java index f6a9edb81..cb7003674 100644 --- a/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/Util.java +++ b/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/Util.java @@ -19,6 +19,7 @@ import java.util.Set; import junit.framework.Assert; import com.ibm.wala.cast.js.html.MappedSourceModule; +import com.ibm.wala.cast.js.html.WebPageLoaderFactory; import com.ibm.wala.cast.js.html.WebUtil; import com.ibm.wala.cast.js.ipa.callgraph.JSCFABuilder; import com.ibm.wala.cast.js.ipa.callgraph.JSZeroOrOneXCFABuilder; @@ -77,7 +78,7 @@ public class Util extends com.ibm.wala.cast.js.ipa.callgraph.Util { public static CallGraph makeScriptCG(SourceModule[] scripts, boolean useOneCFA) throws IOException, IllegalArgumentException, CancelException { - PropagationCallGraphBuilder b = makeCGBuilder(scripts, useOneCFA); + PropagationCallGraphBuilder b = makeCGBuilder(makeLoaders(), scripts, useOneCFA); CallGraph CG = b.makeCallGraph(b.getOptions()); dumpCG(b.getPointerAnalysis(), CG); return CG; @@ -86,7 +87,7 @@ public class Util extends com.ibm.wala.cast.js.ipa.callgraph.Util { public static JSCFABuilder makeHTMLCGBuilder(URL url) throws IOException { JavaScriptLoader.addBootstrapFile(WebUtil.preamble); Set script = WebUtil.extractScriptFromHTML(url); - JSCFABuilder builder = makeCGBuilder(script.toArray(new SourceModule[script.size()]), false); + JSCFABuilder builder = makeCGBuilder(new WebPageLoaderFactory(translatorFactory), script.toArray(new SourceModule[script.size()]), false); builder.setBaseURL(url); return builder; } @@ -105,8 +106,7 @@ public class Util extends com.ibm.wala.cast.js.ipa.callgraph.Util { return CG; } - public static JSCFABuilder makeCGBuilder(SourceModule[] scripts, boolean useOneCFA) throws IOException { - JavaScriptLoaderFactory loaders = makeLoaders(); + public static JSCFABuilder makeCGBuilder(JavaScriptLoaderFactory loaders, SourceModule[] scripts, boolean useOneCFA) throws IOException { AnalysisScope scope = makeScope(scripts, loaders, JavaScriptLoader.JS); return makeCG(loaders, scope, useOneCFA); } diff --git a/com.ibm.wala.cast.js/dat/preamble.js b/com.ibm.wala.cast.js/dat/preamble.js index 4f5923535..5d53c3f2c 100644 --- a/com.ibm.wala.cast.js/dat/preamble.js +++ b/com.ibm.wala.cast.js/dat/preamble.js @@ -15,7 +15,7 @@ note_post_parameters = function notePostParameters(url) { // hook for analysis of Web pages }; -function NamedNodeList() { +NamedNodeList = function NamedNodeList() { var maxLength = 10; var local = new Array(10); var counter = -1; @@ -85,7 +85,7 @@ function NamedNodeList() { } } -function DOMNode() { // An impostor for the Node class +DOMNode = function DOMNode() { // An impostor for the Node class this.childNodes = new NamedNodeList(); this.insertBefore = function insertBefore(newChild, refChild) { this.childNodes.insertBefore(newChild, refChild); @@ -116,7 +116,7 @@ function DOMNode() { // An impostor for the Node class } } -function DOMDocument() { +DOMDocument = function DOMDocument() { this.temp = DOMNode; this.temp(); @@ -137,11 +137,11 @@ function DOMDocument() { }; } -function HTMLBody(){ +HTMLBody = function HTMLBody(){ this.innerHTML = new String(); } -function DOMHTMLDocument() { +DOMHTMLDocument = function DOMHTMLDocument() { this.temp = DOMDocument; this.temp(); this.URL = new String(); @@ -150,7 +150,7 @@ function DOMHTMLDocument() { } -function Location(){ +Location = function Location(){ this.host = new String(); this.hostname = new String(); this.href = new String(); @@ -163,14 +163,14 @@ function Location(){ } -function DOMWindow(){ +DOMWindow = function DOMWindow(){ this.name = new String(); this.open = function window_open(url, stuff) { note_url(url); }; } -function DOJOObj(){ +DOJOObj = function DOJOObj(){ this.moduleUrl = function module_url(str1, str2){ return str1 + str2; } @@ -194,7 +194,7 @@ window.XMLHttpRequest = XMLHttpRequest; var dojo = new DOJOObj(); -function DOMElement() { // An impostor for the Element class +DOMElement = function DOMElement() { // An impostor for the Element class // inherits from Node this.temp = DOMNode; this.temp(); @@ -215,7 +215,7 @@ function DOMElement() { // An impostor for the Element class } -function DOMHTMLElement() { // An impostor for the HTMLElement class +DOMHTMLElement = function DOMHTMLElement() { // An impostor for the HTMLElement class // inherits from Element this.temp = DOMElement; this.temp(); @@ -234,7 +234,7 @@ function DOMHTMLElement() { // An impostor for the HTMLElement class var dynamic_node = 0; // Just a hack until all HTML elements have corresponding constructors -function DOMHTMLGenericElement(tagName) { +DOMHTMLGenericElement = function DOMHTMLGenericElement(tagName) { // inherits from Element this.temp = DOMHTMLElement; this.temp(); @@ -253,7 +253,7 @@ function DOMHTMLGenericElement(tagName) { var formCount = 0; -function DOMHTMLFormElement() { +DOMHTMLFormElement = function DOMHTMLFormElement() { // inherits from HTMLElement this.temp = DOMHTMLElement; this.temp(); @@ -281,7 +281,7 @@ function DOMHTMLFormElement() { this.target = null; } -function DOMHTMLTableElement () { +DOMHTMLTableElement = function DOMHTMLTableElement () { // inherits from HTMLElement this.temp = DOMHTMLElement; this.temp(); diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/WebPageLoaderFactory.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/WebPageLoaderFactory.java new file mode 100644 index 000000000..c42ba63fb --- /dev/null +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/html/WebPageLoaderFactory.java @@ -0,0 +1,91 @@ +package com.ibm.wala.cast.js.html; + +import com.ibm.wala.cast.ir.translator.TranslatorToIR; +import com.ibm.wala.cast.js.loader.JavaScriptLoader; +import com.ibm.wala.cast.js.loader.JavaScriptLoaderFactory; +import com.ibm.wala.cast.js.ssa.JSInstructionFactory; +import com.ibm.wala.cast.js.translator.JSAstTranslator; +import com.ibm.wala.cast.js.translator.JavaScriptTranslatorFactory; +import com.ibm.wala.cast.tree.CAst; +import com.ibm.wala.cast.tree.CAstNode; +import com.ibm.wala.cast.tree.impl.CAstImpl; +import com.ibm.wala.cast.tree.impl.CAstOperator; +import com.ibm.wala.classLoader.IClassLoader; +import com.ibm.wala.ipa.cha.IClassHierarchy; + +public class WebPageLoaderFactory extends JavaScriptLoaderFactory { + + public WebPageLoaderFactory(JavaScriptTranslatorFactory factory) { + super(factory); + } + + @Override + protected IClassLoader makeTheLoader(IClassHierarchy cha) { + return new JavaScriptLoader( cha, translatorFactory ) { + @Override + protected TranslatorToIR initTranslator() { + return new JSAstTranslator(this) { + private final CAst Ast = new CAstImpl(); + + private boolean isScriptBody(WalkContext context) { + return context.top().getName().equals( "__WINDOW_MAIN__" ); + } + + @Override + protected int doGlobalRead(CAstNode n, WalkContext context, String name) { + int result = context.currentScope().allocateTempValue(); + if (isScriptBody(context) && ! "$$undefined".equals(name) && ! "window".equals(name)) { + + // check if field is defined on 'window' + int windowVal = super.doLocalRead(context, "this"); + int isDefined = context.currentScope().allocateTempValue(); + context.currentScope().getConstantValue(name); + doIsFieldDefined(context, isDefined, windowVal, Ast.makeConstant(name)); + context.cfg().addInstruction( + insts.ConditionalBranchInstruction( + translateConditionOpcode(CAstOperator.OP_NE), + null, + isDefined, + context.currentScope().getConstantValue(new Integer(0)))); + PreBasicBlock srcB = context.cfg().getCurrentBlock(); + + // field lookup of value + context.cfg().newBlock(true); + context.cfg().addInstruction(((JSInstructionFactory) insts).GetInstruction(result, windowVal, name)); + context.cfg().addInstruction(insts.GotoInstruction()); + PreBasicBlock trueB = context.cfg().getCurrentBlock(); + + // read global + context.cfg().newBlock(false); + PreBasicBlock falseB = context.cfg().getCurrentBlock(); + int sr = super.doGlobalRead(n, context, name); + context.cfg().addInstruction(((JSInstructionFactory) insts).AssignInstruction(result, sr)); + + // end + context.cfg().newBlock(true); + + context.cfg().addEdge(trueB, context.cfg().getCurrentBlock()); + context.cfg().addEdge(srcB, falseB); + + return result; + + } else { + return super.doGlobalRead(n, context, name); + } + } + + @Override + protected void doLocalWrite(WalkContext context, String nm, int rval) { + if (isScriptBody(context)) { + int windowVal = super.doLocalRead(context, "this"); + context.currentScope().getConstantValue(nm); + context.cfg().addInstruction(((JSInstructionFactory) insts).PutInstruction(windowVal, rval, nm)); + } + + super.doLocalWrite(context, nm, rval); + } + }; + } + }; + } +} 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 44832c3e1..759ed06a9 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 @@ -482,7 +482,7 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph IR sourceIR = getCFAContextInterpreter().getIR(caller); SymbolTable sourceST = sourceIR.getSymbolTable(); - + IR targetIR = getCFAContextInterpreter().getIR(target); SymbolTable targetST = targetIR.getSymbolTable(); @@ -504,7 +504,7 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph // pass actual arguments to formals in the normal way for (int i = 0; i < Math.min(paramCount, argCount); i++) { - int fn = targetST.getConstant(i); + InstanceKey[] fn = new InstanceKey[]{ getInstanceKeyForConstant(JavaScriptTypes.Number, i) }; PointerKey F = getTargetPointerKey(target, i); if (constParams != null && constParams[i] != null) { @@ -528,7 +528,7 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph if (paramCount < argCount) { if (av != -1) { for (int i = paramCount; i < argCount; i++) { - int fn = targetST.getConstant(i); + InstanceKey[] fn = new InstanceKey[]{ getInstanceKeyForConstant(JavaScriptTypes.Number, i) }; if (constParams != null && constParams[i] != null) { targetVisitor.newFieldWrite(target, av, fn, constParams[i]); } else { @@ -554,8 +554,8 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph // write `length' in argument objects if (av != -1) { - int svn = targetST.getConstant(argCount); - int lnv = targetST.getConstant("length"); + InstanceKey[] svn = new InstanceKey[]{ getInstanceKeyForConstant(JavaScriptTypes.Number, argCount) }; + InstanceKey[] lnv = new InstanceKey[]{ getInstanceKeyForConstant(JavaScriptTypes.String, "length") }; targetVisitor.newFieldWrite(target, av, lnv, svn); } 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 1c41d8200..8d7a407d2 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 @@ -10,6 +10,7 @@ *****************************************************************************/ package com.ibm.wala.cast.js.ipa.callgraph; +import com.ibm.wala.cast.ipa.callgraph.LexicalScopingResolverContexts; import com.ibm.wala.cast.ipa.callgraph.ScopeMappingKeysContextSelector; import com.ibm.wala.ipa.callgraph.AnalysisCache; import com.ibm.wala.ipa.callgraph.AnalysisOptions; @@ -42,6 +43,7 @@ public class JSZeroOrOneXCFABuilder extends JSCFABuilder { ContextSelector contextSelector = appContextSelector == null ? def : new DelegatingContextSelector(appContextSelector, def); contextSelector = new ScopeMappingKeysContextSelector(contextSelector); contextSelector = new JavaScriptConstructorContextSelector(contextSelector); + contextSelector = new LexicalScopingResolverContexts(this, contextSelector); if (doOneCFA) { contextSelector = new nCFAContextSelector(1, contextSelector); } diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/Util.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/Util.java index 6d4899821..34cf585ef 100755 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/Util.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/ipa/callgraph/Util.java @@ -58,7 +58,7 @@ public class Util extends com.ibm.wala.cast.ipa.callgraph.Util { * the translator factory to be used for analysis TODO: pass the factory where * needed instead of using a global? */ - private static JavaScriptTranslatorFactory translatorFactory; + protected static JavaScriptTranslatorFactory translatorFactory; /** * Set up the translator factory. This method should be called before invoking diff --git a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/loader/JavaScriptLoaderFactory.java b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/loader/JavaScriptLoaderFactory.java index 2fad42b9d..f147b19cc 100755 --- a/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/loader/JavaScriptLoaderFactory.java +++ b/com.ibm.wala.cast.js/source/com/ibm/wala/cast/js/loader/JavaScriptLoaderFactory.java @@ -21,7 +21,7 @@ import com.ibm.wala.types.ClassLoaderReference; * Creates the single {@link IClassLoader class loader} used for JavaScript. */ public class JavaScriptLoaderFactory extends SingleClassLoaderFactory { - private final JavaScriptTranslatorFactory translatorFactory; + protected final JavaScriptTranslatorFactory translatorFactory; public JavaScriptLoaderFactory(JavaScriptTranslatorFactory factory) { this.translatorFactory = factory; 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 53cf60b6e..a6d109a31 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 @@ -58,7 +58,7 @@ public class JSAstTranslator extends AstTranslator { } protected boolean treatGlobalsAsLexicallyScoped() { - return true; + return false; } protected boolean useLocalValuesForLexicalVars() { @@ -145,12 +145,7 @@ public class JSAstTranslator extends AstTranslator { // force creation of these constants by calling the getter methods symtab.getNullConstant(); - symtab.getConstant("arguments"); - symtab.getConstant("length"); - for (int i = 0; i < 20; i++) { - symtab.getConstant(i); - } - + ((JavaScriptLoader) loader).defineCodeBodyCode("L" + fnName, cfg, symtab, hasCatchBlock, caughtTypes, hasMonitorOp, LI, debugInfo); } 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 e9e8f25b6..af9b7454f 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 @@ -17,6 +17,7 @@ import java.util.Set; import com.ibm.wala.analysis.reflection.ReflectionContextInterpreter; import com.ibm.wala.cast.ipa.callgraph.AstCallGraph.AstCGNode; +import com.ibm.wala.cast.ipa.callgraph.LexicalScopingResolverContexts.Resolver; import com.ibm.wala.cast.ipa.callgraph.ScopeMappingInstanceKeys.ScopeMappingInstanceKey; import com.ibm.wala.cast.ir.ssa.AbstractLexicalInvoke; import com.ibm.wala.cast.ir.ssa.AstAssertInstruction; @@ -26,6 +27,7 @@ import com.ibm.wala.cast.ir.ssa.AstGlobalWrite; import com.ibm.wala.cast.ir.ssa.AstIRFactory.AstIR; import com.ibm.wala.cast.ir.ssa.AstInstructionVisitor; import com.ibm.wala.cast.ir.ssa.AstIsDefinedInstruction; +import com.ibm.wala.cast.ir.ssa.AstLexicalAccess; import com.ibm.wala.cast.ir.ssa.AstLexicalAccess.Access; import com.ibm.wala.cast.ir.ssa.AstLexicalRead; import com.ibm.wala.cast.ir.ssa.AstLexicalWrite; @@ -301,39 +303,30 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa return ((AstPointerKeyFactory) getBuilder().getPointerKeyFactory()).getPointerKeysForReflectedFieldWrite(I, F); } - private void visitLexical(final LexicalOperator op) { - final PointerKey function = getPointerKeyForLocal(1); - if (contentsAreInvariant(symbolTable, du, 1)) { - op.doLexicalPointerKeys(); - } else { - system.newSideEffect(op, function); + private void visitLexical(AstLexicalAccess instruction, final LexicalOperator op) { + op.doLexicalPointerKeys(false); + if (! checkLexicalInstruction(instruction)) { + system.newSideEffect(op, getPointerKeyForLocal(1)); } - - // when a new caller is added for node, re-process the lexical access - class LexicalScopingCallback implements Function { - public Object apply(Object ignore) { - op.doLexicalPointerKeys(); - return null; - } - - private LexicalOperator getOperator() { - return op; - } - - public int hashCode() { - return op.hashCode(); - } - - public boolean equals(Object o) { - return (o instanceof LexicalScopingCallback) && ((LexicalScopingCallback) o).getOperator().equals(op); - } - } - - ((AstCGNode) node).addCallback(new LexicalScopingCallback()); } - public void visitAstLexicalRead(AstLexicalRead instruction) { - visitLexical(new LexicalOperator((AstCGNode) node, instruction.getAccesses(), true) { + private boolean checkLexicalInstruction(AstLexicalAccess instruction) { + Resolver r = (Resolver)node.getContext().get(LexicalScopingResolverContexts.RESOLVER); + if (r == null) { + return false; + } else { + for(Access a : instruction.getAccesses()) { + if (r.getLexicalSites(a) == null) { + return false; + } + } + } + + return true; + } + + public void visitAstLexicalRead(AstLexicalRead instruction) { + visitLexical(instruction, new LexicalOperator((AstCGNode) node, instruction.getAccesses(), true) { protected void action(PointerKey lexicalKey, int vn) { PointerKey lval = getPointerKeyForLocal(vn); if (lexicalKey instanceof LocalPointerKey) { @@ -360,7 +353,7 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa } public void visitAstLexicalWrite(AstLexicalWrite instruction) { - visitLexical(new LexicalOperator((AstCGNode) node, instruction.getAccesses(), false) { + visitLexical(instruction, new LexicalOperator((AstCGNode) node, instruction.getAccesses(), false) { protected void action(PointerKey lexicalKey, int vn) { PointerKey rval = getPointerKeyForLocal(vn); if (contentsAreInvariant(symbolTable, du, vn)) { @@ -403,11 +396,10 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa } catch (UTFDataFormatException e) { Assertions.UNREACHABLE(); } - int fieldNameVn = symtab.getConstant(fieldName); final PointerKey objKey = getPointerKeyForLocal(objVn); - final InstanceKey[] fieldNameKeys = getInvariantContents(fieldNameVn); + final InstanceKey[] fieldNameKeys = new InstanceKey[]{ getInstanceKeyForConstant(fieldName) }; assert fieldNameKeys.length == 1; if (contentsAreInvariant(symtab, du, objVn)) { @@ -539,12 +531,14 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa // callees where the name is not written; // in such cases, the original value (rk) is preserved PointerKey rk = getBuilder().getPointerKeyForLocal(node, r.valueNumber); - PointerKey wk = getBuilder().getPointerKeyForLocal(node, w.valueNumber); - if (contentsAreInvariant(symbolTable, du, r.valueNumber)) { + PointerKey wk = getBuilder().getPointerKeyForLocal(node, w.valueNumber); + if (contentsAreInvariant(node.getIR().getSymbolTable(), du, r.valueNumber)) { system.recordImplicitPointsToSet(rk); - for (InstanceKey ik : getInvariantContents(r.valueNumber)) { - system.newConstraint(wk, ik); - } + final InstanceKey[] objKeys = getInvariantContents(r.valueNumber); + + for (int i = 0; i < objKeys.length; i++) { + system.newConstraint(wk, objKeys[0]); + } } else { system.newConstraint(wk, assignOperator, rk); } @@ -600,7 +594,8 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa * {@link AstConstraintVisitor#handleRootLexicalReference(String, String, CGNode)} * . */ - private void doLexicalPointerKeys() { + private void doLexicalPointerKeys(boolean funargsOnly) { + Resolver r = (Resolver)node.getContext().get(LexicalScopingResolverContexts.RESOLVER); for (int i = 0; i < accesses.length; i++) { final String name = accesses[i].variableName; final String definer = accesses[i].variableDefiner; @@ -609,49 +604,31 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa if (AstTranslator.DEBUG_LEXICAL) System.err.println(("looking up lexical parent " + definer)); - for (Iterator DS = getLexicalDefiners(node, definer).iterator(); DS.hasNext();) { - final CGNode D = DS.next(); - - Iterator PS = new NumberedDFSDiscoverTimeIterator(getBuilder().getCallGraph(), node) { - /** - * - */ - private static final long serialVersionUID = 4546217460630659884L; - - protected void visitEdge(CGNode callee, CGNode caller) { - CGNode from = (CGNode) caller; - CGNode to = (CGNode) callee; - - for (Iterator SS = cg.getPossibleSites(from, to); SS.hasNext();) { - CallSiteReference site = (CallSiteReference) SS.next(); - - PointerKey V = isLoad ? getLocalReadKey(from, site, name, definer, D) : getLocalWriteKey(from, site, name, - definer, D); + Iterator> sites; + if (r != null && (sites = r.getLexicalSites(accesses[i])) != null) { + if (! funargsOnly) { + while(sites.hasNext()) { + Pair x = sites.next(); + PointerKey V = + isLoad ? getLocalReadKey(x.snd, x.fst, name, definer) : getLocalWriteKey(x.snd, x.fst, name, definer); if (V != null) { action(V, vn); } - } - } - - protected Iterator getConnected(CGNode n) { - if (n.equals(D)) - return EmptyIterator.instance(); - else - // traverse backwards - return G.getPredNodes(n); - } - }; - - while (PS.hasNext()) { - PS.next(); + } + } + } else { + Set creators = getLexicalDefiners(node, Pair.make(name, definer)); + for(CGNode n : creators) { + PointerKey funargKey = handleRootLexicalReference(name, definer, n); + action(funargKey, vn); } } } } public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) { - doLexicalPointerKeys(); + doLexicalPointerKeys(true); return NOT_CHANGED; } @@ -699,7 +676,7 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa } } - private Set getLexicalDefiners(final CGNode opNode, final String definer) { + private Set getLexicalDefiners(final CGNode opNode, final Pair definer) { if (definer == null) { return Collections.singleton(getBuilder().getCallGraph().getFakeRootNode()); @@ -716,7 +693,10 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa for (int f = 0; f < functionKeys.length; f++) { system.findOrCreateIndexForInstanceKey(functionKeys[f]); ScopeMappingInstanceKey K = (ScopeMappingInstanceKey) functionKeys[f]; - result.add(K.getDefiningNode(definer)); + Iterator x = K.getFunargNodes(definer); + while (x.hasNext()) { + result.add(x.next()); + } } } else { PointsToSetVariable FV = system.findOrCreatePointsToSet(F); @@ -726,7 +706,10 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa InstanceKey iKey = system.getInstanceKey(ptr); if (iKey instanceof ScopeMappingInstanceKey) { ScopeMappingInstanceKey K = (ScopeMappingInstanceKey) iKey; - result.add(K.getDefiningNode(definer)); + Iterator x = K.getFunargNodes(definer); + while (x.hasNext()) { + result.add(x.next()); + } } else { Assertions.UNREACHABLE("unexpected instance key " + iKey); } @@ -842,163 +825,135 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa * now know the name is accessed by some transitive callee), thereby * requiring marking of the IR as mutated. */ - private PointerKey getLocalReadKey(CGNode n, CallSiteReference callSite, String name, String definer, CGNode definingNode) { - IMethod M = n.getMethod(); - if (n == getBuilder().getCallGraph().getFakeRootNode()) { - return handleRootLexicalReference(name, definer, definingNode); + private PointerKey getLocalReadKey(CGNode n, CallSiteReference callSite, String name, String definer) { + AstIR ir = (AstIR) n.getIR(); + int pc = callSite.getProgramCounter(); + LexicalInformation L = ((AstIR) n.getIR()).lexicalInfo(); + + AbstractLexicalInvoke I = (AbstractLexicalInvoke) ir.getInstructions()[pc]; + + // find existing explicit lexical use + for (int i = I.getNumberOfParameters(); i <= I.getLastLexicalUse(); i++) { + Access A = I.getLexicalUse(i); + if (A.variableName.equals(name) && isEqual(A.variableDefiner, definer)) { + return getBuilder().getPointerKeyForLocal(n, A.valueNumber); + } } - else if (M instanceof AstMethod) { - AstIR ir = (AstIR) n.getIR(); - int pc = callSite.getProgramCounter(); - LexicalInformation L = ((AstIR) n.getIR()).lexicalInfo(); + // make new lexical use + int values[] = L.getExposedUses(pc); + Pair names[] = L.getExposedNames(); + if (names != null && names.length > 0) { + for (int i = 0; i < names.length; i++) { + if (name.equals(names[i].fst) && isEqual(definer, names[i].snd)) { + if (values[i] == -1) + return null; - // some people have no lexical uses at all - if (L == null) { - return null; - } + I.addLexicalUse(new Access(name, definer, values[i])); - AbstractLexicalInvoke I = (AbstractLexicalInvoke) ir.getInstructions()[pc]; + if (SSAConversion.DEBUG_UNDO) + System.err.println(("copy use #" + (-i - 1) + " to use #" + (I.getNumberOfUses() - 1) + " at inst " + pc)); - // find existing explicit lexical use - for (int i = I.getNumberOfParameters(); i <= I.getLastLexicalUse(); i++) { - Access A = I.getLexicalUse(i); - if (A.variableName.equals(name) && isEqual(A.variableDefiner, definer)) { - return getBuilder().getPointerKeyForLocal(n, A.valueNumber); + SSAConversion.copyUse(ir, pc, -i - 1, pc, I.getNumberOfUses() - 1); + + ((AstCallGraph.AstCGNode) n).setLexicallyMutatedIR(ir); + + return getBuilder().getPointerKeyForLocal(n, values[i]); } } - - // make new lexical use - int values[] = L.getExposedUses(pc); - Pair names[] = L.getExposedNames(); - if (names != null && names.length > 0) { - for (int i = 0; i < names.length; i++) { - if (name.equals(names[i].fst) && isEqual(definer, names[i].snd)) { - if (values[i] == -1) - return null; - - I.addLexicalUse(new Access(name, definer, values[i])); - - if (SSAConversion.DEBUG_UNDO) - System.err.println(("copy use #" + (-i - 1) + " to use #" + (I.getNumberOfUses() - 1) + " at inst " + pc)); - - SSAConversion.copyUse(ir, pc, -i - 1, pc, I.getNumberOfUses() - 1); - - ((AstCallGraph.AstCGNode) n).setLexicallyMutatedIR(ir); - - return getBuilder().getPointerKeyForLocal(n, values[i]); - } - } - } - - return null; - - } else { - return null; - } - } - - private PointerKey getLocalWriteKey(CGNode n, CallSiteReference callSite, String name, String definer, CGNode definingNode) { - IMethod M = n.getMethod(); - if (n == getBuilder().getCallGraph().getFakeRootNode()) { - return handleRootLexicalReference(name, definer, definingNode); } - else if (M instanceof AstMethod) { - AstMethod AstM = (AstMethod) M; - AstIR ir = (AstIR) n.getIR(); - LexicalInformation L = ir.lexicalInfo(); + return null; - // some people have no lexical uses at all - if (L == null) - return null; + } - int pc = callSite.getProgramCounter(); - AbstractLexicalInvoke I = (AbstractLexicalInvoke) ir.getInstructions()[pc]; + private PointerKey getLocalWriteKey(CGNode n, CallSiteReference callSite, String name, String definer) { + AstMethod AstM = (AstMethod) n.getMethod();; + AstIR ir = (AstIR) n.getIR(); + LexicalInformation L = ir.lexicalInfo(); - // find existing explicit lexical def - for (int i = 2; i < I.getNumberOfDefs(); i++) { - Access A = I.getLexicalDef(i); - if (A.variableName.equals(name) && isEqual(A.variableDefiner, definer)) { - return getBuilder().getPointerKeyForLocal(n, A.valueNumber); - } + int pc = callSite.getProgramCounter(); + AbstractLexicalInvoke I = (AbstractLexicalInvoke) ir.getInstructions()[pc]; + + // find existing explicit lexical def + for (int i = 2; i < I.getNumberOfDefs(); i++) { + Access A = I.getLexicalDef(i); + if (A.variableName.equals(name) && isEqual(A.variableDefiner, definer)) { + return getBuilder().getPointerKeyForLocal(n, A.valueNumber); } + } - // make new lexical def - int values[] = L.getExposedUses(pc); - Pair names[] = L.getExposedNames(); - if (names != null && names.length > 0) { - for (int i = 0; i < names.length; i++) { - if (name.equals(names[i].fst) && isEqual(definer, names[i].snd)) { - if (values[i] == -1) - return null; + // make new lexical def + int values[] = L.getExposedUses(pc); + Pair names[] = L.getExposedNames(); + if (names != null && names.length > 0) { + for (int i = 0; i < names.length; i++) { + if (name.equals(names[i].fst) && isEqual(definer, names[i].snd)) { + 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); - } + // 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); + // 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]; + // 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; - } + // 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); - - // new def has broken SSA form for values[i], so fix for that - // value - MutableIntSet vs = IntSetUtil.make(); - vs.add(values[i]); - SSAConversion.convert(AstM, ir, getOptions().getSSAOptions()); - - // 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()); - getBuilder().markChanged(n); - - // get SSA-renamed def from call site instruction - return getLocalWriteKey(n, callSite, name, definer, definingNode); + 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); + + // new def has broken SSA form for values[i], so fix for that value + MutableIntSet vs = IntSetUtil.make(); + vs.add(values[i]); + SSAConversion.convert(AstM, ir, getOptions().getSSAOptions()); + + // 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(AstM, n.getContext()); + getBuilder().markChanged(n); + + // get SSA-renamed def from call site instruction + return getLocalWriteKey(n, callSite, name, definer); } } - - return null; - } else { - return null; } + + return null; } // ///////////////////////////////////////////////////////////////////////// @@ -1074,74 +1029,10 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa system.recordImplicitPointsToSet(fieldKey); InstanceKey[] fieldsKeys = getInvariantContents(symtab, du, opNode, fieldsVn); - for (int o = 0; o < objKeys.length; o++) { - PointerKey objCatalog = getPointerKeyForObjectCatalog(objKeys[o]); - for (int f = 0; f < fieldsKeys.length; f++) { - if (isLoadOperation) { - for (Iterator keys = getPointerKeysForReflectedFieldRead(objKeys[o], fieldsKeys[f]); keys.hasNext();) { - AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next(); - if (DEBUG_PROPERTIES) - action.dump(key, true, true); - action.action(key); - } - } else { - if (objCatalog != null) { - system.newConstraint(objCatalog, fieldsKeys[f]); - } - for (Iterator keys = getPointerKeysForReflectedFieldWrite(objKeys[o], fieldsKeys[f]); keys.hasNext();) { - AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next(); - if (DEBUG_PROPERTIES) - action.dump(key, true, true); - action.action(key); - } - } - } - } + newFieldOperationObjectAndFieldConstant(isLoadOperation, action, objKeys, fieldsKeys); } else { - if (!isLoadOperation) { - for (int o = 0; o < objKeys.length; o++) { - PointerKey objCatalog = getPointerKeyForObjectCatalog(objKeys[o]); - if (objCatalog != null) { - system.newConstraint(objCatalog, assignOperator, fieldKey); - } - } - } - - system.newSideEffect(new UnaryOperator() { - public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) { - final IntSetVariable fields = (IntSetVariable) rhs; - if (fields.getValue() != null) { - fields.getValue().foreach(new IntSetAction() { - public void act(int fptr) { - InstanceKey field = system.getInstanceKey(fptr); - for (int o = 0; o < objKeys.length; o++) { - for (Iterator keys = isLoadOperation ? getPointerKeysForReflectedFieldRead(objKeys[o], field) - : getPointerKeysForReflectedFieldWrite(objKeys[o], field); keys.hasNext();) { - AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next(); - if (DEBUG_PROPERTIES) - action.dump(key, false, true); - action.action(key); - } - } - } - }); - } - return NOT_CHANGED; - } - - public int hashCode() { - return System.identityHashCode(this); - } - - public boolean equals(Object o) { - return o == this; - } - - public String toString() { - return "field op" + objVn + ", " + fieldsVn; - } - }, fieldKey); + newFieldOperationOnlyObjectConstant(isLoadOperation, action, fieldKey, objKeys); } } else { @@ -1149,101 +1040,10 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa system.recordImplicitPointsToSet(fieldKey); final InstanceKey[] fieldsKeys = getInvariantContents(symtab, du, opNode, fieldsVn); - system.newSideEffect(new UnaryOperator() { - public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) { - final IntSetVariable objects = (IntSetVariable) rhs; - if (objects.getValue() != null) { - objects.getValue().foreach(new IntSetAction() { - public void act(int optr) { - InstanceKey object = system.getInstanceKey(optr); - PointerKey objCatalog = getPointerKeyForObjectCatalog(object); - for (int f = 0; f < fieldsKeys.length; f++) { - if (isLoadOperation) { - for (Iterator keys = getPointerKeysForReflectedFieldRead(object, fieldsKeys[f]); keys.hasNext();) { - AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next(); - if (DEBUG_PROPERTIES) - action.dump(key, true, false); - action.action(key); - } - } else { - if (objCatalog != null) { - system.newConstraint(objCatalog, fieldsKeys[f]); - } - for (Iterator keys = getPointerKeysForReflectedFieldWrite(object, fieldsKeys[f]); keys.hasNext();) { - AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next(); - if (DEBUG_PROPERTIES) - action.dump(key, true, false); - action.action(key); - } - } - } - } - }); - } - return NOT_CHANGED; - } - - public int hashCode() { - return System.identityHashCode(this); - } - - public boolean equals(Object o) { - return o == this; - } - - public String toString() { - return "field op" + objVn + ", " + fieldsVn; - } - }, objKey); + newFieldOperationOnlyFieldConstant(isLoadOperation, action, objKey, fieldsKeys); } else { - system.newSideEffect(new AbstractOperator() { - 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) { - receivers.getValue().foreach(new IntSetAction() { - public void act(int rptr) { - final InstanceKey receiver = system.getInstanceKey(rptr); - - if (!isLoadOperation) { - PointerKey cat = getPointerKeyForObjectCatalog(receiver); - if (cat != null) { - system.newConstraint(cat, assignOperator, fieldKey); - } - } - - fields.getValue().foreach(new IntSetAction() { - public void act(int fptr) { - InstanceKey field = system.getInstanceKey(fptr); - for (Iterator keys = isLoadOperation ? getPointerKeysForReflectedFieldRead(receiver, field) - : getPointerKeysForReflectedFieldWrite(receiver, field); keys.hasNext();) { - AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next(); - if (DEBUG_PROPERTIES) - action.dump(key, false, false); - action.action(key); - } - } - }); - } - }); - } - - return NOT_CHANGED; - } - - public String toString() { - return "field op"; - } - - public boolean equals(Object o) { - return o == this; - } - - public int hashCode() { - return System.identityHashCode(this); - } - }, objKey, fieldKey); + newFieldFullOperation(isLoadOperation, action, objKey, fieldKey); } } @@ -1251,6 +1051,210 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa System.err.println("finished\n"); } } + + protected void newFieldOperationFieldConstant(CGNode opNode, + final boolean isLoadOperation, + final ReflectedFieldAction action, + final int objVn, + final InstanceKey[] fieldsKeys) + { + IR ir = getBuilder().getCFAContextInterpreter().getIR(opNode); + SymbolTable symtab = ir.getSymbolTable(); + DefUse du = getBuilder().getCFAContextInterpreter().getDU(opNode); + PointerKey objKey = getBuilder().getPointerKeyForLocal(opNode, objVn); + + if (contentsAreInvariant(symtab, du, objVn)) { + system.recordImplicitPointsToSet(objKey); + InstanceKey[] objectKeys = getInvariantContents(symtab, du, opNode, objVn); + + newFieldOperationObjectAndFieldConstant(isLoadOperation, action, objectKeys, fieldsKeys); + + } else { + newFieldOperationOnlyFieldConstant(isLoadOperation, action, objKey, fieldsKeys); + } + + } + + private void newFieldFullOperation(final boolean isLoadOperation, final ReflectedFieldAction action, PointerKey objKey, + final PointerKey fieldKey) { + system.newSideEffect(new AbstractOperator() { + 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) { + receivers.getValue().foreach(new IntSetAction() { + public void act(int rptr) { + final InstanceKey receiver = system.getInstanceKey(rptr); + + if (!isLoadOperation) { + PointerKey cat = getPointerKeyForObjectCatalog(receiver); + if (cat != null) { + system.newConstraint(cat, assignOperator, fieldKey); + } + } + + fields.getValue().foreach(new IntSetAction() { + public void act(int fptr) { + InstanceKey field = system.getInstanceKey(fptr); + for (Iterator keys = isLoadOperation ? getPointerKeysForReflectedFieldRead(receiver, field) + : getPointerKeysForReflectedFieldWrite(receiver, field); keys.hasNext();) { + AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next(); + if (DEBUG_PROPERTIES) + action.dump(key, false, false); + action.action(key); + } + } + }); + } + }); + } + + return NOT_CHANGED; + } + + public String toString() { + return "field op"; + } + + public boolean equals(Object o) { + return o == this; + } + + public int hashCode() { + return System.identityHashCode(this); + } + }, objKey, fieldKey); + } + + private 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) { + final IntSetVariable objects = (IntSetVariable) rhs; + if (objects.getValue() != null) { + objects.getValue().foreach(new IntSetAction() { + public void act(int optr) { + InstanceKey object = system.getInstanceKey(optr); + PointerKey objCatalog = getPointerKeyForObjectCatalog(object); + for (int f = 0; f < fieldsKeys.length; f++) { + if (isLoadOperation) { + for (Iterator keys = getPointerKeysForReflectedFieldRead(object, fieldsKeys[f]); keys.hasNext();) { + AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next(); + if (DEBUG_PROPERTIES) + action.dump(key, true, false); + action.action(key); + } + } else { + if (objCatalog != null) { + system.newConstraint(objCatalog, fieldsKeys[f]); + } + for (Iterator keys = getPointerKeysForReflectedFieldWrite(object, fieldsKeys[f]); keys.hasNext();) { + AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next(); + if (DEBUG_PROPERTIES) + action.dump(key, true, false); + action.action(key); + } + } + } + } + }); + } + return NOT_CHANGED; + } + + public int hashCode() { + return System.identityHashCode(this); + } + + public boolean equals(Object o) { + return o == this; + } + + public String toString() { + return "field op" + objKey; + } + }, objKey); + } + + private void newFieldOperationOnlyObjectConstant(final boolean isLoadOperation, + final ReflectedFieldAction action, + final PointerKey fieldKey, + final InstanceKey[] objKeys) + { + if (!isLoadOperation) { + for (int o = 0; o < objKeys.length; o++) { + PointerKey objCatalog = getPointerKeyForObjectCatalog(objKeys[o]); + if (objCatalog != null) { + system.newConstraint(objCatalog, assignOperator, fieldKey); + } + } + } + + system.newSideEffect(new UnaryOperator() { + public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) { + final IntSetVariable fields = (IntSetVariable) rhs; + if (fields.getValue() != null) { + fields.getValue().foreach(new IntSetAction() { + public void act(int fptr) { + InstanceKey field = system.getInstanceKey(fptr); + for (int o = 0; o < objKeys.length; o++) { + for (Iterator keys = isLoadOperation ? getPointerKeysForReflectedFieldRead(objKeys[o], field) + : getPointerKeysForReflectedFieldWrite(objKeys[o], field); keys.hasNext();) { + AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next(); + if (DEBUG_PROPERTIES) + action.dump(key, false, true); + action.action(key); + } + } + } + }); + } + return NOT_CHANGED; + } + + public int hashCode() { + return System.identityHashCode(this); + } + + public boolean equals(Object o) { + return o == this; + } + + public String toString() { + return "field op" + fieldKey; + } + }, fieldKey); + } + + private 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]); + for (int f = 0; f < fieldsKeys.length; f++) { + if (isLoadOperation) { + for (Iterator keys = getPointerKeysForReflectedFieldRead(objKeys[o], fieldsKeys[f]); keys.hasNext();) { + AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next(); + if (DEBUG_PROPERTIES) + action.dump(key, true, true); + action.action(key); + } + } else { + if (objCatalog != null) { + system.newConstraint(objCatalog, fieldsKeys[f]); + } + for (Iterator keys = getPointerKeysForReflectedFieldWrite(objKeys[o], fieldsKeys[f]); keys.hasNext();) { + AbstractFieldPointerKey key = (AbstractFieldPointerKey) keys.next(); + if (DEBUG_PROPERTIES) + action.dump(key, true, true); + action.action(key); + } + } + } + } + } public void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, int rhsVn) { IR ir = getBuilder().getCFAContextInterpreter().getIR(opNode); @@ -1265,46 +1269,61 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa } } - public void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, final InstanceKey[] rhsFixedValues) { - try { + private final class ConstantWriter implements ReflectedFieldAction { + private final InstanceKey[] rhsFixedValues; + + private ConstantWriter(InstanceKey[] rhsFixedValues) { + this.rhsFixedValues = rhsFixedValues; + } - newFieldOperation(opNode, objVn, fieldsVn, false, new ReflectedFieldAction() { - public void dump(AbstractFieldPointerKey fieldKey, boolean constObj, boolean constProp) { - System.err.println(("writing fixed rvals to " + fieldKey + " " + constObj + ", " + constProp)); - for (int i = 0; i < rhsFixedValues.length; i++) { - System.err.println(("writing " + rhsFixedValues[i])); - } + public void dump(AbstractFieldPointerKey fieldKey, boolean constObj, boolean constProp) { + System.err.println(("writing fixed rvals to " + fieldKey + " " + constObj + ", " + constProp)); + for (int i = 0; i < rhsFixedValues.length; i++) { + System.err.println(("writing " + rhsFixedValues[i])); + } + } + + public void action(AbstractFieldPointerKey fieldKey) { + if (!representsNullType(fieldKey.getInstanceKey())) { + for (int i = 0; i < rhsFixedValues.length; i++) { + system.findOrCreateIndexForInstanceKey(rhsFixedValues[i]); + system.newConstraint(fieldKey, rhsFixedValues[i]); } - - public void action(AbstractFieldPointerKey fieldKey) { - if (!representsNullType(fieldKey.getInstanceKey())) { - for (int i = 0; i < rhsFixedValues.length; i++) { - system.findOrCreateIndexForInstanceKey(rhsFixedValues[i]); - system.newConstraint(fieldKey, rhsFixedValues[i]); - } - } - } - }); - - } catch (RuntimeException e) { - System.err.println("error: " + e); - System.err.println(getBuilder().getCFAContextInterpreter().getIR(opNode)); - throw e; + } } } + + public void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, final InstanceKey[] rhsFixedValues) { + newFieldOperation(opNode, objVn, fieldsVn, false, new ConstantWriter(rhsFixedValues)); + } + public void newFieldWrite(CGNode opNode, int objVn, InstanceKey[] fieldKeys, final InstanceKey[] rhsValues) { + newFieldOperationFieldConstant(opNode, false, new ConstantWriter(rhsValues), objVn, fieldKeys); + } + + private final class NormalWriter implements ReflectedFieldAction { + private final PointerKey rhs; + + private NormalWriter(PointerKey rhs) { + this.rhs = rhs; + } + public void dump(AbstractFieldPointerKey fieldKey, boolean constObj, boolean constProp) { + System.err.println(("write " + rhs + " to " + fieldKey + " " + constObj + ", " + constProp)); + } + + public void action(AbstractFieldPointerKey fieldKey) { + if (!representsNullType(fieldKey.getInstanceKey())) { + system.newConstraint(fieldKey, assignOperator, 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)); - } + newFieldOperation(opNode, objVn, fieldsVn, false, new NormalWriter(rhs)); + } - public void action(AbstractFieldPointerKey fieldKey) { - if (!representsNullType(fieldKey.getInstanceKey())) { - system.newConstraint(fieldKey, assignOperator, rhs); - } - } - }); + public void newFieldWrite(CGNode opNode, int objVn, InstanceKey[] fieldKeys, final PointerKey rhs) { + newFieldOperationFieldConstant(opNode, false, new NormalWriter(rhs), objVn, fieldKeys); } protected void newFieldRead(CGNode opNode, int objVn, int fieldsVn, int lhsVn) { diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/LexicalScopingResolverContexts.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/LexicalScopingResolverContexts.java new file mode 100644 index 000000000..96d3930ac --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/LexicalScopingResolverContexts.java @@ -0,0 +1,220 @@ +package com.ibm.wala.cast.ipa.callgraph; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; + +import com.ibm.wala.cast.ir.ssa.AstLexicalAccess.Access; +import com.ibm.wala.cast.loader.AstMethod; +import com.ibm.wala.cast.loader.AstMethod.LexicalInformation; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.Context; +import com.ibm.wala.ipa.callgraph.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.ipa.callgraph.propagation.PropagationCallGraphBuilder; +import com.ibm.wala.util.collections.CompoundIterator; +import com.ibm.wala.util.collections.EmptyIterator; +import com.ibm.wala.util.collections.MapIterator; +import com.ibm.wala.util.collections.NonNullSingletonIterator; +import com.ibm.wala.util.collections.Pair; +import com.ibm.wala.util.functions.Function; +import com.ibm.wala.util.intset.IntSet; + +public final class LexicalScopingResolverContexts implements ContextSelector { + + public static final ContextKey RESOLVER = new ContextKey() { + public final String toString() { + return "Resolver Key"; + } + }; + + public static class Resolver extends HashMap, Object> implements ContextItem { + private final Map,CGNode> funargKeys = new HashMap,CGNode>(); + private final Resolver parent; + + private Resolver(Resolver parent) { + super(1); + this.parent = parent; + } + + private static Iterator> getLexicalSitesRec(final Object x) { + if (x == null) { + return null; + } else if (x instanceof CGNode) { + return new MapIterator>( + ((CGNode)x).iterateCallSites(), + new Function>() { + public Pair apply(CallSiteReference object) { + return Pair.make(object, (CGNode)x); + } + }); + + } else if (x instanceof Pair) { + return new NonNullSingletonIterator(x); + + } else { + Iterator> result = EmptyIterator.instance(); + Iterator c = ((Collection) x).iterator(); + while(c.hasNext()) { + result = new CompoundIterator>(result, getLexicalSitesRec(c.next())); + } + return result; + } + } + + private void add(Pair name, Pair site) { + if (! containsKey(name)) { + put(name, site); + } else { + Object x = get(name); + if (! x.equals(site)) { + if (x instanceof Collection) { + ((Collection)x).add(site); + } else { + Collection s = new HashSet(2); + s.add(x); + s.add(site); + put(name,s); + } + } + } + } + + public Iterator> getLexicalSites(Pair p) { + return getLexicalSitesRec(get(p)); + } + + public Iterator> getLexicalSites(Access a) { + return getLexicalSites(Pair.make(a.variableName, a.variableDefiner)); + } + + public void addFunarg(Pair var, CGNode target) { + funargKeys.put(var, target); + } + + public CGNode getFunarg(Pair var) { + return funargKeys.get(var); + } + } + + private class LexicalScopingResolverContext implements Context { + private final Resolver governingCallSites; + private final Context base; + + public int hashCode() { + return governingCallSites==null? 1077651: governingCallSites.keySet().hashCode(); + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } else if (getClass().equals(o.getClass())) { + LexicalScopingResolverContext c = (LexicalScopingResolverContext)o; + return (base==null? c.base==null: base.equals(c.base)) + && + (governingCallSites.equals(c.governingCallSites)); + } else { + return false; + } + } + + public ContextItem get(ContextKey name) { + return name.equals(RESOLVER)? governingCallSites: base!=null? base.get(name): null; + } + + private LexicalScopingResolverContext(Resolver governingCallSites, Context base) { + this.base = base; + this.governingCallSites = governingCallSites; + } + + private LexicalScopingResolverContext(CGNode source, CallSiteReference callSite, Context base) { + Context srcContext = source.getContext(); + Resolver srcResolver = (Resolver) srcContext.get(RESOLVER); + + this.base = base; + this.governingCallSites = new Resolver(srcResolver); + + if (source.getMethod() instanceof AstMethod) { + LexicalInformation LI = ((AstMethod)source.getMethod()).lexicalInfo(); + int[] exposedUses = LI.getExposedUses(callSite.getProgramCounter()); + int[] exposedExitUses = LI.getExitExposedUses(); + if (exposedUses.length > 0) { + Pair exposedNames[] = LI.getExposedNames(); + for(int i = 0; i < exposedUses.length; i++) { + if (exposedUses[i] != -1) { + governingCallSites.add(exposedNames[i], Pair.make(callSite, source)); + } + if (exposedExitUses[i] != -1) { + governingCallSites.addFunarg(exposedNames[i], source); + } + } + } + } + + if (srcResolver != null) { + for(Pair x : srcResolver.keySet()) { + Iterator> sites = srcResolver.getLexicalSites(x); + while (sites.hasNext()) { + governingCallSites.add(x, sites.next()); + } + } + } + } + } + + private final ContextSelector base; + + private final PropagationCallGraphBuilder builder; + + public LexicalScopingResolverContexts(PropagationCallGraphBuilder builder, ContextSelector base) { + this.base = base; + this.builder = builder; + } + + private Context checkForRecursion(IMethod target, Resolver srcResolver) { + while (srcResolver != null) { + for(CGNode n : builder.getCallGraph().getNodes(target.getReference())) { + if (n.getContext().get(RESOLVER) == srcResolver) { + return n.getContext(); + } + } + srcResolver = srcResolver.parent; + } + return null; + } + + public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] actualParameters) { + Context baseContext = base.getCalleeTarget(caller, site, callee, actualParameters); + Resolver resolver = (Resolver)caller.getContext().get(RESOLVER); + + Context recursiveParent = checkForRecursion(callee, resolver); + if (recursiveParent != null) { + return recursiveParent; + } + + if (caller.getMethod() instanceof AstMethod + && + ((AstMethod)caller.getMethod()).lexicalInfo().getExposedUses(site.getProgramCounter()).length > 0) + { + return new LexicalScopingResolverContext(caller, site, baseContext); + } + + else if (resolver != null) { + return new LexicalScopingResolverContext(resolver, baseContext); + } + + else { + return baseContext; + } + } + + public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) { + return base.getRelevantParameters(caller, site); + } +} \ No newline at end of file diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/LexicalScopingSSAContextInterpreter.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/LexicalScopingSSAContextInterpreter.java index b5d7c1478..6167309f7 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/LexicalScopingSSAContextInterpreter.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/LexicalScopingSSAContextInterpreter.java @@ -34,7 +34,7 @@ public class LexicalScopingSSAContextInterpreter extends AstContextInsensitiveSS } } - return getAnalysisCache().getSSACache().findOrCreateIR(node.getMethod(), node.getContext(), options.getSSAOptions()); + return super.getIR(node); } public DefUse getDU(CGNode node) { @@ -45,7 +45,7 @@ public class LexicalScopingSSAContextInterpreter extends AstContextInsensitiveSS } } - return getAnalysisCache().getSSACache().findOrCreateDU(node.getMethod(), node.getContext(), options.getSSAOptions()); + return super.getDU(node); } } 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 ab735497d..91533465b 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 @@ -10,10 +10,9 @@ *****************************************************************************/ package com.ibm.wala.cast.ipa.callgraph; -import java.util.HashMap; import java.util.Iterator; -import com.ibm.wala.cast.ir.translator.AstTranslator; +import com.ibm.wala.cast.ipa.callgraph.LexicalScopingResolverContexts.Resolver; import com.ibm.wala.cast.loader.AstMethod.LexicalParent; import com.ibm.wala.classLoader.IClass; import com.ibm.wala.classLoader.NewSiteReference; @@ -21,11 +20,14 @@ import com.ibm.wala.classLoader.ProgramCounter; import com.ibm.wala.ipa.callgraph.CGNode; import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; import com.ibm.wala.ipa.callgraph.propagation.InstanceKeyFactory; +import com.ibm.wala.ipa.callgraph.propagation.PointerKey; import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder; import com.ibm.wala.types.TypeReference; -import com.ibm.wala.util.collections.HashMapFactory; -import com.ibm.wala.util.graph.impl.GraphInverter; -import com.ibm.wala.util.graph.traverse.DFS; +import com.ibm.wala.util.collections.CompoundIterator; +import com.ibm.wala.util.collections.EmptyIterator; +import com.ibm.wala.util.collections.NonNullSingletonIterator; +import com.ibm.wala.util.collections.Pair; +import com.ibm.wala.util.intset.OrdinalSet; /** * An {@link InstanceKeyFactory} that returns {@link ScopeMappingInstanceKey}s @@ -33,12 +35,6 @@ import com.ibm.wala.util.graph.traverse.DFS; */ abstract public class ScopeMappingInstanceKeys implements InstanceKeyFactory { - /** - * return all {@link LexicalParent}s of methods represented by base (a single - * method for JavaScript, all instance methods in Java). - */ - protected abstract LexicalParent[] getParents(InstanceKey base); - /** * does base require a scope mapping key? Typically, true if base is allocated * in a nested lexical scope @@ -76,47 +72,16 @@ abstract public class ScopeMappingInstanceKeys implements InstanceKeyFactory { */ private final CGNode creator; - /** - * mapping from lexical parent names to the corresponding CGNodes - */ - private final HashMap scopeMap; /** * compute the {@link CGNode} correspond to each specified * {@link LexicalParent} of {@link #base}, populating {@link #scopeMap} * */ - private void computeLexicalParentCGNodes() { - if (AstTranslator.DEBUG_LEXICAL) - System.err.println(("starting search for parents at " + creator)); - final LexicalParent[] parents = getParents(base); - Iterator preds = DFS.iterateDiscoverTime(GraphInverter.invert(builder.getCallGraph()), creator); - int toDo = parents.length; - 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 (scopeMap.containsKey(parents[i].getName())) - assert scopeMap.get(parents[i].getName()) == pred; - else { - toDo--; - scopeMap.put(parents[i].getName(), pred); - if (AstTranslator.DEBUG_LEXICAL) - System.err.println(("Adding lexical parent " + parents[i].getName() + " for " + base + " at " + creator - + "(toDo is now " + toDo + ")")); - } - } - } - } - } - } - + private ScopeMappingInstanceKey(CGNode creator, InstanceKey base) { this.creator = creator; this.base = base; - this.scopeMap = HashMapFactory.make(); - computeLexicalParentCGNodes(); } public IClass getConcreteType() { @@ -128,8 +93,26 @@ abstract public class ScopeMappingInstanceKeys implements InstanceKeyFactory { * @param definer * @return */ - CGNode getDefiningNode(String definer) { - return scopeMap.get(definer); + Iterator getFunargNodes(Pair name) { + Iterator result = EmptyIterator.instance(); + + Resolver r = (Resolver)creator.getContext().get(LexicalScopingResolverContexts.RESOLVER); + if (r != null) { + CGNode def = r.getFunarg(name); + if (def != null) { + result = new NonNullSingletonIterator(def); + } + } + + PointerKey funcKey = builder.getPointerKeyForLocal(creator, 1); + OrdinalSet funcPtrs = builder.getPointerAnalysis().getPointsToSet(funcKey); + for(InstanceKey x : funcPtrs) { + if (x instanceof ScopeMappingInstanceKey) { + result = new CompoundIterator(result, ((ScopeMappingInstanceKey)x).getFunargNodes(name)); + } + } + + return result; } public int hashCode() { @@ -146,10 +129,10 @@ abstract public class ScopeMappingInstanceKeys implements InstanceKeyFactory { } } - public InstanceKey getInstanceKeyForAllocation(CGNode node, NewSiteReference allocation) { - InstanceKey base = basic.getInstanceKeyForAllocation(node, allocation); + public InstanceKey getInstanceKeyForAllocation(CGNode creatorNode, NewSiteReference allocationSite) { + InstanceKey base = basic.getInstanceKeyForAllocation(creatorNode, allocationSite); if (base != null && needsScopeMappingKey(base)) { - return new ScopeMappingInstanceKey(node, base); + return new ScopeMappingInstanceKey(creatorNode, base); } else { return base; } diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/SSAConversion.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/SSAConversion.java index 3394d1520..d0aa5d5d5 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/SSAConversion.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/SSAConversion.java @@ -461,9 +461,13 @@ public class SSAConversion extends AbstractSSAConversion { int[] exitLive = lexicalInfo.getExitExposedUses(); BitVector v = new BitVector(); - if (exitLive != null) - for (int i = 0; i < exitLive.length; i++) - v.set(exitLive[i]); + if (exitLive != null) { + for (int i = 0; i < exitLive.length; i++) { + if (exitLive[i] > -1) { + v.set(exitLive[i]); + } + } + } this.liveness = LiveAnalysis.perform(CFG, symtab, v); if (DEBUG) { @@ -514,7 +518,7 @@ public class SSAConversion extends AbstractSSAConversion { int[] exitLives = lexicalInfo.getExitExposedUses(); if (exitLives != null) { for (int i = 0; i < exitLives.length; i++) { - if (!skip(exitLives[i])) { + if (exitLives[i] != -1 && !skip(exitLives[i])) { assert !S[exitLives[i]].isEmpty(); exitLives[i] = top(exitLives[i]); } 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 34d78815e..bd4f91f26 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 @@ -2245,11 +2245,15 @@ public abstract class AstTranslator extends CAstVisitor implements ArrayOpHandle } } - private int[] buildLexicalUseArray(Pair, Integer>[] exposedNames) { + private int[] buildLexicalUseArray(Pair, Integer>[] exposedNames, String entityName) { if (exposedNames != null) { int[] lexicalUses = new int[exposedNames.length]; for (int j = 0; j < exposedNames.length; j++) { - lexicalUses[j] = exposedNames[j].snd; + if (entityName == null || entityName.equals(exposedNames[j].fst.snd)) { + lexicalUses[j] = exposedNames[j].snd; + } else { + lexicalUses[j] = -1; + } } return lexicalUses; @@ -2273,7 +2277,7 @@ public abstract class AstTranslator extends CAstVisitor implements ArrayOpHandle } @SuppressWarnings("unchecked") - AstLexicalInformation(Scope scope, SSAInstruction[] instrs, Set, Integer>> exposedNamesSet, + AstLexicalInformation(String entityName, Scope scope, SSAInstruction[] instrs, Set, Integer>> exposedNamesSet, Set accesses) { Pair, Integer>[] EN = null; if (exposedNamesSet != null) { @@ -2285,12 +2289,12 @@ public abstract class AstTranslator extends CAstVisitor implements ArrayOpHandle // the value numbers stored in exitLexicalUses and instructionLexicalUses // are identical at first; they will be updated // as needed during the final SSA conversion - this.exitLexicalUses = buildLexicalUseArray(EN); + this.exitLexicalUses = buildLexicalUseArray(EN, entityName); this.instructionLexicalUses = new int[instrs.length][]; for (int i = 0; i < instrs.length; i++) { if (instrs[i] instanceof SSAAbstractInvokeInstruction) { - this.instructionLexicalUses[i] = buildLexicalUseArray(EN); + this.instructionLexicalUses[i] = buildLexicalUseArray(EN, null); } } @@ -2330,8 +2334,10 @@ public abstract class AstTranslator extends CAstVisitor implements ArrayOpHandle return exitLexicalUses; } + private static final int[] NONE = new int[0]; + public int[] getExposedUses(int instructionOffset) { - return instructionLexicalUses[instructionOffset]; + return instructionLexicalUses[instructionOffset]==null? NONE: instructionLexicalUses[instructionOffset]; } public IntSet getAllExposedUses() { @@ -2339,7 +2345,9 @@ public abstract class AstTranslator extends CAstVisitor implements ArrayOpHandle allExposedUses = IntSetUtil.make(); if (exitLexicalUses != null) { for (int i = 0; i < exitLexicalUses.length; i++) { - allExposedUses.add(exitLexicalUses[i]); + if (exitLexicalUses[i] > 0) { + allExposedUses.add(exitLexicalUses[i]); + } } } if (instructionLexicalUses != null) { @@ -2765,7 +2773,7 @@ public abstract class AstTranslator extends CAstVisitor implements ArrayOpHandle // (put here to allow subclasses to handle stuff in scoped entities) // assemble lexical information patchLexicalAccesses(cfg.getInstructions(), accesses.get(n)); - AstLexicalInformation LI = new AstLexicalInformation((AbstractScope) functionContext.currentScope(), cfg.getInstructions(), + AstLexicalInformation LI = new AstLexicalInformation(getEntityName(n), (AbstractScope) functionContext.currentScope(), cfg.getInstructions(), exposedNames.get(n), accesses.get(n)); DebuggingInformation DBG = new AstDebuggingInformation(n.getPosition(), line, nms); diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstMethod.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstMethod.java index 56c68a0ad..016a32dbc 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstMethod.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstMethod.java @@ -48,7 +48,7 @@ public abstract class AstMethod implements IMethod { public IntSet getAllExposedUses(); - public Pair[] getExposedNames(); + public Pair[] getExposedNames(); public String[] getScopingParents(); @@ -141,7 +141,7 @@ public abstract class AstMethod implements IMethod { * methods containing state possibly referenced lexically in this * method */ - public abstract class LexicalParent { + public static abstract class LexicalParent { public abstract String getName(); public abstract AstMethod getMethod();