work on CHA
This commit is contained in:
parent
c9e1b2e587
commit
321e925660
|
@ -49,11 +49,11 @@
|
||||||
<target name="getSources" depends="fetchJLex" />
|
<target name="getSources" depends="fetchJLex" />
|
||||||
|
|
||||||
<target name="testdatadir" depends="init,testdata.exists" unless="testdatadir.present">
|
<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>
|
||||||
|
|
||||||
<target name="testdata.exists" depends="init">
|
<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"
|
type="dir"
|
||||||
property="testdatadir.present"/>
|
property="testdatadir.present"/>
|
||||||
</target>
|
</target>
|
||||||
|
@ -65,7 +65,7 @@
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="jar" depends="compile,testdatadir">
|
<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>
|
||||||
|
|
||||||
<target name="init" depends="properties">
|
<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 {
|
public class AstJavaTypeInference extends AstTypeInference {
|
||||||
|
|
||||||
protected final IClass stringClass;
|
protected IClass stringClass;
|
||||||
|
|
||||||
protected class AstJavaTypeOperatorFactory extends AstTypeOperatorFactory implements AstJavaInstructionVisitor {
|
protected class AstJavaTypeOperatorFactory extends AstTypeOperatorFactory implements AstJavaInstructionVisitor {
|
||||||
public void visitBinaryOp(SSABinaryOpInstruction instruction) {
|
public void visitBinaryOp(SSABinaryOpInstruction instruction) {
|
||||||
|
@ -96,7 +96,13 @@ public class AstJavaTypeInference extends AstTypeInference {
|
||||||
|
|
||||||
public AstJavaTypeInference(IR ir, IClassHierarchy cha, boolean doPrimitives) {
|
public AstJavaTypeInference(IR ir, IClassHierarchy cha, boolean doPrimitives) {
|
||||||
super(ir, cha, JavaPrimitiveType.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() {
|
protected void initialize() {
|
||||||
|
@ -125,12 +131,12 @@ public class AstJavaTypeInference extends AstTypeInference {
|
||||||
TypeVariable r = (TypeVariable) rhs[i];
|
TypeVariable r = (TypeVariable) rhs[i];
|
||||||
TypeAbstraction ta = r.getType();
|
TypeAbstraction ta = r.getType();
|
||||||
if (ta instanceof PointType) {
|
if (ta instanceof PointType) {
|
||||||
if (ta.getType().equals(stringClass)) {
|
if (ta.getType().equals(getStringClass())) {
|
||||||
meet = new PointType(ta.getType());
|
meet = new PointType(ta.getType());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (ta instanceof ConeType) {
|
} else if (ta instanceof ConeType) {
|
||||||
if (ta.getType().equals(stringClass)) {
|
if (ta.getType().equals(getStringClass())) {
|
||||||
meet = new PointType(ta.getType());
|
meet = new PointType(ta.getType());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,7 +135,7 @@ public class CrossLanguageClassHierarchy implements IClassHierarchy {
|
||||||
return getHierarchy(c).getNumber(c);
|
return getHierarchy(c).getNumber(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<IMethod> getPossibleTargets(MethodReference ref) {
|
public Set<IMethod> getPossibleTargets(MethodReference ref) {
|
||||||
return getHierarchy(ref).getPossibleTargets(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.demandpa.util,
|
||||||
com.ibm.wala.escape,
|
com.ibm.wala.escape,
|
||||||
com.ibm.wala.ipa.callgraph,
|
com.ibm.wala.ipa.callgraph,
|
||||||
|
com.ibm.wala.ipa.callgraph.cha,
|
||||||
com.ibm.wala.ipa.callgraph.impl,
|
com.ibm.wala.ipa.callgraph.impl,
|
||||||
com.ibm.wala.ipa.callgraph.propagation,
|
com.ibm.wala.ipa.callgraph.propagation,
|
||||||
com.ibm.wala.ipa.callgraph.propagation.cfa,
|
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.CallGraph;
|
||||||
import com.ibm.wala.ipa.callgraph.Context;
|
import com.ibm.wala.ipa.callgraph.Context;
|
||||||
import com.ibm.wala.ipa.callgraph.propagation.ReceiverInstanceContext;
|
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.ipa.cha.IClassHierarchy;
|
||||||
import com.ibm.wala.shrikeBT.IInvokeInstruction;
|
import com.ibm.wala.shrikeBT.IInvokeInstruction;
|
||||||
import com.ibm.wala.types.MethodReference;
|
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.
|
* 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;
|
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
|
* An object that handles context interpreter functions
|
||||||
*/
|
*/
|
||||||
private SSAContextInterpreter interpreter;
|
private T interpreter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set of nodes that are entrypoints for this analysis
|
* 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.
|
* 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() {
|
public BasicCallGraph() {
|
||||||
super();
|
super();
|
||||||
|
@ -303,7 +302,7 @@ public abstract class BasicCallGraph extends AbstractNumberedGraph<CGNode> imple
|
||||||
* @param node a call graph node we want information about
|
* @param node a call graph node we want information about
|
||||||
* @return an object that knows how to interpret information about the node
|
* @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) {
|
if (interpreter == null) {
|
||||||
throw new IllegalStateException("must register an interpreter for this call graph");
|
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;
|
return getNode(N.getMethod(), N.getContext()) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setInterpreter(SSAContextInterpreter interpreter) {
|
public void setInterpreter(T interpreter) {
|
||||||
this.interpreter = 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.AnalysisOptions;
|
||||||
import com.ibm.wala.ipa.callgraph.CGNode;
|
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||||
import com.ibm.wala.ipa.callgraph.Context;
|
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.ipa.cha.IClassHierarchy;
|
||||||
import com.ibm.wala.shrikeBT.BytecodeConstants;
|
import com.ibm.wala.shrikeBT.BytecodeConstants;
|
||||||
import com.ibm.wala.ssa.DefUse;
|
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.
|
* 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;
|
protected final IClassHierarchy cha;
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ import com.ibm.wala.classLoader.IClass;
|
||||||
import com.ibm.wala.classLoader.NewSiteReference;
|
import com.ibm.wala.classLoader.NewSiteReference;
|
||||||
import com.ibm.wala.ipa.callgraph.AnalysisCache;
|
import com.ibm.wala.ipa.callgraph.AnalysisCache;
|
||||||
import com.ibm.wala.ipa.callgraph.CGNode;
|
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.ipa.callgraph.propagation.SSAContextInterpreter;
|
||||||
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
||||||
import com.ibm.wala.types.FieldReference;
|
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
|
* 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;
|
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) {
|
public Iterator<FieldReference> iterateFieldsRead(CGNode node) {
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
throw new IllegalArgumentException("node is 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) {
|
public boolean recordFactoryType(CGNode node, IClass klass) {
|
||||||
// not a factory type
|
// not a factory type
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -12,31 +12,22 @@ package com.ibm.wala.ipa.callgraph.propagation.rta;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
import com.ibm.wala.classLoader.CallSiteReference;
|
|
||||||
import com.ibm.wala.classLoader.IClass;
|
import com.ibm.wala.classLoader.IClass;
|
||||||
import com.ibm.wala.classLoader.NewSiteReference;
|
import com.ibm.wala.classLoader.NewSiteReference;
|
||||||
import com.ibm.wala.ipa.callgraph.CGNode;
|
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||||
|
import com.ibm.wala.ipa.callgraph.cha.CHAContextInterpreter;
|
||||||
import com.ibm.wala.types.FieldReference;
|
import com.ibm.wala.types.FieldReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This object will analyze a method in a context and return information needed for RTA.
|
* This object will analyze a method in a context and return information needed for RTA.
|
||||||
*/
|
*/
|
||||||
public interface RTAContextInterpreter {
|
public interface RTAContextInterpreter extends 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 types that may be allocated by a given method in a given context.
|
* @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);
|
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
|
* @return iterator of FieldReference
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -389,7 +389,7 @@ public class ClassHierarchy implements IClassHierarchy {
|
||||||
* @return the set of IMethods that this call can resolve to.
|
* @return the set of IMethods that this call can resolve to.
|
||||||
* @throws IllegalArgumentException if ref is null
|
* @throws IllegalArgumentException if ref is null
|
||||||
*/
|
*/
|
||||||
public Collection<IMethod> getPossibleTargets(MethodReference ref) {
|
public Set<IMethod> getPossibleTargets(MethodReference ref) {
|
||||||
if (ref == null) {
|
if (ref == null) {
|
||||||
throw new IllegalArgumentException("ref is 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.
|
* @return the set of IMethods that this call can resolve to.
|
||||||
* @throws IllegalArgumentException if ref is null
|
* @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
|
* 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;bundle-version="1.0.0",
|
||||||
com.ibm.wala.cast.js.rhino;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",
|
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",
|
org.eclipse.equinox.common;bundle-version="3.6.100",
|
||||||
com.ibm.wala.ide.tests;bundle-version="1.1.3",
|
com.ibm.wala.ide.tests;bundle-version="1.1.3",
|
||||||
org.eclipse.core.runtime;bundle-version="3.8.0"
|
org.eclipse.core.runtime;bundle-version="3.8.0"
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
|
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
|
||||||
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
|
<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.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.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.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"/>
|
<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);
|
IPath path = new Path("testdata").append(filename);
|
||||||
|
|
||||||
URL url = FileLocator.find(bundle, path, null);
|
URL url = FileLocator.find(bundle, path, null);
|
||||||
assert url != null;
|
assert url != null : bundle.toString() + " path " + path.toString();
|
||||||
try {
|
try {
|
||||||
URL fileURL = FileLocator.toFileURL(url);
|
URL fileURL = FileLocator.toFileURL(url);
|
||||||
File file = new File(fileURL.getPath());
|
File file = new File(fileURL.getPath());
|
||||||
|
|
|
@ -31,7 +31,7 @@ public abstract class ComposedIterator<O,I> implements Iterator<I> {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!inner.hasNext()) {
|
if (inner != null && !inner.hasNext()) {
|
||||||
inner = null;
|
inner = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue