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 AnalysisOptions options;
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 class CHANode extends NodeImpl {
protected CHANode(IMethod method, Context C) {
@ -97,13 +104,18 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
public boolean addTarget(CallSiteReference reference, CGNode target) {
return false;
}
}
public CHACallGraph(IClassHierarchy cha) {
this(cha, false);
}
public CHACallGraph(IClassHierarchy cha, boolean applicationOnly) {
this.cha = cha;
this.options = new AnalysisOptions();
this.cache = new AnalysisCacheImpl();
this.applicationOnly = applicationOnly;
setInterpreter(new ContextInsensitiveCHAContextInterpreter());
}
@ -120,7 +132,7 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
closure();
isInitialized = true;
}
@Override
public IClassHierarchy getClassHierarchy() {
return cha;
@ -138,7 +150,7 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
}
}
}
@Override
public Set<CGNode> getPossibleTargets(CGNode node, CallSiteReference site) {
return Iterator2Collection.toSet(
@ -147,7 +159,7 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
getPossibleTargets(site),
new Predicate<IMethod>() {
@Override public boolean test(IMethod o) {
return !o.isAbstract();
return isRelevantMethod(o);
}
}
),
@ -161,7 +173,7 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
return null;
}
}
}));
}));
}
@Override
@ -171,7 +183,7 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
@Override
public Iterator<CallSiteReference> getPossibleSites(final CGNode src, final CGNode target) {
return
return
new FilterIterator<CallSiteReference>(getInterpreter(src).iterateCallSites(src),
new Predicate<CallSiteReference>() {
@Override public boolean test(CallSiteReference o) {
@ -179,10 +191,10 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
}
});
}
private class CHARootNode extends CHANode {
private final Set<CallSiteReference> calls = HashSetFactory.make();
protected CHARootNode(IMethod method, Context C) {
super(method, C);
}
@ -197,7 +209,7 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
return calls.add(reference);
}
}
@Override
protected CGNode makeFakeRootNode() throws CancelException {
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 {
return new CHARootNode(new FakeWorldClinitMethod(cha, options, cache), Everywhere.EVERYWHERE);
}
private int clinitPC = 0;
@Override
@SuppressWarnings("deprecation")
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 cln = makeNewNode(clinit, Everywhere.EVERYWHERE);
CGNode clinits = getFakeWorldClinitNode();
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 void closure() throws CancelException {
while (! newNodes.isEmpty()) {
CGNode n = newNodes.pop();
@ -240,7 +252,7 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
Iterator<IMethod> methods = getPossibleTargets(sites.next());
while (methods.hasNext()) {
IMethod target = methods.next();
if (!target.isAbstract()) {
if (isRelevantMethod(target)) {
CGNode callee = getNode(target, Everywhere.EVERYWHERE);
if (callee == null) {
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 {
CGNode n;
Key k = new Key(method, C);
@ -267,7 +285,7 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
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();
@ -282,7 +300,7 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
return preds;
}
}
@Override
public Iterator<CGNode> getPredNodes(CGNode n) {
return getPreds(n).iterator();
@ -366,7 +384,7 @@ public class CHACallGraph extends BasicCallGraph<CHAContextInterpreter> {
}
return result;
}
};
}