diff --git a/com.ibm.wala.cast.js.rhino.test/harness-src/com/ibm/wala/cast/js/test/TestTransitiveLexicalAccessesRhino.java b/com.ibm.wala.cast.js.rhino.test/harness-src/com/ibm/wala/cast/js/test/TestTransitiveLexicalAccessesRhino.java new file mode 100644 index 000000000..2a48726a7 --- /dev/null +++ b/com.ibm.wala.cast.js.rhino.test/harness-src/com/ibm/wala/cast/js/test/TestTransitiveLexicalAccessesRhino.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2008 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.test; + +import org.junit.Before; + +import com.ibm.wala.cast.js.translator.CAstRhinoTranslatorFactory; + +public class TestTransitiveLexicalAccessesRhino extends TestTransitiveLexicalAccesses { + + @Before + public void setUp() { + com.ibm.wala.cast.js.ipa.callgraph.JSCallGraphUtil.setTranslatorFactory(new CAstRhinoTranslatorFactory()); + } + + +} diff --git a/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestTransitiveLexicalAccesses.java b/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestTransitiveLexicalAccesses.java new file mode 100644 index 000000000..17b9a1c26 --- /dev/null +++ b/com.ibm.wala.cast.js.test/harness-src/com/ibm/wala/cast/js/test/TestTransitiveLexicalAccesses.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2008 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.test; + +import java.io.IOException; +import java.util.Map; + +import junit.framework.Assert; + +import org.junit.Test; + +import com.ibm.wala.cast.ipa.lexical.TransitiveLexicalAccesses; +import com.ibm.wala.cast.js.ipa.callgraph.JSCFABuilder; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.collections.Pair; +import com.ibm.wala.util.intset.OrdinalSet; + +public abstract class TestTransitiveLexicalAccesses { + + @Test + public void testSimpleLexical() throws IOException, IllegalArgumentException, CancelException { + JSCFABuilder b = JSCallGraphBuilderUtil.makeScriptCGBuilder("tests", "simple-lexical.js"); + CallGraph CG = b.makeCallGraph(b.getOptions()); + TransitiveLexicalAccesses lexAccesses = TransitiveLexicalAccesses.make(CG, b.getPointerAnalysis()); + Map>> result = lexAccesses.computeLexVarsRead(); + for (CGNode n : result.keySet()) { + if (n.toString().contains("Node: ")) { + // function "inner" reads exactly x and z + OrdinalSet> readVars = result.get(n); + Assert.assertEquals(2, readVars.size()); + Assert.assertEquals("[[Node: Context: Everywhere,x], [Node: Context: Everywhere,z]]", readVars.toString()); + } + if (n.toString().contains("Node: ")) { + // function "inner3" reads exactly innerName, inner3, and x and z via callees + OrdinalSet> readVars = result.get(n); + Assert.assertEquals(4, readVars.size()); + Assert.assertEquals("[[Node: Context: Everywhere,inner3], [Node: Context: Everywhere,innerName], [Node: Context: Everywhere,x], [Node: Context: Everywhere,z]]", readVars.toString()); + } + } + } + +} diff --git a/com.ibm.wala.cast/META-INF/MANIFEST.MF b/com.ibm.wala.cast/META-INF/MANIFEST.MF index 6872888ce..8456cb5c1 100644 --- a/com.ibm.wala.cast/META-INF/MANIFEST.MF +++ b/com.ibm.wala.cast/META-INF/MANIFEST.MF @@ -12,6 +12,7 @@ Bundle-ActivationPolicy: lazy Export-Package: com.ibm.wala.cast.analysis.typeInference, com.ibm.wala.cast.ipa.callgraph, com.ibm.wala.cast.ipa.cha, + com.ibm.wala.cast.ipa.lexical, com.ibm.wala.cast.ipa.modref, com.ibm.wala.cast.ir.cfg, com.ibm.wala.cast.ir.ssa, 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 759321849..d35ab274e 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 @@ -92,7 +92,7 @@ abstract public class ScopeMappingInstanceKeys implements InstanceKeyFactory { * @param definer * @return */ - Iterator getFunargNodes(Pair name) { + public Iterator getFunargNodes(Pair name) { if (AstTranslator.NEW_LEXICAL) { Collection constructorCallers = getConstructorCallers(this, name); assert constructorCallers != null && !constructorCallers.isEmpty() : "no callers for constructor"; diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/lexical/TransitiveLexicalAccesses.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/lexical/TransitiveLexicalAccesses.java new file mode 100644 index 000000000..c064c9cda --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/lexical/TransitiveLexicalAccesses.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2008 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.ipa.lexical; + +import java.util.Collection; +import java.util.Map; + +import com.ibm.wala.cast.ipa.callgraph.ScopeMappingInstanceKeys.ScopeMappingInstanceKey; +import com.ibm.wala.cast.ir.ssa.AstLexicalAccess.Access; +import com.ibm.wala.cast.ir.ssa.AstLexicalRead; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.CallGraphTransitiveClosure; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; +import com.ibm.wala.ipa.modref.ModRef; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.collections.Iterator2Iterable; +import com.ibm.wala.util.collections.Pair; +import com.ibm.wala.util.functions.Function; +import com.ibm.wala.util.intset.OrdinalSet; + +/** + * Given a call graph / pointer analysis, determines the lexical variables + * accessed by each call graph node and its transitive callees. Essentially, a + * mod-ref analysis limited to lexical variables. + * + * TODO Share even more code with {@link ModRef}? + * + */ +public class TransitiveLexicalAccesses { + + public static TransitiveLexicalAccesses make(CallGraph cg, PointerAnalysis pa) { + return new TransitiveLexicalAccesses(cg, pa); + } + + + + private final CallGraph cg; + + private final PointerAnalysis pa; + + + + protected TransitiveLexicalAccesses(CallGraph cg, PointerAnalysis pa) { + this.cg = cg; + this.pa = pa; + } + + public Map>> computeLexVarsRead() { + Map>> scan = scanForLexReads(); + return CallGraphTransitiveClosure.transitiveClosure(cg, scan); + } + + private Map>> scanForLexReads() { + return CallGraphTransitiveClosure.collectNodeResults(cg, new Function>>() { + + public Collection> apply(CGNode n) { + return scanNodeForLexReads(n); + } + }); + } + + protected Collection> scanNodeForLexReads(CGNode n) { + Collection> result = HashSetFactory.make(); + IR ir = n.getIR(); + if (ir != null) { + for (SSAInstruction instr: Iterator2Iterable.make(ir.iterateNormalInstructions())) { + if (instr instanceof AstLexicalRead) { + AstLexicalRead read = (AstLexicalRead) instr; + for (Access a : read.getAccesses()) { + Pair nameAndDefiner = a.getName(); + result.addAll(getNodeNamePairsForAccess(n, nameAndDefiner)); + } + } + } + } + return result; + } + + private Collection> getNodeNamePairsForAccess(CGNode n, Pair nameAndDefiner) { + Collection> result = HashSetFactory.make(); + // use scope-mapping instance keys in pointer analysis. may need a different + // scheme for CG construction not based on pointer analysis + OrdinalSet functionValues = pa.getPointsToSet(pa.getHeapModel().getPointerKeyForLocal(n, 1)); + for (InstanceKey ik : functionValues) { + if (ik instanceof ScopeMappingInstanceKey) { + ScopeMappingInstanceKey smik = (ScopeMappingInstanceKey) ik; + for (CGNode definerNode : Iterator2Iterable.make(smik.getFunargNodes(nameAndDefiner))) { + result.add(Pair.make(definerNode,nameAndDefiner.fst)); + } + } + } + return result; + } +}