1 cananian 1.2.2.3 // CallGraph.java, created Mon Oct 12  6:11:27 1998 by cananian
  2 cananian 1.1     // Copyright (C) 1998 C. Scott Ananian <cananian@alumni.princeton.edu>
  3 cananian 1.1     // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 cananian 1.1     package harpoon.Main;
  5 cananian 1.1     
  6 cananian 1.2.2.2 import harpoon.ClassFile.CachingCodeFactory;
  7 cananian 1.2.2.1 import harpoon.ClassFile.HClass;
  8 cananian 1.2.2.2 import harpoon.ClassFile.HCodeFactory;
  9 cananian 1.2.2.1 import harpoon.ClassFile.HConstructor;
 10 cananian 1.2.2.1 import harpoon.ClassFile.HMethod;
 11 cananian 1.2.2.6 import harpoon.ClassFile.Linker;
 12 cananian 1.2.2.6 import harpoon.ClassFile.Loader;
 13 cananian 1.4     import net.cscott.jutil.UniqueVector;
 14 cananian 1.1     
 15 cananian 1.2.2.6 import java.util.Collections;
 16 cananian 1.1     import java.util.Enumeration;
 17 cananian 1.2     import java.util.Hashtable;
 18 cananian 1.2     import java.util.Vector;
 19 cananian 1.1     /**
 20 cananian 1.1      * <code>CallGraph</code> is a command-line call-graph generation tool.
 21 cananian 1.1      * 
 22 cananian 1.1      * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 23 cananian 1.4      * @version $Id: CallGraph.java,v 1.4 2004/02/08 01:58:13 cananian Exp $
 24 cananian 1.1      */
 25 cananian 1.1     
 26 cananian 1.1     public abstract class CallGraph extends harpoon.IR.Registration {
 27 cananian 1.1     
 28 cananian 1.1         public static final void main(String args[]) {
 29 cananian 1.1             java.io.PrintWriter out = new java.io.PrintWriter(System.out, true);
 30 cananian 1.2.2.6         Linker linker = Loader.systemLinker;
 31 cananian 1.1             HMethod m = null;
 32 cananian 1.1     
 33 cananian 1.1             if (args.length < 2) {
 34 cananian 1.1                 System.err.println("Needs class and method name.");
 35 cananian 1.1                 return;
 36 cananian 1.1             }
 37 cananian 1.1     
 38 cananian 1.1             {
 39 cananian 1.2.2.6             HClass cls = linker.forName(args[0]);
 40 cananian 1.1                 HMethod hm[] = cls.getDeclaredMethods();
 41 cananian 1.1                 for (int i=0; i<hm.length; i++)
 42 cananian 1.1                     if (hm[i].getName().equals(args[1])) {
 43 cananian 1.1                         m = hm[i];
 44 cananian 1.1                         break;
 45 cananian 1.1                     }
 46 cananian 1.1             }
 47 cananian 1.1     
 48 cananian 1.2.2.2         HCodeFactory hcf =
 49 cananian 1.2.2.2             new CachingCodeFactory(harpoon.IR.Quads.QuadNoSSA.codeFactory());
 50 cananian 1.2.2.4         harpoon.Analysis.ClassHierarchy ch = 
 51 cananian 1.2.2.6             new harpoon.Analysis.Quads.QuadClassHierarchy
 52 cananian 1.2.2.6             (linker, Collections.singleton(m), hcf);
 53 cananian 1.2.2.5         harpoon.Analysis.Quads.CallGraph cg =
 54 salcianu 1.2.2.7             new harpoon.Analysis.Quads.CallGraphImpl(ch, hcf);
 55 cananian 1.1     
 56 cananian 1.1             out.println("graph: {");
 57 cananian 1.1             out.println("title: \"Call graph rooted at "+m.getName()+"\"");
 58 cananian 1.2             String[] setup = { "x: 30", "y: 30",
 59 cananian 1.2                                "height: 800", "width: 500",
 60 cananian 1.1                                "stretch: 60", "shrink: 100",
 61 cananian 1.1                                "display_edge_labels: no",
 62 cananian 1.1                                "classname1: \"class summary\"",
 63 cananian 1.1                                "classname2: \"call graph\"",
 64 cananian 1.1                                "hidden: 1",
 65 cananian 1.2                                "layoutalgorithm: maxdepthslow",
 66 cananian 1.2                                "finetuning: no",
 67 cananian 1.2                                "cmin: 50 rmin:50 pmin: 50",
 68 cananian 1.1             };
 69 cananian 1.1             for (int i=0; i<setup.length; i++)
 70 cananian 1.1                 out.println(setup[i]);
 71 cananian 1.1     
 72 cananian 1.2             // traverse the call tree.
 73 cananian 1.2             StringBuffer nodes = new StringBuffer();
 74 cananian 1.2             StringBuffer edges = new StringBuffer();
 75 cananian 1.2     
 76 cananian 1.2             UniqueVector uv = new UniqueVector();
 77 cananian 1.2             uv.addElement(m);
 78 cananian 1.2             for (int i=0; i<uv.size(); i++) {
 79 cananian 1.2                 // make node
 80 cananian 1.2                 HMethod hm = (HMethod) uv.elementAt(i);
 81 cananian 1.2                 nodes.append("node: { title:\""+nodeString(hm)+"\" ");
 82 cananian 1.2                 nodes.append("textcolor: "+nodeColor(hm)+" }\n");
 83 cananian 1.2                 // make edges
 84 cananian 1.2                 HMethod child[] = cg.calls(hm);
 85 cananian 1.2                 for (int j=0; j<child.length; j++) {
 86 cananian 1.2                     edges.append(edgeString(hm, child[j], 
 87 cananian 1.2                                             "class: 2 color: "+nodeColor(hm)));
 88 cananian 1.2                     uv.addElement(child[j]); // add to worklist.
 89 cananian 1.2                 }
 90 cananian 1.1             }
 91 cananian 1.1             // make invisible summary-node edges
 92 cananian 1.2             Hashtable classMethods = new Hashtable();
 93 cananian 1.1             for (int i=0; i<uv.size(); i++) {
 94 cananian 1.1                 HMethod hm = (HMethod) uv.elementAt(i);
 95 cananian 1.2                 HClass  hc = hm.getDeclaringClass();
 96 cananian 1.2                 Vector v = (Vector) classMethods.get(hc);
 97 cananian 1.2                 if (v==null) { v = new Vector(); classMethods.put(hc, v); }
 98 cananian 1.2                 v.addElement(hm);
 99 cananian 1.2             }
100 cananian 1.2             for (Enumeration e = classMethods.keys(); e.hasMoreElements(); ) {
101 cananian 1.2                 HClass hc = (HClass) e.nextElement();
102 cananian 1.2                 Vector v = (Vector) classMethods.get(hc);
103 cananian 1.2                 for (int i=0; i<v.size(); i++) {
104 cananian 1.2                     int from = ( (i==0)?v.size():i ) - 1;
105 cananian 1.2                     edges.append(edgeString((HMethod) v.elementAt(from),
106 cananian 1.2                                             (HMethod) v.elementAt(i),
107 cananian 1.2                                             "linestyle: invisible class: 1"));
108 cananian 1.1                 }
109 cananian 1.1             }
110 cananian 1.2             // print all this schtuff out.
111 cananian 1.2             out.println(nodes);
112 cananian 1.2             out.println(edges);
113 cananian 1.1             out.println("}");
114 cananian 1.1         }
115 cananian 1.1     
116 cananian 1.1         static String edgeString(HMethod from, HMethod to, String otherinfo)
117 cananian 1.1         {
118 cananian 1.1             return "edge: { " +
119 cananian 1.1                 "sourcename: \""+nodeString(from)+"\" " +
120 cananian 1.1                 "targetname: \""+nodeString( to )+"\" " +
121 cananian 1.1                 ( (otherinfo==null)?"":otherinfo ) +
122 cananian 1.2                 "}\n";
123 cananian 1.1         }
124 cananian 1.1         static String nodeString(HMethod m) {
125 cananian 1.1             // Modified version of HMethod.toString.
126 cananian 1.1             StringBuffer r = new StringBuffer();
127 cananian 1.1             r.append(getTypeName(m.getDeclaringClass()));
128 cananian 1.1             if (!(m instanceof HConstructor)) {
129 cananian 1.1                 r.append('.');
130 cananian 1.1                 r.append(m.getName());
131 cananian 1.1             }
132 cananian 1.1             r.append('(');
133 cananian 1.1             HClass hcp[] = m.getParameterTypes();
134 cananian 1.1             for (int i=0; i<hcp.length; i++) {
135 cananian 1.1                 r.append(getTypeName(hcp[i]));
136 cananian 1.1                 if (i<hcp.length-1)
137 cananian 1.1                     r.append(',');
138 cananian 1.1             }
139 cananian 1.1             r.append(')');
140 cananian 1.1             return r.toString();
141 cananian 1.1         }
142 cananian 1.2         static String nodeColor(HMethod m) {
143 cananian 1.2             // list of color values to skip:
144 cananian 1.2             int not[]=new int[]{ 0/*white*/, 4/*yellow*/, 6/*cyan*/, 28/*pink*/};
145 cananian 1.2             int color = m.getDeclaringClass().hashCode()%(32-not.length);
146 cananian 1.2             for (int i=0; i<not.length; i++)
147 cananian 1.2                 if (color >= not[i]) color++;
148 cananian 1.2             return ""+color;
149 cananian 1.2         }
150 cananian 1.2             
151 cananian 1.1         // From HField:
152 cananian 1.1         static String getTypeName(HClass hc) {
153 cananian 1.1             if (hc.isArray()) {
154 cananian 1.1                 StringBuffer r = new StringBuffer();
155 cananian 1.1                 HClass sup = hc;
156 cananian 1.1                 int i=0;
157 cananian 1.1                 for (; sup.isArray(); sup = sup.getComponentType())
158 cananian 1.1                     i++;
159 cananian 1.1                 r.append(sup.getName());
160 cananian 1.1                 for (int j=0; j<i; j++)
161 cananian 1.1                     r.append("[]");
162 cananian 1.1                 return r.toString();
163 cananian 1.1             }
164 cananian 1.1             return hc.getName();
165 cananian 1.1         }
166 cananian 1.1     }