add application-only call graph

This commit is contained in:
Manu Sridharan 2017-04-17 14:54:06 -07:00
parent 8c65754b0e
commit 589db13fa7
1 changed files with 40 additions and 22 deletions

View File

@ -54,9 +54,16 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
private final IClassHierarchy cha; private final IClassHierarchy cha;
private final AnalysisOptions options; private final AnalysisOptions options;
private final IAnalysisCacheView cache; private final IAnalysisCacheView cache;
/**
* if set to true, do not include call graph edges in classes outside
* the application class loader. This means callbacks from library
* to application will be ignored.
*/
private final boolean applicationOnly;
private boolean isInitialized = false; private boolean isInitialized = false;
private class CHANode extends NodeImpl { private class CHANode extends NodeImpl {
protected CHANode(IMethod method, Context C) { protected CHANode(IMethod method, Context C) {
@ -97,13 +104,18 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
public boolean addTarget(CallSiteReference reference, CGNode target) { public boolean addTarget(CallSiteReference reference, CGNode target) {
return false; return false;
} }
} }
public CHACallGraph(IClassHierarchy cha) { public CHACallGraph(IClassHierarchy cha) {
this(cha, false);
}
public CHACallGraph(IClassHierarchy cha, boolean applicationOnly) {
this.cha = cha; this.cha = cha;
this.options = new AnalysisOptions(); this.options = new AnalysisOptions();
this.cache = new AnalysisCacheImpl(); this.cache = new AnalysisCacheImpl();
this.applicationOnly = applicationOnly;
setInterpreter(new ContextInsensitiveCHAContextInterpreter()); setInterpreter(new ContextInsensitiveCHAContextInterpreter());
} }
@ -120,7 +132,7 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
closure(); closure();
isInitialized = true; isInitialized = true;
} }
@Override @Override
public IClassHierarchy getClassHierarchy() { public IClassHierarchy getClassHierarchy() {
return cha; return cha;
@ -138,7 +150,7 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
} }
} }
} }
@Override @Override
public Set<CGNode> getPossibleTargets(CGNode node, CallSiteReference site) { public Set<CGNode> getPossibleTargets(CGNode node, CallSiteReference site) {
return Iterator2Collection.toSet( return Iterator2Collection.toSet(
@ -147,7 +159,7 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
getPossibleTargets(site), getPossibleTargets(site),
new Predicate<IMethod>() { new Predicate<IMethod>() {
@Override public boolean test(IMethod o) { @Override public boolean test(IMethod o) {
return !o.isAbstract(); return isRelevantMethod(o);
} }
} }
), ),
@ -161,7 +173,7 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
return null; return null;
} }
} }
})); }));
} }
@Override @Override
@ -171,7 +183,7 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
@Override @Override
public Iterator<CallSiteReference> getPossibleSites(final CGNode src, final CGNode target) { public Iterator<CallSiteReference> getPossibleSites(final CGNode src, final CGNode target) {
return return
new FilterIterator<CallSiteReference>(getInterpreter(src).iterateCallSites(src), new FilterIterator<CallSiteReference>(getInterpreter(src).iterateCallSites(src),
new Predicate<CallSiteReference>() { new Predicate<CallSiteReference>() {
@Override public boolean test(CallSiteReference o) { @Override public boolean test(CallSiteReference o) {
@ -179,10 +191,10 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
} }
}); });
} }
private class CHARootNode extends CHANode { private class CHARootNode extends CHANode {
private final Set<CallSiteReference> calls = HashSetFactory.make(); private final Set<CallSiteReference> calls = HashSetFactory.make();
protected CHARootNode(IMethod method, Context C) { protected CHARootNode(IMethod method, Context C) {
super(method, C); super(method, C);
} }
@ -197,7 +209,7 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
return calls.add(reference); return calls.add(reference);
} }
} }
@Override @Override
protected CGNode makeFakeRootNode() throws CancelException { protected CGNode makeFakeRootNode() throws CancelException {
return new CHARootNode(new FakeRootMethod(cha, options, cache), Everywhere.EVERYWHERE); return new CHARootNode(new FakeRootMethod(cha, options, cache), Everywhere.EVERYWHERE);
@ -207,23 +219,23 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
protected CGNode makeFakeWorldClinitNode() throws CancelException { protected CGNode makeFakeWorldClinitNode() throws CancelException {
return new CHARootNode(new FakeWorldClinitMethod(cha, options, cache), Everywhere.EVERYWHERE); return new CHARootNode(new FakeWorldClinitMethod(cha, options, cache), Everywhere.EVERYWHERE);
} }
private int clinitPC = 0; private int clinitPC = 0;
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public CGNode findOrCreateNode(IMethod method, Context C) throws CancelException { public CGNode findOrCreateNode(IMethod method, Context C) throws CancelException {
assert C.equals(Everywhere.EVERYWHERE); assert C.equals(Everywhere.EVERYWHERE);
assert !method.isAbstract(); assert !method.isAbstract();
CGNode n = getNode(method, C); CGNode n = getNode(method, C);
if (n == null) { if (n == null) {
assert !isInitialized; assert !isInitialized;
n = makeNewNode(method, C); n = makeNewNode(method, C);
IMethod clinit = method.getDeclaringClass().getClassInitializer(); IMethod clinit = method.getDeclaringClass().getClassInitializer();
if (clinit != null && getNode(clinit, Everywhere.EVERYWHERE) == null) { if (clinit != null && getNode(clinit, Everywhere.EVERYWHERE) == null) {
CGNode cln = makeNewNode(clinit, Everywhere.EVERYWHERE); CGNode cln = makeNewNode(clinit, Everywhere.EVERYWHERE);
CGNode clinits = getFakeWorldClinitNode(); CGNode clinits = getFakeWorldClinitNode();
clinits.addTarget(CallSiteReference.make(clinitPC++, clinit.getReference(), IInvokeInstruction.Dispatch.STATIC), cln); clinits.addTarget(CallSiteReference.make(clinitPC++, clinit.getReference(), IInvokeInstruction.Dispatch.STATIC), cln);
} }
@ -232,7 +244,7 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
} }
private Stack<CGNode> newNodes = new Stack<CGNode>(); private Stack<CGNode> newNodes = new Stack<CGNode>();
private void closure() throws CancelException { private void closure() throws CancelException {
while (! newNodes.isEmpty()) { while (! newNodes.isEmpty()) {
CGNode n = newNodes.pop(); CGNode n = newNodes.pop();
@ -240,7 +252,7 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
Iterator<IMethod> methods = getPossibleTargets(sites.next()); Iterator<IMethod> methods = getPossibleTargets(sites.next());
while (methods.hasNext()) { while (methods.hasNext()) {
IMethod target = methods.next(); IMethod target = methods.next();
if (!target.isAbstract()) { if (isRelevantMethod(target)) {
CGNode callee = getNode(target, Everywhere.EVERYWHERE); CGNode callee = getNode(target, Everywhere.EVERYWHERE);
if (callee == null) { if (callee == null) {
callee = findOrCreateNode(target, Everywhere.EVERYWHERE); callee = findOrCreateNode(target, Everywhere.EVERYWHERE);
@ -254,6 +266,12 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
} }
} }
private boolean isRelevantMethod(IMethod target) {
return !target.isAbstract()
&& (!applicationOnly
|| cha.getScope().isApplicationLoader(target.getDeclaringClass().getClassLoader()));
}
private CGNode makeNewNode(IMethod method, Context C) throws CancelException { private CGNode makeNewNode(IMethod method, Context C) throws CancelException {
CGNode n; CGNode n;
Key k = new Key(method, C); Key k = new Key(method, C);
@ -267,7 +285,7 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
protected NumberedEdgeManager<CGNode> getEdgeManager() { protected NumberedEdgeManager<CGNode> getEdgeManager() {
return new NumberedEdgeManager<CGNode>() { return new NumberedEdgeManager<CGNode>() {
private final Map<CGNode, SoftReference<Set<CGNode>>> predecessors = HashMapFactory.make(); private final Map<CGNode, SoftReference<Set<CGNode>>> predecessors = HashMapFactory.make();
private Set<CGNode> getPreds(CGNode n) { private Set<CGNode> getPreds(CGNode n) {
if (predecessors.containsKey(n) && predecessors.get(n).get() != null) { if (predecessors.containsKey(n) && predecessors.get(n).get() != null) {
return predecessors.get(n).get(); return predecessors.get(n).get();
@ -282,7 +300,7 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
return preds; return preds;
} }
} }
@Override @Override
public Iterator<CGNode> getPredNodes(CGNode n) { public Iterator<CGNode> getPredNodes(CGNode n) {
return getPreds(n).iterator(); return getPreds(n).iterator();
@ -366,7 +384,7 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
} }
return result; return result;
} }
}; };
} }