Code to compute transitive lexical accesses of methods.

The TransitiveLexicalAccesses class computes the lexical variables
read by a CGNode and its transitive callees.  Also, a basic test case.
This commit is contained in:
Manu Sridharan 2013-01-03 15:58:07 -08:00
parent 8ed998a249
commit 26e7eb50ba
5 changed files with 185 additions and 1 deletions

View File

@ -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());
}
}

View File

@ -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<CGNode, OrdinalSet<Pair<CGNode, String>>> result = lexAccesses.computeLexVarsRead();
for (CGNode n : result.keySet()) {
if (n.toString().contains("Node: <Code body of function Ltests/simple-lexical.js/outer/inner>")) {
// function "inner" reads exactly x and z
OrdinalSet<Pair<CGNode, String>> readVars = result.get(n);
Assert.assertEquals(2, readVars.size());
Assert.assertEquals("[[Node: <Code body of function Ltests/simple-lexical.js/outer> Context: Everywhere,x], [Node: <Code body of function Ltests/simple-lexical.js/outer> Context: Everywhere,z]]", readVars.toString());
}
if (n.toString().contains("Node: <Code body of function Ltests/simple-lexical.js/outer/inner2>")) {
// function "inner3" reads exactly innerName, inner3, and x and z via callees
OrdinalSet<Pair<CGNode, String>> readVars = result.get(n);
Assert.assertEquals(4, readVars.size());
Assert.assertEquals("[[Node: <Code body of function Ltests/simple-lexical.js/outer> Context: Everywhere,inner3], [Node: <Code body of function Ltests/simple-lexical.js/outer> Context: Everywhere,innerName], [Node: <Code body of function Ltests/simple-lexical.js/outer> Context: Everywhere,x], [Node: <Code body of function Ltests/simple-lexical.js/outer> Context: Everywhere,z]]", readVars.toString());
}
}
}
}

View File

@ -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,

View File

@ -92,7 +92,7 @@ abstract public class ScopeMappingInstanceKeys implements InstanceKeyFactory {
* @param definer
* @return
*/
Iterator<CGNode> getFunargNodes(Pair<String, String> name) {
public Iterator<CGNode> getFunargNodes(Pair<String, String> name) {
if (AstTranslator.NEW_LEXICAL) {
Collection<CGNode> constructorCallers = getConstructorCallers(this, name);
assert constructorCallers != null && !constructorCallers.isEmpty() : "no callers for constructor";

View File

@ -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<CGNode, OrdinalSet<Pair<CGNode, String>>> computeLexVarsRead() {
Map<CGNode, Collection<Pair<CGNode, String>>> scan = scanForLexReads();
return CallGraphTransitiveClosure.transitiveClosure(cg, scan);
}
private Map<CGNode, Collection<Pair<CGNode, String>>> scanForLexReads() {
return CallGraphTransitiveClosure.collectNodeResults(cg, new Function<CGNode, Collection<Pair<CGNode,String>>>() {
public Collection<Pair<CGNode, String>> apply(CGNode n) {
return scanNodeForLexReads(n);
}
});
}
protected Collection<Pair<CGNode, String>> scanNodeForLexReads(CGNode n) {
Collection<Pair<CGNode, String>> 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<String, String> nameAndDefiner = a.getName();
result.addAll(getNodeNamePairsForAccess(n, nameAndDefiner));
}
}
}
}
return result;
}
private Collection<Pair<CGNode, String>> getNodeNamePairsForAccess(CGNode n, Pair<String, String> nameAndDefiner) {
Collection<Pair<CGNode, String>> 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<InstanceKey> 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;
}
}