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: