1 cananian 1.1.2.1 // CallGraphImpl.java, created Sun Oct 11 12:56:36 1998 by cananian 2 cananian 1.1.2.1 // Copyright (C) 1998 C. Scott Ananian <cananian@alumni.princeton.edu> 3 cananian 1.1.2.1 // Licensed under the terms of the GNU GPL; see COPYING for details. 4 cananian 1.1.2.1 package harpoon.Analysis.Quads; 5 cananian 1.1.2.1 6 cananian 1.1.2.1 import harpoon.Analysis.ClassHierarchy; 7 cananian 1.1.2.1 import harpoon.Analysis.Maps.ExactTypeMap; 8 cananian 1.1.2.1 import harpoon.Analysis.ReachingDefs; 9 cananian 1.1.2.1 import harpoon.Analysis.SSxReachingDefsImpl; 10 cananian 1.1.2.1 import harpoon.ClassFile.HClass; 11 cananian 1.1.2.1 import harpoon.ClassFile.HCode; 12 cananian 1.1.2.1 import harpoon.ClassFile.HCodeFactory; 13 cananian 1.1.2.1 import harpoon.ClassFile.HMethod; 14 cananian 1.1.2.1 import harpoon.IR.Quads.Quad; 15 cananian 1.1.2.1 import harpoon.IR.Quads.CALL; 16 cananian 1.1.2.1 import harpoon.Temp.Temp; 17 cananian 1.1.2.1 import harpoon.Util.Util; 18 cananian 1.6 import net.cscott.jutil.WorkSet; 19 cananian 1.1.2.1 20 cananian 1.1.2.1 import java.util.Arrays; 21 cananian 1.1.2.1 import java.util.Collections; 22 cananian 1.1.2.1 import java.util.HashMap; 23 cananian 1.1.2.1 import java.util.HashSet; 24 cananian 1.1.2.1 import java.util.Iterator; 25 cananian 1.1.2.1 import java.util.List; 26 cananian 1.1.2.1 import java.util.Map; 27 cananian 1.1.2.1 import java.util.Set; 28 cananian 1.1.2.1 import java.util.Vector; 29 cananian 1.1.2.1 30 cananian 1.1.2.1 /** 31 cananian 1.1.2.1 * <code>CallGraphImpl2</code> constructs a simple directed call graph. 32 cananian 1.1.2.1 * This version pays closer attention to types for a more precise 33 cananian 1.1.2.1 * result. To quantify this a bit, the standard <code>CallGraphImpl</code> 34 cananian 1.1.2.1 * yields a 510-node call graph on the "Hello, World" program, compared 35 cananian 1.1.2.1 * to the 370-node graph that <code>CallGraphImpl2</code> gives you. 36 cananian 1.1.2.1 * <p> 37 cananian 1.1.2.1 * <code>CallGraphImpl2</code> only works on SSI form. 38 cananian 1.1.2.1 * 39 cananian 1.1.2.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 40 cananian 1.7 * @version $Id: CallGraphImpl2.java,v 1.7 2004/02/08 03:20:10 cananian Exp $ 41 cananian 1.1.2.1 */ 42 salcianu 1.5 public class CallGraphImpl2 extends harpoon.Analysis.CallGraph { 43 cananian 1.1.2.1 final HCodeFactory hcf; 44 cananian 1.1.2.1 final ClassHierarchy ch; 45 cananian 1.1.2.1 /** Creates a <code>CallGraph</code> using the specified 46 cananian 1.1.2.1 * <code>ClassHierarchy</code>. <code>hcf</code> must be a code 47 cananian 1.1.2.1 * factory that generates quad-ssi form. */ 48 cananian 1.1.2.1 public CallGraphImpl2(ClassHierarchy ch, HCodeFactory hcf) { 49 cananian 1.1.2.1 // this is maybe a little too draconian 50 cananian 1.3.2.1 assert hcf.getCodeName() 51 cananian 1.3.2.1 .equals(harpoon.IR.Quads.QuadSSI.codename); 52 cananian 1.1.2.1 this.ch = ch; 53 cananian 1.1.2.1 this.hcf = hcf; 54 cananian 1.1.2.1 } 55 cananian 1.1.2.1 56 cananian 1.1.2.1 /** Return a list of all possible methods called by this method. */ 57 cananian 1.1.2.1 public HMethod[] calls(final HMethod m) { 58 cananian 1.1.2.1 HMethod[] retval = (HMethod[]) cache.get(m); 59 cananian 1.1.2.1 if (retval==null) { 60 cananian 1.1.2.1 final Set s = new HashSet(); 61 cananian 1.1.2.1 final HCode hc = hcf.convert(m); 62 cananian 1.1.2.1 if (hc==null) { cache.put(m,new HMethod[0]); return calls(m); } 63 cananian 1.1.2.1 ExactTypeMap etm = new TypeInfo((harpoon.IR.Quads.QuadSSI)hc); 64 cananian 1.1.2.1 ReachingDefs rd = new SSxReachingDefsImpl(hc); 65 cananian 1.7 for (Object qO : getCallSites(m, hc)) { 66 cananian 1.7 CALL q = (CALL) qO; 67 cananian 1.1.2.1 HMethod cm = q.method(); 68 cananian 1.1.2.1 if (s.contains(cm)) continue; // duplicate. 69 cananian 1.1.2.1 s.addAll(Arrays.asList(calls((CALL)q, rd, etm))); 70 cananian 1.1.2.1 } 71 cananian 1.1.2.1 // finally, copy result vector to retval array. 72 cananian 1.1.2.1 retval = (HMethod[]) s.toArray(new HMethod[s.size()]); 73 cananian 1.1.2.1 // and cache result. 74 cananian 1.1.2.1 cache.put(m, retval); 75 cananian 1.1.2.1 } 76 cananian 1.1.2.1 return retval; 77 cananian 1.1.2.1 } 78 cananian 1.1.2.1 final private Map cache = new HashMap(); 79 cananian 1.1.2.1 80 cananian 1.1.2.1 /** Returns a List of all the <code>CALL</code>s quads in the code 81 cananian 1.1.2.1 of <code>hm</code> (in representation <code>hc</code>). */ 82 cananian 1.1.2.1 private List getCallSites(final HMethod hm, final HCode hc){ 83 cananian 1.1.2.1 if (hc==null) return Collections.EMPTY_LIST; 84 cananian 1.3.2.1 assert hc.getMethod().equals(hm); 85 cananian 1.1.2.1 if (cache_cs.containsKey(hc)) return (List) cache_cs.get(hc); 86 cananian 1.1.2.1 87 cananian 1.1.2.1 final Vector v = new Vector(); 88 cananian 1.1.2.1 for (Iterator it = hc.getElementsI(); it.hasNext(); ) { 89 cananian 1.1.2.1 Quad q = (Quad) it.next(); 90 cananian 1.1.2.1 if (q instanceof CALL) v.add(q); 91 cananian 1.1.2.1 } 92 cananian 1.1.2.1 cache_cs.put(hc, Collections.unmodifiableList(v)); 93 cananian 1.1.2.1 return getCallSites(hm, hc); 94 cananian 1.1.2.1 } 95 cananian 1.1.2.1 final private Map cache_cs = new HashMap(); 96 cananian 1.1.2.1 97 cananian 1.1.2.1 /** Return a list of all possible methods called by this method at 98 cananian 1.1.2.1 * a particular call site. */ 99 cananian 1.1.2.1 public HMethod[] calls(final CALL cs, 100 cananian 1.1.2.1 ReachingDefs rd, ExactTypeMap etm) { 101 cananian 1.1.2.1 HMethod cm = cs.method(); 102 cananian 1.1.2.1 // for 'special' invocations, we know the method exactly. 103 cananian 1.1.2.1 if ((!cs.isVirtual()) || cs.isStatic()) return new HMethod[]{ cm }; 104 cananian 1.1.2.1 // find type of receiver 105 cananian 1.1.2.1 Temp receiver = cs.params(0); 106 cananian 1.1.2.1 Quad def = (Quad) rd.reachingDefs(cs, receiver).iterator().next(); 107 cananian 1.1.2.1 HClass rtype = etm.typeMap(def, receiver); 108 cananian 1.1.2.1 // if the type is exact, we know the method exactly. 109 cananian 1.1.2.1 if (etm.isExactType(def, receiver)) 110 cananian 1.1.2.1 try { 111 cananian 1.1.2.1 return new HMethod[] 112 cananian 1.1.2.1 { rtype.getMethod(cm.getName(),cm.getDescriptor()) }; 113 cananian 1.1.2.1 } catch (NoSuchMethodError nsme) {//hm, no matching method. 114 cananian 1.1.2.1 return new HMethod[0]; 115 cananian 1.1.2.1 } 116 cananian 1.1.2.1 // otherwise, compute set of methods: 117 cananian 1.1.2.1 final Set s = new HashSet(); 118 cananian 1.1.2.1 // all methods of the type and its children are reachable. 119 cananian 1.1.2.1 WorkSet W = new WorkSet(); 120 cananian 1.1.2.1 W.add(rtype); 121 cananian 1.1.2.1 while (!W.isEmpty()) { 122 cananian 1.1.2.1 HClass c = (HClass) W.pop(); 123 cananian 1.1.2.1 // if this class can be instatiated, then its 124 cananian 1.1.2.1 // implementation of the method should be added to the set. 125 cananian 1.1.2.1 if (ch.instantiatedClasses().contains(c)) 126 cananian 1.1.2.1 try { 127 cananian 1.1.2.1 s.add(c.getMethod(cm.getName(), 128 cananian 1.1.2.1 cm.getDescriptor())); 129 cananian 1.1.2.1 } catch (NoSuchMethodError nsme) { } 130 cananian 1.1.2.1 // recurse through all children of this method's class. 131 cananian 1.1.2.1 for (Iterator it=ch.children(c).iterator(); it.hasNext(); ) 132 cananian 1.1.2.1 W.add(it.next()); 133 cananian 1.1.2.1 } 134 cananian 1.1.2.1 // finally, copy result vector to retval array. 135 cananian 1.1.2.1 return (HMethod[]) s.toArray(new HMethod[s.size()]); 136 cananian 1.1.2.1 } 137 cananian 1.1.2.1 138 cananian 1.1.2.1 /** Returns the set of all the methods that can be called in the 139 cananian 1.1.2.1 execution of the program. */ 140 cananian 1.1.2.1 public Set callableMethods(){ 141 cananian 1.1.2.1 return ch.callableMethods(); 142 cananian 1.1.2.1 } 143 cananian 1.1.2.1 144 cananian 1.2 }