1 cananian 1.1.2.1 // QuadClassHierarchy.java, created Sun Oct 11 13:08:31 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.16 import harpoon.ClassFile.HClass; 7 cananian 1.1.2.16 import harpoon.ClassFile.HCodeFactory; 8 cananian 1.1.2.16 import harpoon.ClassFile.HConstructor; 9 cananian 1.1.2.16 import harpoon.ClassFile.HField; 10 cananian 1.1.2.16 import harpoon.ClassFile.HMethod; 11 cananian 1.1.2.16 import harpoon.ClassFile.Linker; 12 cananian 1.1.2.16 import harpoon.IR.Quads.ANEW; 13 cananian 1.1.2.16 import harpoon.IR.Quads.CALL; 14 cananian 1.1.2.16 import harpoon.IR.Quads.CONST; 15 cananian 1.1.2.16 import harpoon.IR.Quads.Code; 16 cananian 1.1.2.16 import harpoon.IR.Quads.GET; 17 cananian 1.1.2.23 import harpoon.IR.Quads.HANDLER; 18 cananian 1.1.2.16 import harpoon.IR.Quads.INSTANCEOF; 19 cananian 1.1.2.16 import harpoon.IR.Quads.NEW; 20 cananian 1.1.2.16 import harpoon.IR.Quads.Quad; 21 cananian 1.1.2.28 import harpoon.IR.Quads.QuadVisitor; 22 cananian 1.1.2.16 import harpoon.IR.Quads.SET; 23 cananian 1.1.2.33 import harpoon.IR.Quads.TYPECAST; 24 cananian 1.1.2.20 import harpoon.IR.Quads.TYPESWITCH; 25 cananian 1.1.2.1 import harpoon.Util.ArraySet; 26 cananian 1.6 import net.cscott.jutil.Default; 27 cananian 1.1.2.3 import harpoon.Util.HClassUtil; 28 cananian 1.1.2.1 import harpoon.Util.Util; 29 cananian 1.1.2.34 import harpoon.Util.Collections.WorkSet; 30 cananian 1.1.2.1 31 cananian 1.1.2.12 import java.lang.reflect.Modifier; 32 cananian 1.1.2.12 33 cananian 1.1.2.8 import java.util.ArrayList; 34 cananian 1.1.2.4 import java.util.Arrays; 35 cananian 1.1.2.2 import java.util.Collection; 36 cananian 1.1.2.1 import java.util.Collections; 37 cananian 1.1.2.1 import java.util.HashSet; 38 cananian 1.1.2.1 import java.util.HashMap; 39 cananian 1.1.2.1 import java.util.Iterator; 40 cananian 1.1.2.8 import java.util.List; 41 cananian 1.1.2.1 import java.util.Map; 42 cananian 1.1.2.1 import java.util.Set; 43 cananian 1.1.2.1 /** 44 cananian 1.1.2.1 * <code>QuadClassHierarchy</code> computes a <code>ClassHierarchy</code> 45 cananian 1.1.2.1 * of classes possibly usable starting from some root method using 46 cananian 1.1.2.1 * quad form. 47 cananian 1.1.2.1 * Native methods are not analyzed. 48 cananian 1.1.2.1 * 49 cananian 1.1.2.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 50 cananian 1.7 * @version $Id: QuadClassHierarchy.java,v 1.7 2004/02/08 05:09:40 cananian Exp $ 51 cananian 1.1.2.1 */ 52 cananian 1.1.2.1 53 cananian 1.1.2.1 public class QuadClassHierarchy extends harpoon.Analysis.ClassHierarchy 54 cananian 1.1.2.1 implements java.io.Serializable { 55 cananian 1.3.2.2 private final Map<HClass,HClass[]> children = 56 cananian 1.3.2.2 new HashMap<HClass,HClass[]>(); 57 cananian 1.3.2.2 private final Set<HMethod> methods = new HashSet<HMethod>(); 58 cananian 1.1.2.1 59 cananian 1.1.2.1 /** Returns set of all callable methods. 60 cananian 1.1.2.1 @return <code>Set</code> of <code>HMethod</code>s. 61 cananian 1.1.2.1 */ 62 cananian 1.3.2.2 public Set<HMethod> callableMethods() { 63 cananian 1.1.2.1 return _unmod_methods; 64 cananian 1.1.2.1 } 65 cananian 1.3.2.2 private final Set<HMethod> _unmod_methods = 66 cananian 1.3.2.2 Collections.unmodifiableSet(methods); 67 cananian 1.1.2.1 68 cananian 1.1.2.22 // inherit description from parent class. 69 cananian 1.3.2.2 public Set<HClass> children(HClass c) { 70 cananian 1.1.2.1 if (children.containsKey(c)) 71 cananian 1.3.2.2 return new ArraySet<HClass>(children.get(c)); 72 cananian 1.3.2.2 return Default.EMPTY_SET(); 73 cananian 1.1.2.1 } 74 cananian 1.1.2.22 // inherit description from parent class. 75 cananian 1.3.2.2 public Set<HClass> classes() { 76 cananian 1.1.2.1 if (_classes == null) { 77 cananian 1.3.2.2 _classes = new HashSet<HClass>(); 78 cananian 1.3.2.2 for(Iterator<HClass> it = children.keySet().iterator(); 79 cananian 1.3.2.2 it.hasNext(); ) 80 cananian 1.1.2.1 _classes.add(it.next()); 81 cananian 1.7 for(HClass[] ch : children.values()) { 82 cananian 1.1.2.1 for (int i=0; i<ch.length; i++) 83 cananian 1.1.2.1 _classes.add(ch[i]); 84 cananian 1.1.2.1 } 85 cananian 1.1.2.1 _classes = Collections.unmodifiableSet(_classes); 86 cananian 1.1.2.1 } 87 cananian 1.1.2.1 return _classes; 88 cananian 1.1.2.1 } 89 cananian 1.3.2.2 private transient Set<HClass> _classes = null; 90 cananian 1.1.2.1 /** Returns the set of all classes instantiated. 91 cananian 1.1.2.1 (Actually only the list of classes for which an explicit NEW is found; 92 cananian 1.1.2.1 should include list of classes that are automatically created by JVM!) */ 93 cananian 1.3.2.2 public Set<HClass> instantiatedClasses() { 94 cananian 1.1.2.1 return _unmod_insted; 95 cananian 1.1.2.1 } 96 cananian 1.3.2.2 private final Set<HClass> instedClasses = new HashSet<HClass>(); 97 cananian 1.3.2.2 private final Set<HClass> _unmod_insted = 98 cananian 1.3.2.2 Collections.unmodifiableSet(instedClasses); 99 cananian 1.1.2.1 100 cananian 1.1.2.1 /** Returns a human-readable representation of the hierarchy. */ 101 cananian 1.1.2.1 public String toString() { 102 cananian 1.1.2.1 // not the most intuitive representation... 103 cananian 1.1.2.1 StringBuffer sb = new StringBuffer("{"); 104 cananian 1.3.2.2 for (Iterator<HClass> it=children.keySet().iterator(); it.hasNext(); ){ 105 cananian 1.3.2.2 HClass c = it.next(); 106 cananian 1.1.2.1 sb.append(c.toString()); 107 cananian 1.1.2.1 sb.append("={"); 108 cananian 1.3.2.2 for (Iterator<HClass> it2=children(c).iterator(); it2.hasNext(); ){ 109 cananian 1.1.2.1 sb.append(it2.next().toString()); 110 cananian 1.1.2.1 if (it2.hasNext()) 111 cananian 1.1.2.1 sb.append(','); 112 cananian 1.1.2.1 } 113 cananian 1.1.2.1 sb.append('}'); 114 cananian 1.1.2.1 if (it.hasNext()) 115 cananian 1.1.2.1 sb.append(", "); 116 cananian 1.1.2.1 } 117 cananian 1.1.2.1 sb.append('}'); 118 cananian 1.1.2.1 return sb.toString(); 119 cananian 1.1.2.1 } 120 cananian 1.1.2.1 121 cananian 1.1.2.15 ////// hclass objects 122 cananian 1.1.2.15 private final HMethod HMstrIntern; 123 cananian 1.1.2.15 private final HMethod HMthrStart; 124 cananian 1.1.2.15 private final HMethod HMthrRun; 125 cananian 1.1.2.15 private QuadClassHierarchy(Linker linker) { 126 cananian 1.1.2.15 HMstrIntern = linker.forName("java.lang.String") 127 cananian 1.1.2.15 .getMethod("intern",new HClass[0]); 128 cananian 1.1.2.15 HMthrStart = linker.forName("java.lang.Thread") 129 cananian 1.1.2.15 .getMethod("start", new HClass[0]); 130 cananian 1.1.2.15 HMthrRun = linker.forName("java.lang.Thread") 131 cananian 1.1.2.15 .getMethod("run", new HClass[0]); 132 cananian 1.1.2.2 } 133 cananian 1.1.2.15 134 cananian 1.1.2.1 /** Creates a <code>ClassHierarchy</code> of all classes 135 cananian 1.1.2.13 * reachable/usable from <code>HMethod</code>s in the <code>roots</code> 136 cananian 1.1.2.13 * <code>Collection</code>. <code>HClass</code>es included in 137 cananian 1.1.2.13 * <code>roots</code> are guaranteed to be included in the 138 cananian 1.1.2.13 * <code>classes()</code> set of this class hierarchy, but they may 139 cananian 1.1.2.13 * not be included in the <code>instantiatedClasses</code> set 140 cananian 1.1.2.13 * (if an instantiation instruction is not found for them). To 141 cananian 1.1.2.13 * explicitly include an instantiated class in the hierarchy, add 142 cananian 1.1.2.13 * a constructor or non-static method of that class to the 143 cananian 1.1.2.13 * <code>roots</code> <code>Collection</code>.<p> <code>hcf</code> 144 cananian 1.1.2.1 * must be a code factory that generates quad form. */ 145 cananian 1.1.2.15 public QuadClassHierarchy(Linker linker, 146 cananian 1.1.2.15 Collection roots, HCodeFactory hcf) { 147 cananian 1.1.2.15 this(linker); // initialize hclass objects. 148 cananian 1.1.2.22 if (hcf.getCodeName().equals(harpoon.IR.Quads.QuadWithTry.codename)) { 149 cananian 1.1.2.22 // add 'implicit' exceptions to root set when analyzing QuadWithTry 150 cananian 1.1.2.22 String[] implExcName = new String[] { 151 cananian 1.1.2.22 "java.lang.ArrayStoreException", 152 cananian 1.1.2.22 "java.lang.NullPointerException", 153 cananian 1.1.2.22 "java.lang.ArrayIndexOutOfBoundsException", 154 cananian 1.1.2.22 "java.lang.NegativeArraySizeException", 155 cananian 1.1.2.22 "java.lang.ArithmeticException", 156 cananian 1.1.2.22 "java.lang.ClassCastException" 157 cananian 1.1.2.22 }; 158 cananian 1.1.2.22 roots = new HashSet(roots); // make mutable 159 cananian 1.1.2.22 for (int i=0; i<implExcName.length; i++) 160 cananian 1.1.2.22 roots.add(linker.forName(implExcName[i]) 161 cananian 1.1.2.22 .getConstructor(new HClass[0])); 162 cananian 1.1.2.22 } 163 cananian 1.1.2.1 // state. 164 cananian 1.1.2.28 final State S = new State(); 165 cananian 1.1.2.1 166 cananian 1.1.2.13 // make initial worklist from roots collection. 167 cananian 1.1.2.2 for (Iterator it=roots.iterator(); it.hasNext(); ) { 168 cananian 1.1.2.13 HClass rootC; HMethod rootM; boolean instantiated; 169 cananian 1.1.2.13 // deal with the different types of objects in the roots collection 170 cananian 1.1.2.13 Object o = it.next(); 171 cananian 1.1.2.13 if (o instanceof HMethod) { 172 cananian 1.1.2.13 rootM = (HMethod) o; 173 cananian 1.1.2.13 rootC = rootM.getDeclaringClass(); 174 cananian 1.1.2.13 // let's assume non-static roots have objects to go with 'em. 175 cananian 1.1.2.13 instantiated = !rootM.isStatic(); 176 cananian 1.1.2.13 } else { // only HMethods and HClasses in roots, so must be HClass 177 cananian 1.1.2.13 rootM = null; 178 cananian 1.1.2.13 rootC = (HClass) o; 179 cananian 1.3.2.5 // no methods of an array. so mention of an array means 180 cananian 1.3.2.5 // it is instantiated. otherwise, it's not. 181 cananian 1.3.2.5 instantiated = rootC.isArray(); 182 cananian 1.1.2.13 } 183 cananian 1.1.2.13 if (instantiated) 184 cananian 1.1.2.27 discoverInstantiatedClass(S, rootC); 185 cananian 1.1.2.13 else 186 cananian 1.1.2.27 discoverClass(S, rootC); 187 cananian 1.1.2.13 if (rootM!=null) 188 cananian 1.1.2.27 methodPush(S, rootM); 189 cananian 1.1.2.2 } 190 cananian 1.1.2.13 191 cananian 1.1.2.13 // worklist algorithm. 192 cananian 1.1.2.27 while (!S.W.isEmpty()) { 193 cananian 1.3.2.2 HMethod m = S.W.pull(); 194 cananian 1.1.2.27 S.done.add(m); // mark us done with this method. 195 cananian 1.1.2.1 // This method should be marked as usable. 196 cananian 1.1.2.1 { 197 cananian 1.3.2.2 Set<HMethod> s = S.classMethodsUsed.get(m.getDeclaringClass()); 198 cananian 1.3.2.1 assert s!=null; 199 cananian 1.3.2.1 assert s.contains(m); 200 cananian 1.1.2.1 } 201 cananian 1.1.2.1 // look at the hcode for the method. 202 cananian 1.1.2.1 harpoon.IR.Quads.Code hc = (harpoon.IR.Quads.Code) hcf.convert(m); 203 cananian 1.1.2.1 if (hc==null) { // native or unanalyzable method. 204 cananian 1.3.2.4 if(!m.getReturnType().isPrimitive() && 205 cananian 1.3.2.4 !m.getReturnType().isInterface()) 206 cananian 1.1.2.9 // be safe; assume the native method can make an object 207 cananian 1.1.2.9 // of its return type. 208 cananian 1.1.2.27 discoverInstantiatedClass(S, m.getReturnType()); 209 cananian 1.1.2.2 } else { // look for CALLs, NEWs, and ANEWs 210 cananian 1.1.2.28 QuadVisitor qv = new QuadVisitor() { 211 cananian 1.1.2.28 public void visit(Quad q) { /* do nothing */ } 212 cananian 1.1.2.28 // creation of a (possibly-new) class 213 cananian 1.1.2.28 public void visit(ANEW q) { 214 cananian 1.1.2.28 discoverInstantiatedClass(S, q.hclass()); 215 cananian 1.1.2.28 } 216 cananian 1.1.2.28 public void visit(NEW q) { 217 cananian 1.1.2.28 discoverInstantiatedClass(S, q.hclass()); 218 cananian 1.1.2.28 } 219 cananian 1.1.2.28 public void visit(CONST q) { 220 cananian 1.1.2.28 if (q.type().isPrimitive()) return; 221 cananian 1.1.2.28 discoverInstantiatedClass(S, q.type()); 222 cananian 1.5 if (q.type().getName().equals("java.lang.String")) 223 cananian 1.5 // string constants use intern() 224 cananian 1.5 discoverMethod(S,HMstrIntern,false/*non-virtual*/); 225 cananian 1.5 if (q.type().getName().equals("java.lang.Class")) 226 cananian 1.5 discoverClass(S, (HClass) q.value()); 227 cananian 1.5 if (q.type().getName().equals("java.lang.reflect.Field")) 228 cananian 1.5 discoverClass(S, ((HField) q.value()).getDeclaringClass()); 229 cananian 1.5 if (q.type().getName().equals("java.lang.reflect.Method")) 230 cananian 1.5 discoverClass(S, ((HMethod) q.value()).getDeclaringClass()); 231 cananian 1.1.2.28 } 232 cananian 1.1.2.28 // CALLs: 233 cananian 1.1.2.28 public void visit(CALL q) { 234 cananian 1.1.2.1 if (q.isStatic() || !q.isVirtual()) 235 cananian 1.1.2.29 discoverMethod(S, q.method(),false/*non-virtual*/); 236 cananian 1.1.2.1 else 237 cananian 1.1.2.29 discoverMethod(S, q.method(),true/*virtual*/); 238 cananian 1.1.2.1 } 239 cananian 1.1.2.7 // get and set discover classes (don't instantiate, though) 240 cananian 1.1.2.28 public void visit(GET q) { 241 cananian 1.1.2.28 discoverClass(S, q.field().getDeclaringClass()); 242 cananian 1.1.2.28 } 243 cananian 1.1.2.28 public void visit(SET q) { 244 cananian 1.1.2.28 discoverClass(S, q.field().getDeclaringClass()); 245 cananian 1.1.2.7 } 246 cananian 1.1.2.8 // make sure we have the class we're testing against 247 cananian 1.1.2.8 // handy. 248 cananian 1.1.2.28 public void visit(INSTANCEOF q) { 249 cananian 1.1.2.33 discoverClass(S, q.hclass()); 250 cananian 1.1.2.33 } 251 cananian 1.1.2.33 public void visit(TYPECAST q) { 252 cananian 1.1.2.28 discoverClass(S, q.hclass()); 253 cananian 1.1.2.20 } 254 cananian 1.1.2.28 public void visit(TYPESWITCH q) { 255 cananian 1.1.2.20 for (int i=0; i<q.keysLength(); i++) 256 cananian 1.1.2.27 discoverClass(S, q.keys(i)); 257 cananian 1.1.2.23 } 258 cananian 1.1.2.28 public void visit(HANDLER q) { 259 cananian 1.1.2.28 if (q.caughtException()==null) return; 260 cananian 1.1.2.28 discoverClass(S, q.caughtException()); 261 cananian 1.1.2.8 } 262 cananian 1.1.2.28 }; 263 cananian 1.1.2.28 // iterate through quads with visitor. 264 cananian 1.3.2.2 for (Iterator<Quad> it = hc.getElementsI(); it.hasNext(); ) 265 cananian 1.3.2.2 it.next().accept(qv); 266 cananian 1.1.2.1 } 267 cananian 1.1.2.1 } // END worklist. 268 cananian 1.1.2.1 269 cananian 1.1.2.3 // build method table from classMethodsUsed. 270 cananian 1.3.2.2 for (Iterator<Set<HMethod>> it= S.classMethodsUsed.values().iterator(); 271 cananian 1.1.2.4 it.hasNext(); ) 272 cananian 1.3.2.2 methods.addAll(it.next()); 273 cananian 1.1.2.3 // now generate children set from classKnownChildren. 274 cananian 1.7 for (HClass c : S.classKnownChildren.keySet()) { 275 cananian 1.3.2.2 Set<HClass> s = S.classKnownChildren.get(c); 276 cananian 1.3.2.2 HClass ch[] = s.toArray(new HClass[s.size()]); 277 cananian 1.1.2.1 children.put(c, ch); 278 cananian 1.1.2.1 } 279 cananian 1.1.2.1 } 280 cananian 1.1.2.1 281 cananian 1.1.2.1 /* when we discover a new class nc: 282 cananian 1.1.2.1 for each superclass c or superinterface i of this class, 283 cananian 1.1.2.1 add all called methods of c/i to worklist of nc, if nc implements. 284 cananian 1.1.2.1 */ 285 cananian 1.1.2.27 private void discoverClass(State S, HClass c) { 286 cananian 1.1.2.27 if (S.classKnownChildren.containsKey(c)) return; // not a new class. 287 cananian 1.1.2.1 // add to known-children lists. 288 cananian 1.3.2.1 assert !S.classKnownChildren.containsKey(c); 289 cananian 1.1.2.27 S.classKnownChildren.put(c, new HashSet()); 290 cananian 1.3.2.1 assert !S.classMethodsUsed.containsKey(c); 291 cananian 1.1.2.27 S.classMethodsUsed.put(c, new HashSet()); 292 cananian 1.3.2.1 assert !S.classMethodsPending.containsKey(c); 293 cananian 1.1.2.27 S.classMethodsPending.put(c, new HashSet()); 294 cananian 1.1.2.4 // add class initializer (if it exists) to "called" methods. 295 cananian 1.1.2.4 HMethod ci = c.getClassInitializer(); 296 cananian 1.1.2.27 if ((ci!=null) && (!S.done.contains(ci))) 297 cananian 1.1.2.27 methodPush(S, ci); 298 cananian 1.1.2.22 // mark component type of arrays 299 cananian 1.1.2.22 if (c.isArray()) 300 cananian 1.1.2.27 discoverClass(S, c.getComponentType()); 301 cananian 1.1.2.22 // work through parents (superclass and interfaces) 302 cananian 1.7 for (Object pO : parents(c)) { 303 cananian 1.7 HClass p = (HClass) pO; 304 cananian 1.1.2.27 discoverClass(S, p); 305 cananian 1.3.2.2 Set<HClass> knownChildren = S.classKnownChildren.get(p); 306 cananian 1.1.2.1 knownChildren.add(c); // kC non-null after discoverClass. 307 cananian 1.1.2.1 } 308 cananian 1.1.2.4 } 309 cananian 1.1.2.27 private void discoverInstantiatedClass(State S, HClass c) { 310 cananian 1.1.2.4 if (instedClasses.contains(c)) return; else instedClasses.add(c); 311 cananian 1.1.2.27 discoverClass(S, c); 312 salcianu 1.1.2.26 313 cananian 1.1.2.4 // collect superclasses and interfaces. 314 cananian 1.1.2.4 // new worklist. 315 cananian 1.3.2.2 WorkSet<HClass> sW = new WorkSet<HClass>(); 316 cananian 1.1.2.4 // put superclass and interfaces on worklist. 317 cananian 1.1.2.22 sW.addAll(parents(c)); 318 cananian 1.1.2.1 319 cananian 1.1.2.4 // first, wake up all methods of this class that were 320 cananian 1.1.2.4 // pending instantiation, and clear the pending list. 321 cananian 1.3.2.2 List<HMethod> ml = 322 cananian 1.3.2.2 new ArrayList<HMethod>(S.classMethodsPending.get(c));//copy list 323 cananian 1.3.2.2 for (Iterator<HMethod> it=ml.iterator(); it.hasNext(); ) 324 cananian 1.3.2.2 methodPush(S, it.next()); 325 cananian 1.1.2.4 326 cananian 1.1.2.4 // if instantiated, 327 cananian 1.1.2.1 // add all called methods of superclasses/interfaces to worklist. 328 cananian 1.1.2.1 while (!sW.isEmpty()) { 329 cananian 1.1.2.1 // pull a superclass or superinterface off the list. 330 cananian 1.3.2.2 HClass s = sW.pop(); 331 cananian 1.1.2.1 // add superclasses/interfaces of this one to local worklist 332 cananian 1.1.2.22 sW.addAll(parents(s)); 333 cananian 1.1.2.1 // now add called methods of s to top-level worklist. 334 cananian 1.3.2.2 Set<HMethod> calledMethods = 335 cananian 1.3.2.2 new WorkSet<HMethod>(S.classMethodsUsed.get(s)); 336 cananian 1.3.2.2 calledMethods.addAll(S.classMethodsPending.get(s)); 337 cananian 1.7 for (HMethod m : calledMethods){ 338 cananian 1.1.2.12 if (!isVirtual(m)) continue; // not inheritable. 339 cananian 1.1.2.1 try { 340 cananian 1.1.2.4 HMethod nm = c.getMethod(m.getName(), 341 cananian 1.1.2.4 m.getDescriptor()); 342 cananian 1.1.2.27 if (!S.done.contains(nm)) 343 cananian 1.1.2.27 methodPush(S, nm); 344 cananian 1.1.2.1 } catch (NoSuchMethodError nsme) { } 345 cananian 1.1.2.1 } 346 cananian 1.1.2.1 } 347 cananian 1.1.2.1 // done with this class/interface. 348 cananian 1.1.2.1 } 349 cananian 1.1.2.1 /* when we hit a method call site (method in class c): 350 cananian 1.1.2.1 add method of c and all children of c to worklist. 351 cananian 1.1.2.1 if method in interface i: 352 cananian 1.1.2.1 add method of c and all implementations of c. 353 cananian 1.1.2.1 */ 354 cananian 1.1.2.29 private void discoverMethod(State S, HMethod m, boolean isVirtual) { 355 cananian 1.1.2.29 if (isVirtual && S.nonvirtual.contains(m)) { 356 cananian 1.1.2.29 // this is the first virtual invocation of a previously 357 cananian 1.1.2.29 // nonvirtual method. 358 cananian 1.1.2.30 // [removing m from S.nonvirtual will be done below, 359 cananian 1.1.2.30 // near the call to methodPush(S, nm)] 360 cananian 1.1.2.29 } else if (S.done.contains(m) || S.W.contains(m)) { 361 cananian 1.1.2.29 // we've done this guy before 362 cananian 1.1.2.29 return; 363 cananian 1.1.2.29 } 364 cananian 1.1.2.27 discoverClass(S, m.getDeclaringClass()); 365 cananian 1.1.2.14 // Thread.start() implicitly causes a call to Thread.run() 366 cananian 1.1.2.14 if (m.equals(HMthrStart)) 367 cananian 1.1.2.29 discoverMethod(S, HMthrRun, true/*virtual*/); 368 cananian 1.1.2.29 if (!isVirtual) { // short-cut for non-virtual methods. 369 cananian 1.1.2.29 S.nonvirtual.add(m); 370 cananian 1.1.2.29 methodPush(S, m); 371 cananian 1.1.2.29 return; // that's all folks. 372 cananian 1.1.2.29 } 373 cananian 1.1.2.32 // mark as pending in its own class if not already used. 374 cananian 1.3.2.2 if (!S.classMethodsUsed.get(m.getDeclaringClass()).contains(m)) 375 cananian 1.3.2.2 S.classMethodsPending.get(m.getDeclaringClass()).add(m); 376 cananian 1.1.2.4 // now add as 'used' to all instantiated children. 377 cananian 1.1.2.4 // (including itself, if its own class has been instantiated) 378 cananian 1.3.2.2 WorkSet<HClass> cW = new WorkSet<HClass>(); 379 cananian 1.1.2.1 cW.push(m.getDeclaringClass()); 380 cananian 1.1.2.1 while (!cW.isEmpty()) { 381 cananian 1.1.2.1 // pull a class from the worklist 382 cananian 1.3.2.2 HClass c = cW.pull(); 383 cananian 1.1.2.1 // see if we should add method-of-c to method worklist. 384 cananian 1.1.2.11 if (c.isInterface() || instedClasses.contains(c)) 385 cananian 1.1.2.4 try { 386 cananian 1.1.2.4 HMethod nm = c.getMethod(m.getName(), 387 cananian 1.1.2.4 m.getDescriptor()); 388 cananian 1.3.2.1 assert isVirtual; // shouldn't be here otherwise. 389 cananian 1.1.2.30 if (!S.done.contains(nm)) 390 cananian 1.1.2.30 methodPush(S, nm); 391 cananian 1.1.2.32 else if (!S.nonvirtual.contains(nm)) 392 cananian 1.1.2.32 continue; // nothing new to discover. 393 cananian 1.1.2.32 else S.nonvirtual.remove(nm); // since we're virtual here. 394 cananian 1.1.2.4 } catch (NoSuchMethodError e) { } 395 cananian 1.1.2.1 // add all children to the worklist. 396 cananian 1.3.2.2 Set<HClass> knownChildren = S.classKnownChildren.get(c); 397 cananian 1.3.2.2 for (Iterator<HClass> it=knownChildren.iterator(); it.hasNext(); ) 398 cananian 1.1.2.1 cW.push(it.next()); 399 cananian 1.1.2.1 } 400 cananian 1.1.2.1 // done. 401 cananian 1.1.2.1 } 402 cananian 1.1.2.14 403 cananian 1.1.2.27 private void methodPush(State S, HMethod m) { 404 cananian 1.3.2.1 assert !S.done.contains(m); 405 cananian 1.1.2.27 if (S.W.contains(m)) return; // already on work list. 406 cananian 1.1.2.1 // Add to worklist 407 cananian 1.1.2.27 S.W.add(m); 408 cananian 1.1.2.4 // mark this method as used. 409 cananian 1.3.2.2 Set<HMethod> s1 = S.classMethodsUsed.get(m.getDeclaringClass()); 410 cananian 1.1.2.4 s1.add(m); 411 cananian 1.1.2.4 // and no longer pending. 412 cananian 1.3.2.2 Set<HMethod> s2 = S.classMethodsPending.get(m.getDeclaringClass()); 413 cananian 1.1.2.4 s2.remove(m); 414 cananian 1.1.2.27 } 415 cananian 1.1.2.27 // State for algorithm. 416 cananian 1.1.2.27 private static class State { 417 cananian 1.1.2.27 // keeps track of methods which are actually invoked at some point. 418 cananian 1.3.2.2 final Map<HClass,Set<HMethod>> classMethodsUsed 419 cananian 1.3.2.2 = new HashMap<HClass,Set<HMethod>>(); // class->set map. 420 cananian 1.1.2.27 // keeps track of methods which might be called, if someone gets 421 cananian 1.1.2.27 // around to instantiating an object of the proper type. 422 cananian 1.3.2.2 final Map<HClass,Set<HMethod>> classMethodsPending 423 cananian 1.3.2.2 = new HashMap<HClass,Set<HMethod>>(); // class->set map 424 cananian 1.1.2.27 // keeps track of all known children of a given class. 425 cananian 1.3.2.2 final Map<HClass,Set<HClass>> classKnownChildren 426 cananian 1.3.2.2 = new HashMap<HClass,Set<HClass>>(); // class->set map. 427 cananian 1.1.2.27 // keeps track of which methods we've done already. 428 cananian 1.3.2.2 final Set<HMethod> done = new HashSet<HMethod>(); 429 cananian 1.1.2.29 // keeps track of methods we've only seen non-virtual invocations for. 430 cananian 1.3.2.2 final Set<HMethod> nonvirtual = new HashSet<HMethod>(); 431 cananian 1.1.2.27 432 cananian 1.1.2.27 // Worklist. 433 cananian 1.3.2.2 final WorkSet<HMethod> W = new WorkSet<HMethod>(); 434 cananian 1.1.2.12 } 435 cananian 1.1.2.12 436 cananian 1.1.2.12 // useful utility method 437 cananian 1.1.2.12 private static boolean isVirtual(HMethod m) { 438 cananian 1.1.2.12 if (m.isStatic()) return false; 439 cananian 1.1.2.12 if (Modifier.isPrivate(m.getModifiers())) return false; 440 cananian 1.1.2.12 if (m instanceof HConstructor) return false; 441 cananian 1.1.2.12 return true; 442 cananian 1.1.2.1 } 443 cananian 1.1.2.1 444 cananian 1.1.2.1 /* ALGORITHM: 445 cananian 1.1.2.1 for each class: 446 cananian 1.1.2.1 table of all methods used in that class. 447 cananian 1.1.2.1 list of known immediate children of the class. 448 cananian 1.1.2.1 when we discover a new class nc: 449 cananian 1.1.2.1 for each superclass c of this class, 450 cananian 1.1.2.1 add all called methods of c to worklist of nc, if nc implements. 451 cananian 1.1.2.1 when we hit a method call site (method in class c): 452 cananian 1.1.2.1 add method of c and all children of c to worklist. 453 cananian 1.1.2.1 for each method on worklist: 454 cananian 1.1.2.1 mark method as used in class. 455 cananian 1.1.2.1 for each NEW: add possibly new class. 456 cananian 1.1.2.1 for each CALL: add possibly new methods. 457 cananian 1.1.2.1 */ 458 cananian 1.2 }