1 cananian 1.1.4.1 // ClassMethodMap.java, created Fri Oct 8 15:06:25 1999 by cananian 2 cananian 1.1.4.1 // Copyright (C) 1999 C. Scott Ananian <cananian@alumni.princeton.edu> 3 cananian 1.1.4.1 // Licensed under the terms of the GNU GPL; see COPYING for details. 4 cananian 1.1.4.1 package harpoon.Backend.Analysis; 5 cananian 1.1.4.1 6 cananian 1.1.4.1 import harpoon.Backend.Maps.MethodMap; 7 cananian 1.1.4.1 import harpoon.ClassFile.HClass; 8 cananian 1.1.4.1 import harpoon.ClassFile.HConstructor; 9 cananian 1.1.4.1 import harpoon.ClassFile.HMethod; 10 cananian 1.1.4.1 import harpoon.Util.Util; 11 cananian 1.1.4.1 12 cananian 1.1.4.1 import java.lang.reflect.Modifier; 13 cananian 1.1.4.1 import java.util.ArrayList; 14 cananian 1.1.4.1 import java.util.Collections; 15 cananian 1.1.4.1 import java.util.HashMap; 16 cananian 1.1.4.1 import java.util.HashSet; 17 cananian 1.1.4.1 import java.util.Iterator; 18 cananian 1.1.4.1 import java.util.List; 19 cananian 1.1.4.1 import java.util.Map; 20 cananian 1.1.4.1 import java.util.Set; 21 cananian 1.1.4.1 22 cananian 1.1.4.1 /** 23 cananian 1.1.4.1 * A <code>ClassMethodMap</code> is a method map for virtual methods of 24 cananian 1.1.4.1 * an object (not static, not private, not constructors). It uses the 25 cananian 1.1.4.1 * natural ordering (under <code>Comparable</code> of the methods when 26 cananian 1.1.4.1 * possible and caches results for efficiency. 27 cananian 1.1.4.1 * 28 cananian 1.1.4.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 29 cananian 1.4 * @version $Id: ClassMethodMap.java,v 1.4 2002/04/10 03:02:22 cananian Exp $ 30 cananian 1.1.4.1 */ 31 cananian 1.1.4.1 public class ClassMethodMap extends MethodMap { 32 cananian 1.1.4.1 33 cananian 1.1.4.1 /** Creates a <code>ClassMethodMap</code>. */ 34 cananian 1.1.4.1 public ClassMethodMap() { /* no special initialization. */ } 35 cananian 1.1.4.1 36 cananian 1.1.4.1 public int methodOrder(HMethod hm) { 37 cananian 1.1.4.1 // method must be a virtual class method and thus 38 cananian 1.1.4.1 // 1) not an interface method 39 cananian 1.1.4.1 // 2) not static, not private, and not a constructor. 40 cananian 1.3.2.1 assert !hm.isInterfaceMethod(); 41 cananian 1.3.2.1 assert isVirtual(hm); 42 cananian 1.1.4.1 // check cache first. 43 cananian 1.1.4.1 if (cache.containsKey(hm)) return ((Integer)cache.get(hm)).intValue(); 44 cananian 1.1.4.1 // we actually compute numbers for a whole class at a time. 45 cananian 1.1.4.1 HClass hc = hm.getDeclaringClass(); 46 cananian 1.1.4.1 HClass sc = hc.getSuperclass(); 47 cananian 1.1.4.1 HMethod[] prenumbered = (sc==null)?new HMethod[0]:sc.getMethods(); 48 cananian 1.1.4.1 HMethod[] tobenumbered= hc.getMethods(); 49 cananian 1.1.4.1 int prenonstatic=0, tobenonstatic=0; 50 cananian 1.1.4.1 // identify and remove methods matching signatures of methods 51 cananian 1.1.4.1 // already numbered (because they belong to the parent) 52 cananian 1.1.4.1 Map presigs = new HashMap(); 53 cananian 1.1.4.1 for (int i=0; i<prenumbered.length; i++) { 54 cananian 1.1.4.1 if (!isVirtual(prenumbered[i])) continue; 55 cananian 1.1.4.1 // not static, not private, and not a constructor... 56 cananian 1.1.4.1 prenonstatic++; 57 cananian 1.1.4.1 String sig = prenumbered[i].getName() + 58 cananian 1.1.4.1 prenumbered[i].getDescriptor(); 59 cananian 1.1.4.1 presigs.put(sig, prenumbered[i]); 60 cananian 1.1.4.1 } 61 cananian 1.1.4.1 // create remainder list of class-local (not inherited) methods. 62 cananian 1.1.4.1 // (also filter out static methods) 63 cananian 1.1.4.1 List remainder = new ArrayList(); 64 cananian 1.1.4.1 for (int i=0; i<tobenumbered.length; i++) { 65 cananian 1.1.4.1 if (!isVirtual(tobenumbered[i])) continue; 66 cananian 1.1.4.1 // not static, not private, and not a constructor... 67 cananian 1.1.4.1 tobenonstatic++; 68 cananian 1.1.4.1 String sig = tobenumbered[i].getName() + 69 cananian 1.1.4.1 tobenumbered[i].getDescriptor(); 70 cananian 1.1.4.1 if (!presigs.containsKey(sig)) 71 cananian 1.1.4.1 remainder.add(tobenumbered[i]); 72 cananian 1.1.4.1 else if (!cache.containsKey(tobenumbered[i])) 73 cananian 1.1.4.1 // number inherited methods the same way they are numbered 74 cananian 1.1.4.1 // in the parent. 75 cananian 1.1.4.1 cache.put(tobenumbered[i], 76 cananian 1.1.4.1 new Integer(methodOrder((HMethod)presigs.get(sig)))); 77 cananian 1.1.4.1 } 78 cananian 1.1.4.1 // now sort the class-local methods 79 cananian 1.1.4.1 Collections.sort(remainder); 80 cananian 1.1.4.1 // and make a coherent numbering. 81 cananian 1.1.4.1 int num = prenonstatic; 82 cananian 1.1.4.1 for (Iterator it=remainder.iterator(); it.hasNext(); ) 83 cananian 1.1.4.1 cache.put(it.next(), new Integer(num++)); 84 cananian 1.3.2.1 assert num==tobenonstatic : num + "!=" + tobenonstatic; 85 cananian 1.1.4.1 // by this point the method should have a numbering in the cache. 86 cananian 1.1.4.1 return ((Integer)cache.get(hm)).intValue(); 87 cananian 1.1.4.1 } 88 cananian 1.1.4.1 private final Map cache = new HashMap(); 89 cananian 1.1.4.1 90 cananian 1.1.4.1 /** Determine if a method is "virtual" -- that is, handled by this 91 cananian 1.1.4.1 * map (and included in the class dispatch table). */ 92 cananian 1.1.4.1 private static boolean isVirtual(HMethod hm) { 93 cananian 1.1.4.1 if (hm.isStatic()) return false; 94 cananian 1.1.4.1 if (Modifier.isPrivate(hm.getModifiers())) return false; 95 cananian 1.1.4.1 if (hm instanceof HConstructor) return false; 96 cananian 1.1.4.1 return true; 97 cananian 1.1.4.1 } 98 cananian 1.2 }