1 cananian 1.1.4.1 // Linker.java, created Mon Dec 27 18:54:16 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.ClassFile; 5 cananian 1.1.4.1 6 cananian 1.7 import net.cscott.jutil.ReferenceUnique; 7 cananian 1.1.4.1 import harpoon.Util.Util; 8 cananian 1.1.4.1 9 cananian 1.1.4.1 import java.util.HashMap; 10 cananian 1.1.4.1 import java.util.Map; 11 cananian 1.1.4.1 /** 12 cananian 1.1.4.1 * A <code>Linker</code> object manages the association of symbolic names 13 cananian 1.1.4.1 * to code/data/object descriptions. 14 cananian 1.1.4.1 * 15 cananian 1.1.4.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 16 cananian 1.7 * @version $Id: Linker.java,v 1.7 2004/02/08 01:58:03 cananian Exp $ 17 cananian 1.1.4.1 */ 18 cananian 1.1.4.1 public abstract class Linker implements ReferenceUnique { 19 cananian 1.1.4.1 protected Linker() { } 20 cananian 1.1.4.1 /** private linker cache, for efficiency. */ 21 cananian 1.1.4.1 protected final Map descCache = new HashMap(); 22 cananian 1.1.4.1 /** 23 cananian 1.1.4.1 * Synthetic classes will use this hook to register themselves in 24 cananian 1.1.4.1 * the namespace of this <code>Linker</code>. <b>The given class 25 cananian 1.1.4.1 * <code>hc</code> must be unique in the namespace of this linker. 26 cananian 1.1.4.1 * Not to be used if the <code>Linker</code> already contains a class 27 cananian 1.1.4.1 * with the same descriptor.</b> Use <code>Relinker</code> to do 28 cananian 1.1.4.1 * global replacement of classes. 29 cananian 1.1.4.1 * @see Relinker.relink 30 cananian 1.1.4.1 * @see uniqueName 31 cananian 1.1.4.1 */ 32 cananian 1.1.4.1 void register(HClass hc) { 33 cananian 1.3.2.1 assert hc.getLinker()==this; 34 cananian 1.3.2.1 assert !descCache.containsKey(hc.getDescriptor()); 35 cananian 1.1.4.1 descCache.put(hc.getDescriptor(), hc); 36 cananian 1.1.4.1 } 37 cananian 1.1.4.1 38 cananian 1.1.4.1 /** 39 cananian 1.1.4.1 * Sub-classes will provide implementation for the 40 cananian 1.1.4.1 * <code>forDescriptor0</code> method in order to implement 41 cananian 1.1.4.1 * a linking strategy. This method is only passed descriptors for 42 cananian 1.1.4.1 * class types; never array or primitive type descriptors. 43 cananian 1.1.4.1 * (Hence neither primitive types or array types can be 44 cananian 1.1.4.1 * re-linked, which might violate java language semantics.) 45 cananian 1.1.4.1 * @exception NoSuchClassException 46 cananian 1.1.4.1 * if the class could not be found. 47 cananian 1.1.4.1 */ 48 cananian 1.1.4.1 protected abstract HClass forDescriptor0(String descriptor) 49 cananian 1.1.4.1 throws NoSuchClassException; 50 cananian 1.1.4.1 51 cananian 1.1.4.1 /** 52 cananian 1.1.4.1 * Returns the <code>HClass</code> object associated with the 53 cananian 1.1.4.1 * ComponentType descriptor given. Throws <code>NoSuchClassException</code> 54 cananian 1.1.4.1 * if the descriptor references a class that cannot be found. Throws 55 cananian 1.1.4.1 * <code>Error</code> if an invalid descriptor is given. 56 cananian 1.1.4.1 * @exception Error 57 cananian 1.1.4.1 * if an invalid descriptor is given. 58 cananian 1.1.4.1 * @exception NoSuchClassException 59 cananian 1.1.4.1 * if the class could not be found. 60 cananian 1.1.4.1 */ 61 cananian 1.5 public HClass forDescriptor(String descriptor) 62 cananian 1.1.4.1 throws NoSuchClassException { 63 cananian 1.3.2.1 assert descriptor.indexOf('.')==-1; // should be desc, not name. 64 cananian 1.1.4.1 // Trim descriptor. 65 cananian 1.1.4.1 int i; 66 cananian 1.1.4.1 for (i=0; i<descriptor.length(); i++) { 67 cananian 1.1.4.1 char c = descriptor.charAt(i); 68 cananian 1.1.4.1 if (c=='(' || c==')') throw new Error("Bad Descriptor: "+descriptor); 69 cananian 1.1.4.1 if (c=='[') continue; 70 cananian 1.1.4.1 if (c=='L') i = descriptor.indexOf(';', i); 71 cananian 1.1.4.1 break; 72 cananian 1.1.4.1 } 73 cananian 1.1.4.1 descriptor = descriptor.substring(0, i+1); 74 cananian 1.1.4.1 // Check the cache and ensure uniqueness. 75 cananian 1.1.4.1 HClass cls = (HClass) descCache.get(descriptor); 76 cananian 1.1.4.1 if (cls==null) { // not in the cache. 77 cananian 1.1.4.1 cls = _forDescriptor_(descriptor); // do actual descriptor resolution. 78 cananian 1.3.2.1 assert !descCache.containsKey(descriptor); 79 cananian 1.3.2.1 assert descriptor.equals(cls.getDescriptor()) : "The given class name does not match the class' idea of its name\n" 80 witchel 1.1.4.5 + "Try giving the full name to -c" 81 witchel 1.1.4.5 + "\nDescriptor " + descriptor + "\ncls " + cls 82 cananian 1.3.2.1 + "\ncls descriptor " + cls.getDescriptor(); 83 cananian 1.1.4.1 descCache.put(descriptor, cls); 84 cananian 1.1.4.1 } 85 cananian 1.1.4.1 return cls; 86 cananian 1.1.4.1 } 87 cananian 1.1.4.1 // helper function for the above; split apart to make the caching 88 cananian 1.1.4.1 // behavior of the above clearer. 89 cananian 1.1.4.1 private HClass _forDescriptor_(String descriptor) 90 cananian 1.1.4.1 throws NoSuchClassException { 91 cananian 1.1.4.1 switch(descriptor.charAt(0)) { 92 cananian 1.1.4.1 case '[': // arrays. 93 cananian 1.1.4.1 { 94 cananian 1.1.4.1 // count dimensions 95 cananian 1.1.4.1 int d; 96 cananian 1.1.4.1 for (d=0; d<descriptor.length(); d++) 97 cananian 1.1.4.1 if (descriptor.charAt(d)!='[') 98 cananian 1.1.4.1 break; 99 cananian 1.1.4.1 // recurse to fetch base type. 100 cananian 1.1.4.1 HClass basetype = forDescriptor(descriptor.substring(d)); 101 cananian 1.1.4.1 // make it. 102 cananian 1.1.4.4 HClass arraytype = makeArray(basetype, d); 103 cananian 1.3.2.1 assert arraytype.getDescriptor().equals(descriptor); 104 cananian 1.1.4.4 return arraytype; 105 cananian 1.1.4.1 } 106 cananian 1.1.4.1 case 'L': // object type. 107 cananian 1.1.4.1 return forDescriptor0(descriptor); 108 cananian 1.1.4.1 case 'B': // primitive types. 109 cananian 1.1.4.1 return HClass.Byte; 110 cananian 1.1.4.1 case 'C': 111 cananian 1.1.4.1 return HClass.Char; 112 cananian 1.1.4.1 case 'D': 113 cananian 1.1.4.1 return HClass.Double; 114 cananian 1.1.4.1 case 'F': 115 cananian 1.1.4.1 return HClass.Float; 116 cananian 1.1.4.1 case 'I': 117 cananian 1.1.4.1 return HClass.Int; 118 cananian 1.1.4.1 case 'J': 119 cananian 1.1.4.1 return HClass.Long; 120 cananian 1.1.4.1 case 'S': 121 cananian 1.1.4.1 return HClass.Short; 122 cananian 1.1.4.1 case 'Z': 123 cananian 1.1.4.1 return HClass.Boolean; 124 cananian 1.1.4.1 case 'V': 125 cananian 1.1.4.1 return HClass.Void; 126 cananian 1.1.4.1 default: 127 cananian 1.1.4.1 break; 128 cananian 1.1.4.1 } 129 cananian 1.1.4.1 throw new Error("Bad Descriptor: "+descriptor); 130 cananian 1.1.4.4 } 131 cananian 1.1.4.4 /** Allow Linker subclass to substitute a different (mutable?) 132 cananian 1.1.4.4 * array class type. */ 133 cananian 1.1.4.4 protected HClass makeArray(HClass baseType, int dims) { 134 cananian 1.1.4.4 return new HClassArray(this, baseType, dims); 135 cananian 1.1.4.1 } 136 cananian 1.1.4.1 137 cananian 1.1.4.1 /** 138 cananian 1.1.4.1 * Returns the <code>HClass</code> object associated with the class with 139 cananian 1.1.4.1 * the given string name. Given the fully-qualified name for a class or 140 cananian 1.1.4.1 * interface, this method attempts to locate and load the class. If it 141 cananian 1.1.4.1 * succeeds, returns the <code>HClass</code> object representing the class. 142 cananian 1.1.4.1 * If it fails, the method throws a <code>NoSuchClassException</code>. 143 cananian 1.1.4.1 * @param className the fully qualified name of the desired class. 144 cananian 1.1.4.1 * @return the <code>HClass</code> descriptor for the class with the 145 cananian 1.1.4.1 * specified name. 146 cananian 1.1.4.1 * @exception NoSuchClassException 147 cananian 1.1.4.1 * if the class could not be found. 148 cananian 1.1.4.1 */ 149 cananian 1.1.4.1 public final HClass forName(String className) throws NoSuchClassException { 150 cananian 1.1.4.1 if (className.charAt(0)=='[') { 151 cananian 1.3.2.1 assert className.indexOf('.')==-1 : "Class name " + className; // should be desc, not name. 152 cananian 1.1.4.1 return forDescriptor(className); 153 cananian 1.1.4.1 } else { 154 cananian 1.6 assert className.indexOf('/')==-1:className; // should be name, not desc. 155 cananian 1.1.4.1 return forDescriptor("L"+className.replace('.','/')+";"); 156 cananian 1.1.4.1 } 157 cananian 1.1.4.1 } 158 cananian 1.1.4.1 159 cananian 1.1.4.1 /** 160 cananian 1.1.4.1 * Returns the <code>HClass</code> object associated with the given java 161 cananian 1.1.4.1 * <code>Class</code> object. If (for some reason) the class file 162 cananian 1.1.4.1 * cannot be found, the method throws a <code>NoSuchClassException</code>. 163 cananian 1.1.4.1 * @return the <code>HClass</code> descriptor for this <code>Class</code>. 164 cananian 1.1.4.1 * @exception NoSuchClassException 165 cananian 1.1.4.1 * if the classfile could not be found. 166 cananian 1.1.4.1 * @deprecated Don't use java.lang.Class objects if you can help it. 167 cananian 1.1.4.1 */ 168 cananian 1.1.4.1 public final HClass forClass(Class cls) throws NoSuchClassException { 169 cananian 1.1.4.1 // if cls is an array... 170 cananian 1.1.4.1 if (cls.isArray()) 171 cananian 1.1.4.1 return forDescriptor("[" + 172 cananian 1.1.4.1 forClass(cls.getComponentType()).getDescriptor()); 173 cananian 1.1.4.1 // or else if it's a primitive type... 174 cananian 1.1.4.1 if (cls.isPrimitive()) { 175 cananian 1.1.4.1 if (cls == java.lang.Boolean.TYPE) return forDescriptor("Z"); 176 cananian 1.1.4.1 if (cls == java.lang.Character.TYPE) return forDescriptor("C"); 177 cananian 1.1.4.1 if (cls == java.lang.Byte.TYPE) return forDescriptor("B"); 178 cananian 1.1.4.1 if (cls == java.lang.Short.TYPE) return forDescriptor("S"); 179 cananian 1.1.4.1 if (cls == java.lang.Integer.TYPE) return forDescriptor("I"); 180 cananian 1.1.4.1 if (cls == java.lang.Long.TYPE) return forDescriptor("J"); 181 cananian 1.1.4.1 if (cls == java.lang.Float.TYPE) return forDescriptor("F"); 182 cananian 1.1.4.1 if (cls == java.lang.Double.TYPE) return forDescriptor("D"); 183 cananian 1.1.4.1 if (cls == java.lang.Void.TYPE) return forDescriptor("V"); 184 cananian 1.1.4.1 throw new NoSuchClassException("Unknown class primitive: "+cls); 185 cananian 1.1.4.1 } 186 cananian 1.1.4.1 // otherwise... 187 cananian 1.1.4.1 return forName(cls.getName()); 188 cananian 1.1.4.1 } 189 cananian 1.1.4.1 190 cananian 1.1.4.1 /** Creates a new mutable class with the given name which is 191 cananian 1.1.4.1 * based on the given template class. <b>The <code>name</code> 192 cananian 1.1.4.1 * must be unique.</b> 193 cananian 1.1.4.1 * @exception DuplicateClassException if the given name is not unique; 194 cananian 1.1.4.1 * that is, it corresponds to a loadable class. 195 cananian 1.1.4.1 */ 196 cananian 1.1.4.1 public HClass createMutableClass(String name, HClass template) 197 cananian 1.1.4.1 throws DuplicateClassException { 198 cananian 1.3.2.1 assert template.getLinker()==this; 199 cananian 1.1.4.1 try { 200 cananian 1.1.4.1 forName(name); 201 cananian 1.1.4.1 throw new DuplicateClassException(name); 202 cananian 1.1.4.1 } catch (NoSuchClassException e) { /* named class not found, continue */ } 203 cananian 1.1.4.1 // okay, create a mutable class... 204 cananian 1.1.4.1 HClass hc = new HClassSyn(this, name, template); 205 cananian 1.1.4.1 hc.hasBeenModified = true; 206 cananian 1.1.4.1 register(hc); 207 cananian 1.1.4.1 return hc; 208 cananian 1.1.4.1 } 209 cananian 1.1.4.1 } 210 cananian 1.1.4.1 211 cananian 1.1.4.1 // set emacs indentation style. 212 cananian 1.1.4.1 // Local Variables: 213 cananian 1.1.4.1 // c-basic-offset:2 214 cananian 1.2 // End: