added callgraph pruning to remove less relevant library methods

This commit is contained in:
Juergen Graf 2011-07-28 12:08:59 +02:00
parent 6877158843
commit 26d65e9f9c
3 changed files with 411 additions and 0 deletions

View File

@ -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,

View File

@ -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--;
}
}
}

View File

@ -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);
}
}