added callgraph pruning to remove less relevant library methods
This commit is contained in:
parent
6877158843
commit
26d65e9f9c
|
@ -34,6 +34,7 @@ Export-Package: .,
|
|||
com.ibm.wala.escape,
|
||||
com.ibm.wala.ipa.callgraph,
|
||||
com.ibm.wala.ipa.callgraph.impl,
|
||||
com.ibm.wala.ipa.callgraph.pruned,
|
||||
com.ibm.wala.ipa.callgraph.propagation,
|
||||
com.ibm.wala.ipa.callgraph.propagation.cfa,
|
||||
com.ibm.wala.ipa.callgraph.propagation.rta,
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
package com.ibm.wala.ipa.callgraph.pruned;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.ibm.wala.ipa.callgraph.AnalysisScope;
|
||||
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||
import com.ibm.wala.ipa.callgraph.CallGraph;
|
||||
|
||||
public final class CallGraphPruning {
|
||||
|
||||
public CallGraphPruning(CallGraph cg) {
|
||||
this.cg = cg;
|
||||
}
|
||||
|
||||
private Set<CGNode> keep;
|
||||
private LinkedList<CGNode> visited;
|
||||
private List<CGNode> marked;
|
||||
private int depth;
|
||||
private CallGraph cg;
|
||||
|
||||
private boolean DEBUG = false;
|
||||
|
||||
/**
|
||||
* Searches all nodes in the callgraph that correspond to a method of the application (and not the system library).
|
||||
* It includes methods from the system library that transitively may call back into the application.
|
||||
* @return Set of relevant callgraph nodes.
|
||||
*/
|
||||
public Set<CGNode> findApplicationNodes() {
|
||||
return findApplicationNodes(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches all nodes in the callgraph that correspond to a method of the application (and not the system library).
|
||||
* It includes methods from the system library that transitively may call back into the application. Library
|
||||
* methods that do not transitively call back into application methods are cut at the level provided by parameter
|
||||
* depth.
|
||||
* @param depth The level at which non-returning library methods are cut off.
|
||||
* @return Set of relevant callgraph nodes.
|
||||
*/
|
||||
public Set<CGNode> findApplicationNodes(final int depth) {
|
||||
|
||||
if (DEBUG) {
|
||||
System.out.println("Running optimization with depth: " + depth);
|
||||
}
|
||||
|
||||
this.marked = new LinkedList<CGNode>();
|
||||
this.keep = new HashSet<CGNode>();
|
||||
this.visited = new LinkedList<CGNode>();
|
||||
this.depth = depth;
|
||||
|
||||
dfs(cg.getFakeRootNode());
|
||||
|
||||
return keep;
|
||||
}
|
||||
|
||||
private void dfs(CGNode root) {
|
||||
|
||||
visited.addLast(root);
|
||||
|
||||
Iterator<CGNode> it = cg.getSuccNodes(root);
|
||||
while (it.hasNext()) {
|
||||
CGNode next = it.next();
|
||||
if (!marked.contains(next)) {
|
||||
marked.add(next);
|
||||
dfs(next);
|
||||
} else {
|
||||
if (keep.contains(next)) {
|
||||
keep.addAll(visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (checkLoader(root)) {
|
||||
keep.addAll(visited);
|
||||
addDepth(root);
|
||||
}
|
||||
visited.removeLast();
|
||||
}
|
||||
|
||||
private static boolean checkLoader(CGNode node) {
|
||||
return node.getMethod().getDeclaringClass().getClassLoader().getName().equals(AnalysisScope.APPLICATION);
|
||||
}
|
||||
|
||||
private void addDepth(CGNode node) {
|
||||
|
||||
LinkedList<CGNode> A = new LinkedList<CGNode>();
|
||||
LinkedList<CGNode> B = new LinkedList<CGNode>();
|
||||
int i = depth;
|
||||
A.add(node);
|
||||
while (i > 0) {
|
||||
|
||||
for (CGNode n : A) {
|
||||
Iterator<CGNode> it = cg.getSuccNodes(n);
|
||||
while (it.hasNext()) {
|
||||
B.add(it.next());
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
System.out.println("Tiefe: " + B);
|
||||
}
|
||||
|
||||
keep.addAll(B);
|
||||
A.clear();
|
||||
A.addAll(B);
|
||||
B.clear();
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,294 @@
|
|||
package com.ibm.wala.ipa.callgraph.pruned;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Set;
|
||||
|
||||
import com.ibm.wala.classLoader.CallSiteReference;
|
||||
import com.ibm.wala.classLoader.IMethod;
|
||||
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.cha.IClassHierarchy;
|
||||
import com.ibm.wala.types.MethodReference;
|
||||
import com.ibm.wala.util.intset.BitVectorIntSet;
|
||||
import com.ibm.wala.util.intset.IntSet;
|
||||
|
||||
public class PrunedCallGraph implements CallGraph {
|
||||
|
||||
private CallGraph cg;
|
||||
private Set<CGNode> keep;
|
||||
|
||||
public PrunedCallGraph(CallGraph cg, Set<CGNode> keep) {
|
||||
this.cg = cg;
|
||||
this.keep = keep;
|
||||
}
|
||||
|
||||
public void removeNodeAndEdges(CGNode n) throws UnsupportedOperationException {
|
||||
cg.removeNodeAndEdges(n);
|
||||
keep.remove(n);
|
||||
}
|
||||
|
||||
public Iterator<CGNode> iterator() {
|
||||
Iterator<CGNode> tmp = cg.iterator();
|
||||
Collection<CGNode> col = new LinkedList<CGNode>();
|
||||
while (tmp.hasNext()) {
|
||||
CGNode n = tmp.next();
|
||||
if (keep.contains(n)) {
|
||||
col.add(n);
|
||||
}
|
||||
}
|
||||
|
||||
return col.iterator();
|
||||
}
|
||||
|
||||
public int getNumberOfNodes() {
|
||||
return keep.size();
|
||||
}
|
||||
|
||||
public void addNode(CGNode n) {
|
||||
cg.addNode(n);
|
||||
keep.add(n);
|
||||
}
|
||||
|
||||
public void removeNode(CGNode n) throws UnsupportedOperationException {
|
||||
cg.removeNode(n);
|
||||
keep.remove(n);
|
||||
}
|
||||
|
||||
public boolean containsNode(CGNode n) {
|
||||
return cg.containsNode(n) && keep.contains(n);
|
||||
}
|
||||
|
||||
public Iterator<CGNode> getPredNodes(CGNode n) {
|
||||
Iterator<CGNode> tmp = cg.getPredNodes(n);
|
||||
Collection<CGNode> col = new LinkedList<CGNode>();
|
||||
while (tmp.hasNext()) {
|
||||
CGNode no = tmp.next();
|
||||
if (keep.contains(no)) {
|
||||
col.add(no);
|
||||
}
|
||||
}
|
||||
|
||||
return col.iterator();
|
||||
}
|
||||
|
||||
public int getPredNodeCount(CGNode n) {
|
||||
Iterator<CGNode> tmp = cg.getPredNodes(n);
|
||||
int cnt = 0;
|
||||
while (tmp.hasNext()) {
|
||||
CGNode no = tmp.next();
|
||||
if (keep.contains(no)) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
|
||||
public Iterator<CGNode> getSuccNodes(CGNode n) {
|
||||
Iterator<CGNode> tmp = cg.getSuccNodes(n);
|
||||
Collection<CGNode> col = new LinkedList<CGNode>();
|
||||
while (tmp.hasNext()) {
|
||||
CGNode no = tmp.next();
|
||||
if (keep.contains(no)) {
|
||||
col.add(no);
|
||||
}
|
||||
}
|
||||
|
||||
return col.iterator();
|
||||
}
|
||||
|
||||
|
||||
public int getSuccNodeCount(CGNode n) {
|
||||
Iterator<CGNode> tmp = cg.getSuccNodes(n);
|
||||
int cnt = 0;
|
||||
while (tmp.hasNext()) {
|
||||
CGNode no = tmp.next();
|
||||
if (keep.contains(no)) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
|
||||
public void addEdge(CGNode src, CGNode dst) {
|
||||
if (keep.contains(src) && keep.contains(dst)){
|
||||
cg.addEdge(src, dst);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void removeEdge(CGNode src, CGNode dst) throws UnsupportedOperationException {
|
||||
cg.removeEdge(src, dst);
|
||||
}
|
||||
|
||||
|
||||
public void removeAllIncidentEdges(CGNode node) throws UnsupportedOperationException {
|
||||
cg.removeAllIncidentEdges(node);
|
||||
}
|
||||
|
||||
|
||||
public void removeIncomingEdges(CGNode node) throws UnsupportedOperationException {
|
||||
cg.removeIncomingEdges(node);
|
||||
}
|
||||
|
||||
|
||||
public void removeOutgoingEdges(CGNode node) throws UnsupportedOperationException {
|
||||
cg.removeOutgoingEdges(node);
|
||||
}
|
||||
|
||||
|
||||
public boolean hasEdge(CGNode src, CGNode dst) {
|
||||
return cg.hasEdge(src, dst) && keep.contains(src) && keep.contains(dst);
|
||||
}
|
||||
|
||||
|
||||
public int getNumber(CGNode N) {
|
||||
if (keep.contains(N)) {
|
||||
return cg.getNumber(N);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public CGNode getNode(int number) {
|
||||
if(keep.contains(cg.getNode(number))) {
|
||||
return cg.getNode(number);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int getMaxNumber() {
|
||||
return cg.getMaxNumber();
|
||||
}
|
||||
|
||||
|
||||
public Iterator<CGNode> iterateNodes(IntSet s) {
|
||||
Iterator<CGNode> tmp = cg.iterateNodes(s);
|
||||
Collection<CGNode> col = new LinkedList<CGNode>();
|
||||
while (tmp.hasNext()) {
|
||||
CGNode n = tmp.next();
|
||||
if (keep.contains(n)) {
|
||||
col.add(n);
|
||||
}
|
||||
}
|
||||
|
||||
return col.iterator();
|
||||
}
|
||||
|
||||
|
||||
public IntSet getSuccNodeNumbers(CGNode node) {
|
||||
if (!keep.contains(node)){
|
||||
return null;
|
||||
}
|
||||
IntSet tmp = cg.getSuccNodeNumbers(node);
|
||||
BitVectorIntSet kp = new BitVectorIntSet();
|
||||
for (CGNode n : keep) {
|
||||
kp.add(getNumber(n));
|
||||
}
|
||||
return tmp.intersection(kp);
|
||||
}
|
||||
|
||||
|
||||
public IntSet getPredNodeNumbers(CGNode node) {
|
||||
if (!keep.contains(node)){
|
||||
return null;
|
||||
}
|
||||
if (!keep.contains(node)){
|
||||
return null;
|
||||
}
|
||||
IntSet tmp = cg.getPredNodeNumbers(node);
|
||||
BitVectorIntSet kp = new BitVectorIntSet();
|
||||
for (CGNode n : keep) {
|
||||
kp.add(getNumber(n));
|
||||
}
|
||||
return tmp.intersection(kp);
|
||||
}
|
||||
|
||||
|
||||
public CGNode getFakeRootNode() {
|
||||
if (keep.contains(cg.getFakeRootNode())) {
|
||||
return cg.getFakeRootNode();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Collection<CGNode> getEntrypointNodes() {
|
||||
Collection<CGNode> tmp = cg.getEntrypointNodes();
|
||||
Set<CGNode> ret = new HashSet<CGNode>();
|
||||
for (CGNode n : tmp) {
|
||||
if (keep.contains(n)) {
|
||||
ret.add(n);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
public CGNode getNode(IMethod method, Context C) {
|
||||
if(keep.contains(cg.getNode(method, C))) {
|
||||
return cg.getNode(method, C);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Set<CGNode> getNodes(MethodReference m) {
|
||||
Set<CGNode> tmp = cg.getNodes(m);
|
||||
Set<CGNode> ret = new HashSet<CGNode>();
|
||||
for (CGNode n : tmp) {
|
||||
if (keep.contains(n)) {
|
||||
ret.add(n);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
public IClassHierarchy getClassHierarchy() {
|
||||
return cg.getClassHierarchy();
|
||||
}
|
||||
|
||||
|
||||
public Set<CGNode> getPossibleTargets(CGNode node, CallSiteReference site) {
|
||||
if (!keep.contains(node)){
|
||||
return null;
|
||||
}
|
||||
Set<CGNode> tmp = cg.getPossibleTargets(node, site);
|
||||
Set<CGNode> ret = new HashSet<CGNode>();
|
||||
for (CGNode n : tmp) {
|
||||
if (keep.contains(n)) {
|
||||
ret.add(n);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
public int getNumberOfTargets(CGNode node, CallSiteReference site) {
|
||||
if (!keep.contains(node)){
|
||||
return -1;
|
||||
}
|
||||
return getPossibleTargets(node, site).size();
|
||||
}
|
||||
|
||||
|
||||
public Iterator<CallSiteReference> getPossibleSites(CGNode src, CGNode target) {
|
||||
if (!(keep.contains(src) && keep.contains(target))){
|
||||
return null;
|
||||
}
|
||||
return cg.getPossibleSites(src, target);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue