fix some warnings
[eclipsethinslicer.git] / Svelte / src / edu / berkeley / cs / bodik / svelte / plugin / cgview / CallGraphSlice.java
blob293c4df771b39265a648e8221544e2a1fc713fbb
1 /*******************************************************************************
2 * This program and the accompanying materials
3 * are made available under the terms of the Eclipse Public License v1.0
4 * which accompanies this distribution, and is available at
5 * http://www.eclipse.org/legal/epl-v10.html.
6 *
7 * This file is a derivative of code released by the University of
8 * California under the terms listed below.
10 * Refinement Analysis Tools is Copyright ©2007 The Regents of the
11 * University of California (Regents). Provided that this notice and
12 * the following two paragraphs are included in any distribution of
13 * Refinement Analysis Tools or its derivative work, Regents agrees
14 * not to assert any of Regents' copyright rights in Refinement
15 * Analysis Tools against recipient for recipient’s reproduction,
16 * preparation of derivative works, public display, public
17 * performance, distribution or sublicensing of Refinement Analysis
18 * Tools and derivative works, in source code and object code form.
19 * This agreement not to assert does not confer, by implication,
20 * estoppel, or otherwise any license or rights in any intellectual
21 * property of Regents, including, but not limited to, any patents
22 * of Regents or Regents’ employees.
24 * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT,
25 * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
26 * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE
27 * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
30 * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
32 * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY
33 * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING
34 * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
35 * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
36 * UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
38 package edu.berkeley.cs.bodik.svelte.plugin.cgview;
40 import java.util.ArrayList;
41 import java.util.Collection;
42 import java.util.HashSet;
43 import java.util.Hashtable;
44 import java.util.Iterator;
46 import com.ibm.wala.ipa.callgraph.CGNode;
47 import com.ibm.wala.ipa.slicer.NormalReturnCallee;
48 import com.ibm.wala.ipa.slicer.NormalReturnCaller;
49 import com.ibm.wala.ipa.slicer.NormalStatement;
50 import com.ibm.wala.ipa.slicer.ParamCallee;
51 import com.ibm.wala.ipa.slicer.ParamCaller;
52 import com.ibm.wala.ipa.slicer.Statement;
53 import com.ibm.wala.types.TypeReference;
54 import com.ibm.wala.util.graph.Graph;
56 import edu.berkeley.cs.bodik.svelte.Slice;
57 import edu.berkeley.cs.bodik.svelte.StatementUtils;
58 import edu.berkeley.cs.bodik.svelte.plugin.SliceEnvironment;
60 public class CallGraphSlice {
61 private Slice seed;
62 // if you want to work on performance, you could try having using CGNode for this instead (need
63 // another hash for string lookups)
64 private Hashtable<String, Node> allnodes = null;
66 // fakenewnodes are added to represent new X() calls which assign a default value of x.property.
67 // for instance, if the function foo() contains the line "b = new Bar()", which causes
68 // b.myObject to have a default
69 // value of null, and b.myObject is used later in function hello(), we don't want to show foo()
70 // having a direct edge to hello()
71 // rather we want to show an edge from foo to a "fake new node", and from this to hello()
72 // private Hashtable<TypeReference, FakeNewNode> fakenewnodes = null;
73 // 2008-05-06: wasn't read so was giving a warning, taken out. I don't know why?
75 // really a hash set
76 private Hashtable<Edge, Edge> alledges = null;
78 // a mapping from class -> unique index, 1,2,3,... in the order came upon by the BFS traversal
79 // of the slice.
80 Hashtable<String, Integer> classesToIndices;
82 private Hashtable<Node, ArrayList<Edge>> predEdges = null;
83 private int depth;
85 public CallGraphSlice(Slice seed, int depth) {
86 this.seed = seed;
87 this.depth = depth;
90 class Node {
91 boolean drawPredNodes = false;
94 class RegularNode extends Node {
95 CGNode node;
97 public RegularNode(CGNode node) {
98 this.node = node;
101 @Override
102 public int hashCode() {
103 return node.getMethod().getSignature().hashCode();
106 @Override
107 public boolean equals(Object xx) {
108 RegularNode x;
109 return (xx instanceof RegularNode) && ((x = (RegularNode) xx) != null)
110 && x.node.getMethod().getSignature().equals(node.getMethod().getSignature());
111 // compare based on signature.
114 @Override
115 public String toString() {
116 return node.getMethod().getSignature();
120 class FakeNewNode extends Node {
121 TypeReference typref; // reference to the constructor function
123 public FakeNewNode(TypeReference newInstType) {
124 this.typref = newInstType;
127 @Override
128 public int hashCode() {
129 return typref.toString().hashCode();
132 @Override
133 public boolean equals(Object xx) {
134 FakeNewNode x;
135 return (xx instanceof FakeNewNode) && ((x = (FakeNewNode) xx) != null)
136 && x.typref.toString().equals(typref.toString());
137 // compare based on signature.
140 @Override
141 public String toString() {
142 return typref.toString();
146 class Edge {
147 public static final int TYPE_THRU_PARAM = 1;
148 public static final int TYPE_THRU_RETVAL = 2;
149 public static final int TYPE_THRU_ALIASING = 3;
151 public int type;
152 public int duplicity;
153 public Node from;
154 public Node to;
156 public Edge(int type, Node from, Node to) {
157 this.type = type;
158 this.duplicity = 1;
159 this.from = from;
160 this.to = to;
163 @Override
164 public int hashCode() {
165 return from.hashCode() + to.hashCode() + type;
168 @Override
169 public boolean equals(Object xx) {
170 Edge x;
171 return (xx instanceof Edge) && ((x = (Edge) xx) != null) && from.equals(x.from)
172 && to.equals(x.to) && type == x.type;
177 private Node getNodeFromCGNode(CGNode cgn) {
178 assert (allnodes != null);
179 Node node = allnodes.get(cgn.getMethod().getSignature());
180 if (node == null) {
181 node = new RegularNode(cgn);
182 allnodes.put(cgn.getMethod().getSignature(), node);
184 // if this class not listed in classesToColor, add this class.
185 String sig = node.toString();
186 int lastdot = sig.lastIndexOf('.');
187 String classname = sig.substring(0, lastdot);
188 if (classesToIndices.get(classname) == null)
189 classesToIndices.put(classname, new Integer(classesToIndices.size() + 1));
191 return node;
195 * Add edge to alledges and tosPredEdges. If it is already in (check all edges but should be in
196 * both in), just increments the duplicity (if the second arg is true)
198 * @param edgeToAdd
200 private void addEdge(Edge edgeToAdd, boolean ignoreIfAlreadyIn) {
201 if (edgeToAdd != null) {
202 Edge alreadyIn = alledges.get(edgeToAdd);
203 if (alreadyIn == null) {
204 alledges.put(edgeToAdd, edgeToAdd);
206 ArrayList<Edge> tosPredEdges = predEdges.get(edgeToAdd.to);
207 if (tosPredEdges == null) {
208 tosPredEdges = new ArrayList<Edge>();
209 predEdges.put(edgeToAdd.to, tosPredEdges);
211 tosPredEdges.add(edgeToAdd);
212 } else {
213 if (!ignoreIfAlreadyIn)
214 alreadyIn.duplicity += 1;
219 private Node getOrMakeFakeNewNode(TypeReference newInstType) {
220 assert (allnodes != null);
221 Node node = allnodes.get(newInstType.toString());
222 if (node == null) {
223 node = new FakeNewNode(newInstType);
224 allnodes.put(newInstType.toString(), node);
226 // if this class not listed in classesToColor, add this class.
227 String classname = newInstType.getClass().toString();
228 System.out.println("DEBUG fakenewnode class = " + classname);
229 if (classesToIndices.get(classname) == null)
230 classesToIndices.put(classname, new Integer(classesToIndices.size() + 1));
232 return node;
235 // this also calculates the colors (via getNodeFromCGNode)
236 public void recalculateGraph() {
237 // clear nodes & edges
238 allnodes = new Hashtable<String, Node>();
239 // fakenewnodes = new Hashtable<TypeReference, FakeNewNode>();
240 alledges = new Hashtable<Edge, Edge>();
241 predEdges = new Hashtable<Node, ArrayList<Edge>>();
242 classesToIndices = new Hashtable<String, Integer>();
244 // do the cgview stuff and generate the dot code
246 // NEVER fix method seed statements here. They should have already been fixed in the seed.
248 Graph<Statement> depGraph = SliceEnvironment.getDepGraph();
250 ArrayList<Statement> worklist = new ArrayList<Statement>();
251 HashSet<Statement> serviced = new HashSet<Statement>();
252 // BFS time, baby
253 worklist.addAll(seed.getStatements());
255 int level = 0;
256 int nextlevelindex = worklist.size();
258 int index = -1;
259 while ((index + 1) < worklist.size()) {
260 index++;
261 if (index == nextlevelindex) {
262 nextlevelindex = worklist.size();
263 level++;
264 if (level > depth)
265 break;
267 Statement s = worklist.get(index);
269 // service it
270 if (serviced.contains(s))
271 continue;
272 serviced.add(s);
274 // look thru the succ nodes, if theres any 'return val' ones or something, build the
275 // bridge.
276 Iterator<? extends Statement> succNodes = depGraph.getSuccNodes(s);
277 Statement ss;
278 while (succNodes.hasNext()) {
279 ss = succNodes.next();
281 Node fromnode = null, tonode = null;
283 if (s instanceof ParamCallee && ss instanceof ParamCaller) {
284 // node of ss calls node of s, passing in the data as a parameter
285 tonode = getNodeFromCGNode(((ParamCallee) s).getNode());
286 fromnode = getNodeFromCGNode(((ParamCaller) ss).getNode());
287 addEdge(new Edge(Edge.TYPE_THRU_PARAM, fromnode, tonode), false);
288 } else if (s instanceof NormalReturnCaller && ss instanceof NormalReturnCallee) {
289 // node of s calls node of ss, gets data from node of ss as a return value
290 tonode = getNodeFromCGNode(((NormalReturnCaller) s).getNode());
291 fromnode = getNodeFromCGNode(((NormalReturnCallee) ss).getNode());
292 addEdge(new Edge(Edge.TYPE_THRU_RETVAL, fromnode, tonode), false);
293 } else if (s instanceof NormalStatement && ss instanceof NormalStatement
294 && ((NormalStatement) s).getNode() != ((NormalStatement) ss).getNode()) {
295 // ss writes to some pointerkey which s reads from, thereby passing data
296 // (possibly)
298 tonode = getNodeFromCGNode(((NormalStatement) s).getNode());
299 fromnode = getNodeFromCGNode(((NormalStatement) ss).getNode());
301 TypeReference newInstType = StatementUtils.getNewInstructionDeclaredType(ss);
302 if (newInstType != null) { // if it's a SSANewInstruction
303 // System.out.println("fakenewnode from " + ss + " --to-- " + s);
304 Node fakenewnode = getOrMakeFakeNewNode(newInstType);
305 addEdge(new Edge(Edge.TYPE_THRU_ALIASING, fakenewnode, tonode), true); // don't
306 // count
307 // duplicity
308 // for
309 // this
310 // edge
311 addEdge(new Edge(Edge.TYPE_THRU_PARAM, fromnode, fakenewnode), false);
312 } else
313 addEdge(new Edge(Edge.TYPE_THRU_ALIASING, fromnode, tonode), false);
316 // add succ nodes to worklist if not already serviced.
317 if (!serviced.contains(ss))
318 worklist.add(ss);
322 System.out.println("! total # of nodes: " + allnodes.size());
323 System.out.println("! total # of edges: " + alledges.size());
324 System.out.println("! total # of statements: " + index);
328 public void toggleCollapsed(String nodename) {
329 if (allnodes != null) {
330 Node node = allnodes.get(nodename);
331 if (node != null) {
332 node.drawPredNodes = !node.drawPredNodes;
333 } else {
334 System.err.println("can't find node " + nodename + "!");
339 public StringBuffer generateDot() {
340 if (predEdges == null)
341 recalculateGraph();
343 // do a BFS of the CG slice graph and find which nodes and edges to draw.
344 HashSet<Node> nodesToDraw = new HashSet<Node>();
345 // HashSet<Edge> edgesToDraw = new HashSet<Edge>();
347 ArrayList<Node> orderedNodesToDraw = new ArrayList<Node>(); // preserver order of BFS to not
348 // surprise users when they
349 // expand/collapse things
350 ArrayList<Edge> orderedEdgesToDraw = new ArrayList<Edge>();
352 ArrayList<Node> worklist = new ArrayList<Node>();
353 // BFS time, baby
355 // start at the seed, as always
356 for (Statement s : seed) {
357 if (s instanceof NormalStatement) {
358 worklist.add(getNodeFromCGNode(((NormalStatement) s).getNode()));
362 int index = -1;
363 while ((index + 1) < worklist.size()) {
364 index++;
365 Node n = worklist.get(index);
367 // service it
368 if (nodesToDraw.contains(n))
369 continue;
370 nodesToDraw.add(n);
371 orderedNodesToDraw.add(n);
373 // look thru the nodes pointing to it and add them
374 if (n.drawPredNodes) {
375 ArrayList<Edge> nsPredEdges = predEdges.get(n);
376 if (nsPredEdges != null) {
377 for (Edge e : nsPredEdges) {
378 worklist.add(e.from);
379 // edgesToDraw.add(e);
380 orderedEdgesToDraw.add(e);
385 return generateDot(orderedNodesToDraw, orderedEdgesToDraw);
388 public StringBuffer generateDot(Collection<Node> nodes, Collection<Edge> edges) {
389 StringBuffer buf = new StringBuffer();
391 // general stuff
392 buf.append("digraph callgraphslice {\n");
393 buf.append("rankdir=RL;\n");
395 .append("node [shape=rect,height=0,width=0,fontsize=12,fillcolor=mediumaquamarine,style=filled]\n");
397 // nodes (need URL property)
399 String[] colors = { "greenyellow", "aliceblue", "salmon", "lightskyblue", "lightslateblue",
400 "peru" };
402 for (Node n : nodes) {
403 String sig = n.toString();
404 String label = sig;
405 Integer colorindex = null;
406 try {
407 int lastdot = sig.lastIndexOf('.');
408 String classname = sig.substring(0, lastdot);
409 String methodname = sig.substring(lastdot + 1, sig.length());
410 lastdot = classname.lastIndexOf('.');
411 String classclassname = classname.substring(lastdot + 1, classname.length());
413 label = methodname + " -- " + classclassname;
414 colorindex = classesToIndices.get(classname);
415 } catch (Exception e) {
418 String color = "lightgrey";
419 if (colorindex != null)
420 color = colors[colorindex.intValue() % colors.length];
422 buf.append(String.format(
423 "\"%s\" [URL=\"%s\",fillcolor=\"%s\",label=\"%s\",color=\"%s\"]\n", n, n,
424 color, label, ((!n.drawPredNodes) && predEdges.get(n) != null) ? "black"
425 : color));
428 // edges
429 for (Edge e : edges) {
430 String s = String.format("\"%s\" -> \"%s\" [", e.from, e.to);
431 if (e.duplicity > 1)
432 s += String.format("label=\"x%2d\",", e.duplicity);
434 if (e.type == Edge.TYPE_THRU_PARAM)
435 s += "color=blue";
436 else if (e.type == Edge.TYPE_THRU_RETVAL)
437 s += "color=red,arrowhead=inv";
438 else if (e.type == Edge.TYPE_THRU_ALIASING)
439 s += "style=dashed";
441 s += "]\n";
442 buf.append(s);
445 buf.append("}\n");
446 return buf;