work on CHA
This commit is contained in:
parent
c9e1b2e587
commit
321e925660
|
@ -49,11 +49,11 @@
|
|||
<target name="getSources" depends="fetchJLex" />
|
||||
|
||||
<target name="testdatadir" depends="init,testdata.exists" unless="testdatadir.present">
|
||||
<mkdir dir="${basedir}/../com.ibm.wala.cast.java.test/testdata"/>
|
||||
<mkdir dir="${basedir}/../com.ibm.wala.ide.jdt.test/testdata"/>
|
||||
</target>
|
||||
|
||||
<target name="testdata.exists" depends="init">
|
||||
<available file="${basedir}/../com.ibm.wala.cast.java.test/testdata"
|
||||
<available file="${basedir}/../com.ibm.wala.ide.jdt.test/testdata"
|
||||
type="dir"
|
||||
property="testdatadir.present"/>
|
||||
</target>
|
||||
|
@ -65,7 +65,7 @@
|
|||
</target>
|
||||
|
||||
<target name="jar" depends="compile,testdatadir">
|
||||
<jar destfile="${basedir}/../com.ibm.wala.cast.java.test/testdata/test_project.zip" basedir="${basedir}"/>
|
||||
<jar destfile="${basedir}/../com.ibm.wala.ide.jdt.test/testdata/test_project.zip" basedir="${basedir}"/>
|
||||
</target>
|
||||
|
||||
<target name="init" depends="properties">
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package javaonepointfive;
|
||||
|
||||
public class TypeInferencePrimAndStringOp {
|
||||
public static void main(String[] args) {
|
||||
int a = 2;
|
||||
String result = "a" + a;
|
||||
}
|
||||
}
|
||||
|
|
@ -33,7 +33,7 @@ import com.ibm.wala.util.debug.Assertions;
|
|||
|
||||
public class AstJavaTypeInference extends AstTypeInference {
|
||||
|
||||
protected final IClass stringClass;
|
||||
protected IClass stringClass;
|
||||
|
||||
protected class AstJavaTypeOperatorFactory extends AstTypeOperatorFactory implements AstJavaInstructionVisitor {
|
||||
public void visitBinaryOp(SSABinaryOpInstruction instruction) {
|
||||
|
@ -96,7 +96,13 @@ public class AstJavaTypeInference extends AstTypeInference {
|
|||
|
||||
public AstJavaTypeInference(IR ir, IClassHierarchy cha, boolean doPrimitives) {
|
||||
super(ir, cha, JavaPrimitiveType.BOOLEAN, doPrimitives);
|
||||
this.stringClass = cha.lookupClass(TypeReference.JavaLangString);
|
||||
}
|
||||
|
||||
IClass getStringClass() {
|
||||
if (stringClass == null) {
|
||||
this.stringClass = cha.lookupClass(TypeReference.JavaLangString);
|
||||
}
|
||||
return stringClass;
|
||||
}
|
||||
|
||||
protected void initialize() {
|
||||
|
@ -125,12 +131,12 @@ public class AstJavaTypeInference extends AstTypeInference {
|
|||
TypeVariable r = (TypeVariable) rhs[i];
|
||||
TypeAbstraction ta = r.getType();
|
||||
if (ta instanceof PointType) {
|
||||
if (ta.getType().equals(stringClass)) {
|
||||
if (ta.getType().equals(getStringClass())) {
|
||||
meet = new PointType(ta.getType());
|
||||
break;
|
||||
}
|
||||
} else if (ta instanceof ConeType) {
|
||||
if (ta.getType().equals(stringClass)) {
|
||||
if (ta.getType().equals(getStringClass())) {
|
||||
meet = new PointType(ta.getType());
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -135,7 +135,7 @@ public class CrossLanguageClassHierarchy implements IClassHierarchy {
|
|||
return getHierarchy(c).getNumber(c);
|
||||
}
|
||||
|
||||
public Collection<IMethod> getPossibleTargets(MethodReference ref) {
|
||||
public Set<IMethod> getPossibleTargets(MethodReference ref) {
|
||||
return getHierarchy(ref).getPossibleTargets(ref);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package com.ibm.wala.core.tests.callGraph;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.ibm.wala.core.tests.util.TestConstants;
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisScope;
|
||||
import com.ibm.wala.ipa.callgraph.CallGraph;
|
||||
import com.ibm.wala.ipa.callgraph.Entrypoint;
|
||||
import com.ibm.wala.ipa.callgraph.cha.CHACallGraph;
|
||||
import com.ibm.wala.ipa.callgraph.impl.AllApplicationEntrypoints;
|
||||
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||
import com.ibm.wala.ipa.cha.ClassHierarchyException;
|
||||
import com.ibm.wala.util.CancelException;
|
||||
|
||||
public class CHACallGraphTest {
|
||||
@Test public void testJava_cup() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException {
|
||||
testCHA(TestConstants.JAVA_CUP, TestConstants.JAVA_CUP_MAIN);
|
||||
}
|
||||
|
||||
public static CallGraph testCHA(String scopeFile, String mainClass) throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException {
|
||||
AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(scopeFile, CallGraphTestUtil.REGRESSION_EXCLUSIONS);
|
||||
ClassHierarchy cha = ClassHierarchy.make(scope);
|
||||
Iterable<Entrypoint> entrypoints;
|
||||
if (mainClass == null) {
|
||||
entrypoints = new AllApplicationEntrypoints(scope, cha);
|
||||
} else {
|
||||
entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, mainClass);
|
||||
}
|
||||
|
||||
CHACallGraph CG = new CHACallGraph(cha);
|
||||
CG.init(entrypoints);
|
||||
|
||||
return CG;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException {
|
||||
testCHA(args[0], args.length>1? args[1]: null);
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ Export-Package: .,
|
|||
com.ibm.wala.demandpa.util,
|
||||
com.ibm.wala.escape,
|
||||
com.ibm.wala.ipa.callgraph,
|
||||
com.ibm.wala.ipa.callgraph.cha,
|
||||
com.ibm.wala.ipa.callgraph.impl,
|
||||
com.ibm.wala.ipa.callgraph.propagation,
|
||||
com.ibm.wala.ipa.callgraph.propagation.cfa,
|
||||
|
|
|
@ -0,0 +1,345 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 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.ipa.callgraph.cha;
|
||||
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.ibm.wala.classLoader.CallSiteReference;
|
||||
import com.ibm.wala.classLoader.IMethod;
|
||||
import com.ibm.wala.classLoader.NewSiteReference;
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisCache;
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
|
||||
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||
import com.ibm.wala.ipa.callgraph.Context;
|
||||
import com.ibm.wala.ipa.callgraph.Entrypoint;
|
||||
import com.ibm.wala.ipa.callgraph.impl.BasicCallGraph;
|
||||
import com.ibm.wala.ipa.callgraph.impl.Everywhere;
|
||||
import com.ibm.wala.ipa.callgraph.impl.FakeRootMethod;
|
||||
import com.ibm.wala.ipa.callgraph.impl.FakeWorldClinitMethod;
|
||||
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
||||
import com.ibm.wala.shrikeBT.IInvokeInstruction;
|
||||
import com.ibm.wala.ssa.DefUse;
|
||||
import com.ibm.wala.ssa.IR;
|
||||
import com.ibm.wala.util.CancelException;
|
||||
import com.ibm.wala.util.collections.ComposedIterator;
|
||||
import com.ibm.wala.util.collections.EmptyIterator;
|
||||
import com.ibm.wala.util.collections.Filter;
|
||||
import com.ibm.wala.util.collections.FilterIterator;
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.collections.Iterator2Collection;
|
||||
import com.ibm.wala.util.collections.IteratorUtil;
|
||||
import com.ibm.wala.util.collections.MapIterator;
|
||||
import com.ibm.wala.util.collections.NonNullSingletonIterator;
|
||||
import com.ibm.wala.util.functions.Function;
|
||||
import com.ibm.wala.util.graph.NumberedEdgeManager;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
import com.ibm.wala.util.intset.IntSetUtil;
|
||||
import com.ibm.wala.util.intset.MutableIntSet;
|
||||
|
||||
public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
|
||||
private final IClassHierarchy cha;
|
||||
private final AnalysisOptions options;
|
||||
private final AnalysisCache cache;
|
||||
|
||||
private boolean isInitialized = false;
|
||||
|
||||
private class CHANode extends NodeImpl {
|
||||
|
||||
protected CHANode(IMethod method, Context C) {
|
||||
super(method, C);
|
||||
}
|
||||
|
||||
public IR getIR() {
|
||||
assert false;
|
||||
return null;
|
||||
}
|
||||
|
||||
public DefUse getDU() {
|
||||
assert false;
|
||||
return null;
|
||||
}
|
||||
|
||||
public Iterator<NewSiteReference> iterateNewSites() {
|
||||
assert false;
|
||||
return null;
|
||||
}
|
||||
|
||||
public Iterator<CallSiteReference> iterateCallSites() {
|
||||
return getInterpreter(this).iterateCallSites(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj.getClass()==getClass() && getMethod().equals(((CHANode)obj).getMethod());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getMethod().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addTarget(CallSiteReference reference, CGNode target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public CHACallGraph(IClassHierarchy cha) {
|
||||
this.cha = cha;
|
||||
this.options = new AnalysisOptions();
|
||||
this.cache = new AnalysisCache();
|
||||
setInterpreter(new ContextInsensitiveCHAContextInterpreter());
|
||||
}
|
||||
|
||||
public void init(Iterable<Entrypoint> entrypoints) throws CancelException {
|
||||
super.init();
|
||||
|
||||
CGNode root = getFakeRootNode();
|
||||
int programCounter = 0;
|
||||
for(Entrypoint e : entrypoints) {
|
||||
root.addTarget(e.makeSite(programCounter++), null);
|
||||
}
|
||||
closure(root, true);
|
||||
isInitialized = true;
|
||||
}
|
||||
|
||||
public IClassHierarchy getClassHierarchy() {
|
||||
return cha;
|
||||
}
|
||||
|
||||
private Iterator<IMethod> getPossibleTargets(CallSiteReference site) {
|
||||
if (site.isDispatch()) {
|
||||
return cha.getPossibleTargets(site.getDeclaredTarget()).iterator();
|
||||
} else {
|
||||
IMethod m = cha.resolveMethod(site.getDeclaredTarget());
|
||||
if (m != null) {
|
||||
return new NonNullSingletonIterator<IMethod>(m);
|
||||
} else {
|
||||
return EmptyIterator.instance();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Set<CGNode> getPossibleTargets(CGNode node, CallSiteReference site) {
|
||||
return Iterator2Collection.toSet(
|
||||
new MapIterator<IMethod,CGNode>(
|
||||
new FilterIterator<IMethod>(
|
||||
getPossibleTargets(site),
|
||||
new Filter<IMethod>() {
|
||||
public boolean accepts(IMethod o) {
|
||||
return !o.isAbstract();
|
||||
}
|
||||
}
|
||||
),
|
||||
new Function<IMethod,CGNode>() {
|
||||
public CGNode apply(IMethod object) {
|
||||
try {
|
||||
return findOrCreateNode(object, Everywhere.EVERYWHERE);
|
||||
} catch (CancelException e) {
|
||||
assert false : e.toString();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public int getNumberOfTargets(CGNode node, CallSiteReference site) {
|
||||
return IteratorUtil.count(getPossibleTargets(site));
|
||||
}
|
||||
|
||||
public Iterator<CallSiteReference> getPossibleSites(final CGNode src, final CGNode target) {
|
||||
return
|
||||
new FilterIterator<CallSiteReference>(getInterpreter(src).iterateCallSites(src),
|
||||
new Filter<CallSiteReference>() {
|
||||
public boolean accepts(CallSiteReference o) {
|
||||
return getPossibleTargets(src, o).contains(target);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private class CHARootNode extends CHANode {
|
||||
private final Set<CallSiteReference> calls = HashSetFactory.make();
|
||||
|
||||
protected CHARootNode(IMethod method, Context C) {
|
||||
super(method, C);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<CallSiteReference> iterateCallSites() {
|
||||
return calls.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addTarget(CallSiteReference reference, CGNode target) {
|
||||
return calls.add(reference);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CGNode makeFakeRootNode() throws CancelException {
|
||||
return new CHARootNode(new FakeRootMethod(cha, options, cache), Everywhere.EVERYWHERE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CGNode makeFakeWorldClinitNode() throws CancelException {
|
||||
return new CHARootNode(new FakeWorldClinitMethod(cha, options, cache), Everywhere.EVERYWHERE);
|
||||
}
|
||||
|
||||
private void closure(CGNode n, boolean fromRoot) throws CancelException {
|
||||
for(Iterator<CallSiteReference> sites = n.iterateCallSites(); sites.hasNext(); ) {
|
||||
Iterator<IMethod> methods = getPossibleTargets(sites.next());
|
||||
while (methods.hasNext()) {
|
||||
IMethod target = methods.next();
|
||||
if (!target.isAbstract()) {
|
||||
CGNode callee = getNode(target, Everywhere.EVERYWHERE);
|
||||
if (callee == null) {
|
||||
callee = findOrCreateNode(target, Everywhere.EVERYWHERE);
|
||||
if (fromRoot) {
|
||||
registerEntrypoint(callee);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int clinitPC = 0;
|
||||
|
||||
@Override
|
||||
public CGNode findOrCreateNode(IMethod method, Context C) throws CancelException {
|
||||
assert C.equals(Everywhere.EVERYWHERE);
|
||||
assert !method.isAbstract();
|
||||
|
||||
CGNode n = getNode(method, C);
|
||||
if (n == null) {
|
||||
assert !isInitialized;
|
||||
n = makeNewNode(method, C);
|
||||
|
||||
IMethod clinit = method.getDeclaringClass().getClassInitializer();
|
||||
if (clinit != null && getNode(clinit, Everywhere.EVERYWHERE) == null) {
|
||||
CGNode cln = makeNewNode(clinit, Everywhere.EVERYWHERE);
|
||||
CGNode clinits = getFakeWorldClinitNode();
|
||||
clinits.addTarget(CallSiteReference.make(clinitPC++, clinit.getReference(), IInvokeInstruction.Dispatch.STATIC), cln);
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
private CGNode makeNewNode(IMethod method, Context C) throws CancelException {
|
||||
CGNode n;
|
||||
Key k = new Key(method, C);
|
||||
n = new CHANode(method, C);
|
||||
registerNode(k, n);
|
||||
closure(n, false);
|
||||
return n;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NumberedEdgeManager<CGNode> getEdgeManager() {
|
||||
return new NumberedEdgeManager<CGNode>() {
|
||||
private final Map<CGNode, SoftReference<Set<CGNode>>> predecessors = HashMapFactory.make();
|
||||
|
||||
private Set<CGNode> getPreds(CGNode n) {
|
||||
if (predecessors.containsKey(n) && predecessors.get(n).get() != null) {
|
||||
return predecessors.get(n).get();
|
||||
} else {
|
||||
Set<CGNode> preds = HashSetFactory.make();
|
||||
for(CGNode node : CHACallGraph.this) {
|
||||
if (getPossibleSites(node, n).hasNext()) {
|
||||
preds.add(node);
|
||||
}
|
||||
}
|
||||
predecessors.put(n, new SoftReference<Set<CGNode>>(preds));
|
||||
return preds;
|
||||
}
|
||||
}
|
||||
|
||||
public Iterator<CGNode> getPredNodes(CGNode n) {
|
||||
return getPreds(n).iterator();
|
||||
}
|
||||
|
||||
public int getPredNodeCount(CGNode n) {
|
||||
return getPreds(n).size();
|
||||
}
|
||||
|
||||
public Iterator<CGNode> getSuccNodes(final CGNode n) {
|
||||
return new FilterIterator<CGNode>(new ComposedIterator<CallSiteReference, CGNode>(n.iterateCallSites()) {
|
||||
@Override
|
||||
public Iterator<? extends CGNode> makeInner(CallSiteReference outer) {
|
||||
return getPossibleTargets(n, outer).iterator();
|
||||
}
|
||||
},
|
||||
new Filter<CGNode>() {
|
||||
private final MutableIntSet nodes = IntSetUtil.make();
|
||||
public boolean accepts(CGNode o) {
|
||||
if (nodes.contains(o.getGraphNodeId())) {
|
||||
return false;
|
||||
} else {
|
||||
nodes.add(o.getGraphNodeId());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public int getSuccNodeCount(CGNode N) {
|
||||
return IteratorUtil.count(getSuccNodes(N));
|
||||
}
|
||||
|
||||
public void addEdge(CGNode src, CGNode dst) {
|
||||
assert false;
|
||||
}
|
||||
|
||||
public void removeEdge(CGNode src, CGNode dst) throws UnsupportedOperationException {
|
||||
assert false;
|
||||
}
|
||||
|
||||
public void removeAllIncidentEdges(CGNode node) throws UnsupportedOperationException {
|
||||
assert false;
|
||||
}
|
||||
|
||||
public void removeIncomingEdges(CGNode node) throws UnsupportedOperationException {
|
||||
assert false;
|
||||
}
|
||||
|
||||
public void removeOutgoingEdges(CGNode node) throws UnsupportedOperationException {
|
||||
assert false;
|
||||
}
|
||||
|
||||
public boolean hasEdge(CGNode src, CGNode dst) {
|
||||
return getPossibleSites(src, dst).hasNext();
|
||||
}
|
||||
|
||||
public IntSet getSuccNodeNumbers(CGNode node) {
|
||||
MutableIntSet result = IntSetUtil.make();
|
||||
for(Iterator<CGNode> ss = getSuccNodes(node); ss.hasNext(); ) {
|
||||
result.add(ss.next().getGraphNodeId());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public IntSet getPredNodeNumbers(CGNode node) {
|
||||
MutableIntSet result = IntSetUtil.make();
|
||||
for(Iterator<CGNode> ss = getPredNodes(node); ss.hasNext(); ) {
|
||||
result.add(ss.next().getGraphNodeId());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 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.ipa.callgraph.cha;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.classLoader.CallSiteReference;
|
||||
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||
|
||||
public interface CHAContextInterpreter {
|
||||
|
||||
/**
|
||||
* Does this object understand the given method? The caller had better check this before inquiring on other properties.
|
||||
*/
|
||||
public boolean understands(CGNode node);
|
||||
|
||||
/**
|
||||
* @return an Iterator of the call statements that may execute in a given method for a given context
|
||||
*/
|
||||
public abstract Iterator<CallSiteReference> iterateCallSites(CGNode node);
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 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.ipa.callgraph.cha;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.classLoader.CallSiteReference;
|
||||
import com.ibm.wala.classLoader.CodeScanner;
|
||||
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
||||
import com.ibm.wala.util.debug.Assertions;
|
||||
|
||||
public class ContextInsensitiveCHAContextInterpreter implements CHAContextInterpreter {
|
||||
|
||||
public boolean understands(CGNode node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public Iterator<CallSiteReference> iterateCallSites(CGNode node) {
|
||||
if (node == null) {
|
||||
throw new IllegalArgumentException("node is null");
|
||||
}
|
||||
try {
|
||||
return CodeScanner.getCallSites(node.getMethod()).iterator();
|
||||
} catch (InvalidClassFileException e) {
|
||||
e.printStackTrace();
|
||||
Assertions.UNREACHABLE();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -23,7 +23,6 @@ import com.ibm.wala.ipa.callgraph.CGNode;
|
|||
import com.ibm.wala.ipa.callgraph.CallGraph;
|
||||
import com.ibm.wala.ipa.callgraph.Context;
|
||||
import com.ibm.wala.ipa.callgraph.propagation.ReceiverInstanceContext;
|
||||
import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter;
|
||||
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
||||
import com.ibm.wala.shrikeBT.IInvokeInstruction;
|
||||
import com.ibm.wala.types.MethodReference;
|
||||
|
@ -42,7 +41,7 @@ import com.ibm.wala.util.graph.traverse.DFS;
|
|||
/**
|
||||
* Basic data structure support for a call graph.
|
||||
*/
|
||||
public abstract class BasicCallGraph extends AbstractNumberedGraph<CGNode> implements CallGraph {
|
||||
public abstract class BasicCallGraph<T> extends AbstractNumberedGraph<CGNode> implements CallGraph {
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
|
@ -61,7 +60,7 @@ public abstract class BasicCallGraph extends AbstractNumberedGraph<CGNode> imple
|
|||
/**
|
||||
* An object that handles context interpreter functions
|
||||
*/
|
||||
private SSAContextInterpreter interpreter;
|
||||
private T interpreter;
|
||||
|
||||
/**
|
||||
* Set of nodes that are entrypoints for this analysis
|
||||
|
@ -81,7 +80,7 @@ public abstract class BasicCallGraph extends AbstractNumberedGraph<CGNode> imple
|
|||
*
|
||||
* TODO: this is a bit redundant with the nodes Map. Restructure these data structures for space efficiency.
|
||||
*/
|
||||
final private Map<MethodReference, Set<CGNode>> mr2Nodes = HashMapFactory.make();
|
||||
protected final Map<MethodReference, Set<CGNode>> mr2Nodes = HashMapFactory.make();
|
||||
|
||||
public BasicCallGraph() {
|
||||
super();
|
||||
|
@ -303,7 +302,7 @@ public abstract class BasicCallGraph extends AbstractNumberedGraph<CGNode> imple
|
|||
* @param node a call graph node we want information about
|
||||
* @return an object that knows how to interpret information about the node
|
||||
*/
|
||||
protected SSAContextInterpreter getInterpreter(CGNode node) {
|
||||
protected T getInterpreter(CGNode node) {
|
||||
if (interpreter == null) {
|
||||
throw new IllegalStateException("must register an interpreter for this call graph");
|
||||
}
|
||||
|
@ -344,7 +343,7 @@ public abstract class BasicCallGraph extends AbstractNumberedGraph<CGNode> imple
|
|||
return getNode(N.getMethod(), N.getContext()) != null;
|
||||
}
|
||||
|
||||
public void setInterpreter(SSAContextInterpreter interpreter) {
|
||||
public void setInterpreter(T interpreter) {
|
||||
this.interpreter = interpreter;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import com.ibm.wala.ipa.callgraph.AnalysisCache;
|
|||
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
|
||||
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||
import com.ibm.wala.ipa.callgraph.Context;
|
||||
import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter;
|
||||
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
||||
import com.ibm.wala.shrikeBT.BytecodeConstants;
|
||||
import com.ibm.wala.ssa.DefUse;
|
||||
|
@ -50,7 +51,7 @@ import com.ibm.wala.util.intset.SparseIntSet;
|
|||
/**
|
||||
* A call graph which explicitly holds the target for each call site in each node.
|
||||
*/
|
||||
public class ExplicitCallGraph extends BasicCallGraph implements BytecodeConstants {
|
||||
public class ExplicitCallGraph extends BasicCallGraph<SSAContextInterpreter> implements BytecodeConstants {
|
||||
|
||||
protected final IClassHierarchy cha;
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import com.ibm.wala.classLoader.IClass;
|
|||
import com.ibm.wala.classLoader.NewSiteReference;
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisCache;
|
||||
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||
import com.ibm.wala.ipa.callgraph.cha.ContextInsensitiveCHAContextInterpreter;
|
||||
import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter;
|
||||
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
||||
import com.ibm.wala.types.FieldReference;
|
||||
|
@ -27,7 +28,7 @@ import com.ibm.wala.util.debug.Assertions;
|
|||
/**
|
||||
* Default implementation of MethodContextInterpreter for context-insensitive analysis
|
||||
*/
|
||||
public abstract class ContextInsensitiveRTAInterpreter implements RTAContextInterpreter, SSAContextInterpreter {
|
||||
public abstract class ContextInsensitiveRTAInterpreter extends ContextInsensitiveCHAContextInterpreter implements RTAContextInterpreter, SSAContextInterpreter {
|
||||
|
||||
private final AnalysisCache analysisCache;
|
||||
|
||||
|
@ -52,19 +53,6 @@ public abstract class ContextInsensitiveRTAInterpreter implements RTAContextInte
|
|||
}
|
||||
}
|
||||
|
||||
public Iterator<CallSiteReference> iterateCallSites(CGNode node) {
|
||||
if (node == null) {
|
||||
throw new IllegalArgumentException("node is null");
|
||||
}
|
||||
try {
|
||||
return CodeScanner.getCallSites(node.getMethod()).iterator();
|
||||
} catch (InvalidClassFileException e) {
|
||||
e.printStackTrace();
|
||||
Assertions.UNREACHABLE();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Iterator<FieldReference> iterateFieldsRead(CGNode node) {
|
||||
if (node == null) {
|
||||
throw new IllegalArgumentException("node is null");
|
||||
|
@ -91,10 +79,6 @@ public abstract class ContextInsensitiveRTAInterpreter implements RTAContextInte
|
|||
}
|
||||
}
|
||||
|
||||
public boolean understands(CGNode node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean recordFactoryType(CGNode node, IClass klass) {
|
||||
// not a factory type
|
||||
return false;
|
||||
|
|
|
@ -12,31 +12,22 @@ package com.ibm.wala.ipa.callgraph.propagation.rta;
|
|||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.ibm.wala.classLoader.CallSiteReference;
|
||||
import com.ibm.wala.classLoader.IClass;
|
||||
import com.ibm.wala.classLoader.NewSiteReference;
|
||||
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||
import com.ibm.wala.ipa.callgraph.cha.CHAContextInterpreter;
|
||||
import com.ibm.wala.types.FieldReference;
|
||||
|
||||
/**
|
||||
* This object will analyze a method in a context and return information needed for RTA.
|
||||
*/
|
||||
public interface RTAContextInterpreter {
|
||||
/**
|
||||
* Does this object understand the given method? The caller had better check this before inquiring on other properties.
|
||||
*/
|
||||
public boolean understands(CGNode node);
|
||||
public interface RTAContextInterpreter extends CHAContextInterpreter {
|
||||
|
||||
/**
|
||||
* @return an Iterator of the types that may be allocated by a given method in a given context.
|
||||
*/
|
||||
public abstract Iterator<NewSiteReference> iterateNewSites(CGNode node);
|
||||
|
||||
/**
|
||||
* @return an Iterator of the call statements that may execute in a given method for a given context
|
||||
*/
|
||||
public abstract Iterator<CallSiteReference> iterateCallSites(CGNode node);
|
||||
|
||||
/**
|
||||
* @return iterator of FieldReference
|
||||
*/
|
||||
|
|
|
@ -389,7 +389,7 @@ public class ClassHierarchy implements IClassHierarchy {
|
|||
* @return the set of IMethods that this call can resolve to.
|
||||
* @throws IllegalArgumentException if ref is null
|
||||
*/
|
||||
public Collection<IMethod> getPossibleTargets(MethodReference ref) {
|
||||
public Set<IMethod> getPossibleTargets(MethodReference ref) {
|
||||
if (ref == null) {
|
||||
throw new IllegalArgumentException("ref is null");
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ public interface IClassHierarchy extends Iterable<IClass> {
|
|||
* @return the set of IMethods that this call can resolve to.
|
||||
* @throws IllegalArgumentException if ref is null
|
||||
*/
|
||||
public Collection<IMethod> getPossibleTargets(MethodReference ref);
|
||||
public Set<IMethod> getPossibleTargets(MethodReference ref);
|
||||
|
||||
/**
|
||||
* Find the possible targets of a call to a method reference where the receiver is of a certain type
|
||||
|
|
|
@ -9,7 +9,7 @@ Require-Bundle: com.ibm.wala.core;bundle-version="1.1.3",
|
|||
com.ibm.wala.cast.js;bundle-version="1.0.0",
|
||||
com.ibm.wala.cast.js.rhino;bundle-version="1.0.0",
|
||||
com.ibm.wala.ide.jsdt;bundle-version="1.0.0",
|
||||
org.eclipse.wst.jsdt.core;bundle-version="1.1.202",
|
||||
org.eclipse.wst.jsdt.core,
|
||||
org.eclipse.equinox.common;bundle-version="3.6.100",
|
||||
com.ibm.wala.ide.tests;bundle-version="1.1.3",
|
||||
org.eclipse.core.runtime;bundle-version="3.8.0"
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
|
||||
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
|
||||
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.launching.macosx.MacOSXType/Oracle Java 1.7"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.launching.macosx.MacOSXType/JDK 1.6"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.ibm.wala.ide.jsdt.tests.JSProjectScopeTest"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.ibm.wala.ide.jsdt.tests"/>
|
||||
|
|
|
@ -114,7 +114,7 @@ public class EclipseTestUtil {
|
|||
IPath path = new Path("testdata").append(filename);
|
||||
|
||||
URL url = FileLocator.find(bundle, path, null);
|
||||
assert url != null;
|
||||
assert url != null : bundle.toString() + " path " + path.toString();
|
||||
try {
|
||||
URL fileURL = FileLocator.toFileURL(url);
|
||||
File file = new File(fileURL.getPath());
|
||||
|
|
|
@ -31,7 +31,7 @@ public abstract class ComposedIterator<O,I> implements Iterator<I> {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (!inner.hasNext()) {
|
||||
if (inner != null && !inner.hasNext()) {
|
||||
inner = null;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue