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:
parent
8ed998a249
commit
26e7eb50ba
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue