add application-only call graph
This commit is contained in:
parent
8c65754b0e
commit
589db13fa7
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue