001: /* Soot - a J*va Optimization Framework
002: * Copyright (C) 2002 Ondrej Lhotak
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2.1 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the
016: * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
017: * Boston, MA 02111-1307, USA.
018: */
019:
020: package soot.jimple.toolkits.callgraph;
021:
022: import java.util.ArrayList;
023: import java.util.Collection;
024: import java.util.Iterator;
025: import java.util.List;
026:
027: import soot.EntryPoints;
028: import soot.G;
029: import soot.Local;
030: import soot.MethodOrMethodContext;
031: import soot.PhaseOptions;
032: import soot.PointsToAnalysis;
033: import soot.PointsToSet;
034: import soot.Scene;
035: import soot.SootMethod;
036: import soot.Type;
037: import soot.util.queue.QueueReader;
038:
039: /** Models the call graph.
040: * @author Ondrej Lhotak
041: */
042: public final class CallGraphBuilder {
043: private PointsToAnalysis pa;
044: private final ReachableMethods reachables;
045: private final OnFlyCallGraphBuilder ofcgb;
046: private final CallGraph cg;
047:
048: public CallGraph getCallGraph() {
049: return cg;
050: }
051:
052: public ReachableMethods reachables() {
053: return reachables;
054: }
055:
056: public static ContextManager makeContextManager(CallGraph cg) {
057: return new ContextInsensitiveContextManager(cg);
058: }
059:
060: /** This constructor builds a complete call graph using the given
061: * PointsToAnalysis to resolve virtual calls. */
062: public CallGraphBuilder(PointsToAnalysis pa) {
063: this .pa = pa;
064: cg = new CallGraph();
065: Scene.v().setCallGraph(cg);
066: reachables = Scene.v().getReachableMethods();
067: ContextManager cm = makeContextManager(cg);
068: ofcgb = new OnFlyCallGraphBuilder(cm, reachables);
069: }
070:
071: /** This constructor builds the incomplete hack call graph for the
072: * Dava ThrowFinder.
073: * It uses all application class methods as entry points, and it ignores
074: * any calls by non-application class methods.
075: * Don't use this constructor if you need a real call graph. */
076: public CallGraphBuilder() {
077: G.v().out
078: .println("Warning: using incomplete callgraph containing "
079: + "only application classes.");
080: pa = soot.jimple.toolkits.pointer.DumbPointerAnalysis.v();
081: cg = new CallGraph();
082: Scene.v().setCallGraph(cg);
083: List<MethodOrMethodContext> entryPoints = new ArrayList<MethodOrMethodContext>();
084: entryPoints.addAll(EntryPoints.v()
085: .methodsOfApplicationClasses());
086: entryPoints.addAll(EntryPoints.v().implicit());
087: reachables = new ReachableMethods(cg, entryPoints);
088: ContextManager cm = new ContextInsensitiveContextManager(cg);
089: ofcgb = new OnFlyCallGraphBuilder(cm, reachables, true);
090: }
091:
092: public void build() {
093: QueueReader worklist = reachables.listener();
094: while (true) {
095: ofcgb.processReachables();
096: reachables.update();
097: if (!worklist.hasNext())
098: break;
099: MethodOrMethodContext momc = (MethodOrMethodContext) worklist
100: .next();
101: List receivers = (List) ofcgb.methodToReceivers().get(
102: momc.method());
103: if (receivers != null)
104: for (Iterator receiverIt = receivers.iterator(); receiverIt
105: .hasNext();) {
106: final Local receiver = (Local) receiverIt.next();
107: final PointsToSet p2set = pa
108: .reachingObjects(receiver);
109: for (Iterator typeIt = p2set.possibleTypes()
110: .iterator(); typeIt.hasNext();) {
111: final Type type = (Type) typeIt.next();
112: ofcgb.addType(receiver, momc.context(), type,
113: null);
114: }
115: }
116: List stringConstants = (List) ofcgb
117: .methodToStringConstants().get(momc.method());
118: if (stringConstants != null)
119: for (Iterator stringConstantIt = stringConstants
120: .iterator(); stringConstantIt.hasNext();) {
121: final Local stringConstant = (Local) stringConstantIt
122: .next();
123: PointsToSet p2set = pa
124: .reachingObjects(stringConstant);
125: Collection possibleStringConstants = p2set
126: .possibleStringConstants();
127: if (possibleStringConstants == null) {
128: ofcgb.addStringConstant(stringConstant, momc
129: .context(), null);
130: } else {
131: for (Iterator constantIt = possibleStringConstants
132: .iterator(); constantIt.hasNext();) {
133: final String constant = (String) constantIt
134: .next();
135: ofcgb.addStringConstant(stringConstant,
136: momc.context(), constant);
137: }
138: }
139: }
140: }
141: }
142: }
|