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 }