View Javadoc

1   // PrimordialClassLoader.java, created Mon Feb  5 23:23:20 2001 by joewhaley
2   // Copyright (C) 2001-3 John Whaley <jwhaley@alum.mit.edu>
3   // Licensed under the terms of the GNU LGPL; see COPYING for details.
4   package joeq.Class;
5   
6   import java.util.ArrayList;
7   import java.util.Collections;
8   import java.util.Enumeration;
9   import java.util.HashMap;
10  import java.util.HashSet;
11  import java.util.Iterator;
12  import java.util.LinkedHashSet;
13  import java.util.List;
14  import java.util.Map;
15  import java.util.Set;
16  import java.util.zip.ZipEntry;
17  import java.util.zip.ZipFile;
18  import java.io.DataInput;
19  import java.io.DataInputStream;
20  import java.io.File;
21  import java.io.FileInputStream;
22  import java.io.FileNotFoundException;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.PrintStream;
26  import joeq.ClassLib.ClassLibInterface;
27  import joeq.Main.jq;
28  import joeq.UTF.Utf8;
29  import jwutil.collections.AppendIterator;
30  import jwutil.collections.Filter;
31  import jwutil.collections.FilterIterator;
32  import jwutil.collections.UnmodifiableIterator;
33  import jwutil.util.Assert;
34  
35  /***
36   * PrimordialClassLoader
37   *
38   * @author  John Whaley <jwhaley@alum.mit.edu>
39   * @version $Id: PrimordialClassLoader.java 2192 2005-02-18 06:07:06Z livshits $
40   */
41  public class PrimordialClassLoader extends ClassLoader implements jq_ClassFileConstants {
42      
43      public static /*final*/ boolean TRACE = false;
44      public static final PrintStream out = System.out;
45      
46      abstract static class ClasspathElement {
47          /*** Open a stream to read the given resource, or return
48           *  <code>null</code> if resource cannot be found. */
49          abstract InputStream getResourceAsStream(String resourcename);
50          abstract boolean containsResource(String name);
51          /*** Iterate over all classes in the given package. */
52          Iterator listPackage(String packagename) { return listPackage(packagename, false); }
53          abstract Iterator listPackage(String packagename, boolean recursive);
54          abstract Iterator listPackages();
55      }
56      /*** A .zip or .jar file in the CLASSPATH. */
57      static class ZipFileElement extends ClasspathElement {
58          ZipFile zf;
59          Map entries;
60          ZipFileElement(ZipFile zf) {
61              this.zf = zf;
62          }
63          void initializeEntryMap() {
64              int size = zf.size();
65              entries = new HashMap(size + (size >> 1));
66              if (size > 0) {
67                  for (Enumeration e = zf.entries(); e.hasMoreElements(); ) {
68                      ZipEntry ze = (ZipEntry) e.nextElement();
69                      entries.put(ze.getName(), ze);
70                  }
71              }
72              if (TRACE) out.println(this+" contains: "+entries.keySet());
73          }
74          public String toString() { return zf.getName(); }
75          InputStream getResourceAsStream(String name) {
76              if (TRACE) out.println("Getting resource for "+name+" in zip file "+zf.getName());
77              if (entries == null) initializeEntryMap();
78              if (name.charAt(0) == '/') name = name.substring(1);
79              ZipEntry ze = (ZipEntry) entries.get(name);
80              try { // look for name in zipfile, return null if something goes wrong.
81                  return (ze==null)?null:zf.getInputStream(ze);
82              } catch (IOException e) { return null; }
83          }
84          boolean containsResource(String name) {
85              if (TRACE) out.println("Searching for "+name+" in zip file "+zf.getName());
86              if (entries == null) initializeEntryMap();
87              return entries.containsKey(name);
88          }
89          Iterator listPackage(final String pathname, final boolean recursive) {
90              if (TRACE) out.println("Listing package "+pathname+" of zip file "+zf.getName());
91              // look for directory name first
92              if (entries == null) initializeEntryMap();
93              final String filesep   = "/";
94              return new FilterIterator(entries.values().iterator(),
95              new Filter() {
96                  public boolean isElement(Object o) {
97                      ZipEntry zze = (ZipEntry) o;
98                      String name = zze.getName();
99                      if (TRACE) out.println("Checking if zipentry "+name+" is in package "+pathname);
100                     return (!zze.isDirectory()) && name.startsWith(pathname) &&
101                             name.endsWith(".class") &&
102                             (recursive || name.lastIndexOf(filesep)==(pathname.length()-1));
103                 }
104                 public Object map(Object o) {
105                     return ((ZipEntry)o).getName();
106                 }
107             });
108         }
109         Iterator listPackages() {
110             if (TRACE) out.println("Listing packages of zip file "+zf.getName());
111             if (entries == null) initializeEntryMap();
112             LinkedHashSet result = new LinkedHashSet();
113             for (Iterator i=entries.values().iterator(); i.hasNext(); ) {
114                 ZipEntry zze = (ZipEntry) i.next();
115                 if (zze.isDirectory()) continue;
116                 String name = zze.getName();
117                 if (name.endsWith(".class")) {
118                     int index = name.lastIndexOf('/');
119                     result.add(name.substring(0, index+1));
120                 }
121             }
122             if (TRACE) out.println("Result: "+result);
123             return result.iterator();
124         }
125         /*** Close the zipfile when this object is garbage-collected. */
126         protected void finalize() throws Throwable {
127             // yes, it is possible to finalize an uninitialized object.
128             try { if (zf!=null) zf.close(); } finally { super.finalize(); }
129         }
130     }
131     // These should be static so that we don't need to look them up during
132     // class loading.
133     public static final String pathsep = System.getProperty("path.separator");
134     public static final String filesep = System.getProperty("file.separator");
135     /*** A regular path string in the CLASSPATH. */
136     static class PathElement extends ClasspathElement {
137         String path;
138         Set entries;
139 
140         PathElement(String path) {
141             this.path = path;
142         }
143         
144         void initializeEntryMap() {
145             this.entries = new HashSet();
146             buildEntries(null);
147             if (TRACE) out.println(this+" contains: "+entries);
148         }
149         
150         public String toString() { return path; }
151         
152         InputStream getResourceAsStream(String name) {
153             if (TRACE) out.println("Getting resource for "+name+" in path "+path);
154             if (entries == null) initializeEntryMap();
155             if (name.charAt(0) == '/') name = name.substring(1);
156             if (!entries.contains(name))
157                 return null;
158             if (filesep.charAt(0) != '/') name = name.replace('/', filesep.charAt(0));
159             try { // try to open the file, starting from path.
160                 File f = new File(path, name);
161                 return new FileInputStream(f);
162             } catch (FileNotFoundException e) {
163                 return null; // if anything goes wrong, return null.
164             }
165         }
166         
167         boolean containsResource(String name) {
168             if (TRACE) out.println("Searching for "+name+" in path "+path);
169             if (entries == null) initializeEntryMap();
170             return entries.contains(name);
171         }
172         
173         Iterator listPackage(final String pathn, final boolean recursive) {
174             if (TRACE) out.println("Listing package "+pathn+" in path "+path);
175             if (entries == null) initializeEntryMap();
176             final String filesep   = "/";
177             return new FilterIterator(entries.iterator(),
178                 new Filter() {
179                     public boolean isElement(Object o) {
180                         String name = (String) o;
181                         if (TRACE) out.println("Checking if file "+name+" is in package "+pathn);
182                         return name.startsWith(pathn) &&
183                                name.endsWith(".class") &&
184                                (recursive || name.lastIndexOf(filesep)==(pathn.length()-1));
185                     }
186                 });
187         }
188 
189         Iterator listPackages() {
190             if (TRACE) out.println("Listing packages of path "+path);
191             HashSet hs = new HashSet();
192             listPackages(null, hs);
193             return hs.iterator();
194         }
195         
196         private void listPackages(final String dir, final HashSet pkgs) {
197             final File f = dir == null ? new File(path) : new File(path, dir);
198             if (!f.exists() || !f.isDirectory()) return;
199             //pkgs.add(path);    // add the current directory first
200             String [] subdirs = f.list(new java.io.FilenameFilter() {
201                 public boolean accept(File _dir, String name) {
202                     if (dir != null && name.endsWith(".class"))
203                         pkgs.add(dir);
204                     return new File(_dir, name).isDirectory();
205                 }
206             });
207             for (int i = 0; i < subdirs.length; i++) {
208                 String dn = (String)subdirs[i];
209                 if (dir != null)
210                     dn = dir + filesep + dn;
211                 listPackages(dn, pkgs);
212             }
213         }
214         
215         private void buildEntries(final String pathn) {
216             File f;
217             if (pathn == null) {
218                 f = new File(path);
219             } else if (filesep.charAt(0) == '/') {
220                 f = new File(path, pathn);
221             } else {
222                 f = new File(path, pathn.replace('/', filesep.charAt(0)));
223             }
224             if (!f.exists() || !f.isDirectory()) return;
225             String[] cls = f.list(new java.io.FilenameFilter() {
226                     public boolean accept(File _dir, String name) {
227                         return !new File(_dir, name).isDirectory();
228                     }
229                 });
230             
231             if (cls != null) {
232                 for (int i = 0; i < cls.length; ++i) {
233                     String s = (pathn==null)?(cls[i]):(pathn+cls[i]);
234                     entries.add(s);
235                 }
236             }
237 
238             String [] subdirs = f.list(new java.io.FilenameFilter() {
239                     public boolean accept(File _dir, String name) {
240                         return new File(_dir, name).isDirectory();
241                     }
242                 });
243             if (subdirs != null) {
244                 for (int i = 0; i < subdirs.length; i++) {
245                     String dn = (String)subdirs[i];
246                     if (pathn != null) dn = pathn + dn;
247                     buildEntries(dn + '/');
248                 }
249             }
250         }
251     }
252 
253     /*** Vector of ClasspathElements corresponding to CLASSPATH entries. */
254     public void addToClasspath(String s) {
255         //Assert._assert(s.indexOf(pathsep) == -1);
256         Set duplicates = new HashSet(); // don't add duplicates.
257         duplicates.addAll(classpathList);
258         for (Iterator it = classpaths(s); it.hasNext(); ) {
259             String path = (String) it.next();
260             if (duplicates.contains(path)) continue; // skip duplicate.
261             else duplicates.add(path);
262             if (path.toLowerCase().endsWith(".zip") ||
263                 path.toLowerCase().endsWith(".jar"))
264                 try {
265                     if (TRACE) out.println("Adding zip file "+path+" to classpath");
266                     classpathList.add(new ZipFileElement(new ZipFile(path)));
267                 } catch (IOException ex) { /* skip this zip file, then. */ }
268             else {
269                 if (TRACE) out.println("Adding path "+path+" to classpath");
270                 classpathList.add(new PathElement(path));
271             }
272         }
273         ((ArrayList) classpathList).trimToSize(); // save memory.
274     }
275 
276     /*** Iterate over the components of the system CLASSPATH.
277      *  Each element is a <code>String</code> naming one segment of the
278      *  CLASSPATH. */
279     public static final Iterator classpaths(String classpath) {
280 
281         // For convenience, make sure classpath begins with and ends with pathsep.
282         if (!classpath.startsWith(pathsep)) classpath = pathsep + classpath;
283         if (!classpath.endsWith(pathsep)) classpath = classpath + pathsep;
284         final String cp = classpath;
285 
286         return new UnmodifiableIterator() {
287             int i=0;
288             public boolean hasNext() {
289                 return (cp.length() > (i+pathsep.length()));
290             }
291             public Object next() {
292                 i+=pathsep.length(); // cp begins with pathsep.
293                 String path = cp.substring(i, cp.indexOf(pathsep, i));
294                 i+=path.length(); // skip over path.
295                 return path;
296             }
297         };
298     }
299 
300     public Iterator listPackage(final String pathname) {
301         return listPackage(pathname, false);
302     }
303 
304     public Iterator listPackage(final String pathname, boolean recursive) {
305         Iterator result = null;
306         for (Iterator it = classpathList.iterator(); it.hasNext(); ) {
307             ClasspathElement cpe = (ClasspathElement)it.next();
308             Iterator lp = cpe.listPackage(pathname, recursive);
309             if (!lp.hasNext()) continue;
310             result = result==null?lp:new AppendIterator(lp, result);
311         }
312         if (result == null) return Collections.EMPTY_SET.iterator();
313         return result;
314     }
315     
316     public Iterator listPackages() {
317         Iterator result = null;
318         for (Iterator it = classpathList.iterator(); it.hasNext(); ) {
319             ClasspathElement cpe = (ClasspathElement)it.next();
320             Iterator lp = cpe.listPackages();
321             if (!lp.hasNext()) continue;
322             result = result==null?lp:new AppendIterator(lp, result);
323         }
324         if (result == null) return Collections.EMPTY_SET.iterator();
325         return result;
326     }
327 
328     public String classpathToString() {
329         StringBuffer result = new StringBuffer(pathsep);
330         for (Iterator it = classpathList.iterator(); it.hasNext(); ) {
331             ClasspathElement cpe = (ClasspathElement) it.next();
332             result.append(cpe.toString());
333             result.append(pathsep);
334         }
335         return result.toString();
336     }
337     
338     public static String descriptorToResource(String desc) {
339         Assert._assert(desc.charAt(0)==TC_CLASS);
340         Assert._assert(desc.charAt(desc.length()-1)==TC_CLASSEND);
341         Assert._assert(desc.indexOf('.')==-1); // should have '/' separators.
342         return desc.substring(1, desc.length()-1) + ".class";
343     }
344     
345     /*** Translate a class name into a corresponding resource name.
346      * @param classname The class name to translate.
347      */
348     public static String classnameToResource(String classname) {
349         Assert._assert(classname.indexOf('/')==-1); // should have '.' separators.
350         // Swap all '.' for '/' & append ".class"
351         return classname.replace('.', filesep.charAt(0)) + ".class";
352     }
353 
354     public String getResourcePath(String name) {
355         for (Iterator it = classpathList.iterator(); it.hasNext(); ) {
356             ClasspathElement cpe = (ClasspathElement) it.next();
357             if (cpe.containsResource(name))
358                 return cpe.toString();
359         }
360         // Couldn't find resource.
361         return null;
362     }
363 
364     public String getPackagePath(String name) {
365         for (Iterator it = classpathList.iterator(); it.hasNext(); ) {
366             ClasspathElement cpe = (ClasspathElement) it.next();
367             for (Iterator it2 = cpe.listPackages(); it2.hasNext(); ) {
368                 if (name.equals(it2.next()))
369                     return cpe.toString();
370             }
371         }
372         // Couldn't find resource.
373         return null;
374     }
375 
376     /*** Open an <code>InputStream</code> on a resource found somewhere
377      *  in the CLASSPATH.
378      * @param name The filename of the resource to locate.
379      */
380     public InputStream getResourceAsStream(String name) {
381         //if (!jq.RunningNative && name.startsWith("java/")) {
382         //    // hijack loading of java/* to point to bootstrap versions
383         //    char[] c = name.toCharArray();
384         //    c[3] = '_';
385         //    String name2 = new String(c);
386         //    for (Iterator it = classpathList.iterator(); it.hasNext(); ) {
387         //        ClasspathElement cpe = (ClasspathElement) it.next();
388         //        InputStream is = cpe.getResourceAsStream(name2);
389         //        if (is!=null) {
390         //            return is; // return stream if found.
391         //        }
392         //    }
393         //}
394         for (Iterator it = classpathList.iterator(); it.hasNext(); ) {
395             ClasspathElement cpe = (ClasspathElement) it.next();
396             InputStream is = cpe.getResourceAsStream(name);
397             if (is != null) {
398                 return is; // return stream if found.
399             }
400         }
401         // Couldn't find resource.
402         return null;
403     }
404     
405     private PrimordialClassLoader() {
406         bs_desc2type = new HashMap();
407         allTypes = new jq_Type[1024]; numTypes = 0;
408         classpathList = new ArrayList();
409     }
410     
411     private void put_desc2type(Utf8 desc, jq_Type type) {
412         Object result = bs_desc2type.put(desc, type);
413         Assert._assert(result == null);
414         if (numTypes == allTypes.length) {
415             jq_Type[] a = new jq_Type[allTypes.length * 2];
416             System.arraycopy(allTypes, 0, a, 0, numTypes);
417             allTypes = a;
418         }
419         allTypes[numTypes++] = type;
420     }
421     
422     private static void initPrimitiveTypes() {
423         // trigger jq_Primitive clinit
424         loader.getOrCreateBSType(jq_Primitive.BYTE.getDesc());
425         loader.put_desc2type(jq_Array.BYTE_ARRAY.getDesc(), jq_Array.BYTE_ARRAY);
426         loader.put_desc2type(jq_Array.CHAR_ARRAY.getDesc(), jq_Array.CHAR_ARRAY);
427         loader.put_desc2type(jq_Array.DOUBLE_ARRAY.getDesc(), jq_Array.DOUBLE_ARRAY);
428         loader.put_desc2type(jq_Array.FLOAT_ARRAY.getDesc(), jq_Array.FLOAT_ARRAY);
429         loader.put_desc2type(jq_Array.INT_ARRAY.getDesc(), jq_Array.INT_ARRAY);
430         loader.put_desc2type(jq_Array.LONG_ARRAY.getDesc(), jq_Array.LONG_ARRAY);
431         loader.put_desc2type(jq_Array.SHORT_ARRAY.getDesc(), jq_Array.SHORT_ARRAY);
432         loader.put_desc2type(jq_Array.BOOLEAN_ARRAY.getDesc(), jq_Array.BOOLEAN_ARRAY);
433     }
434     
435     public DataInputStream getClassFileStream(Utf8 descriptor)
436     throws IOException {
437         String resourceName = descriptorToResource(descriptor.toString());
438         InputStream is = getResourceAsStream(resourceName);
439         if (is == null) return null;
440         return new DataInputStream(is);
441     }
442 
443     public static final PrimordialClassLoader loader;
444     public static final jq_Class JavaLangObject;
445     public static final jq_Class JavaLangClass;
446     public static final jq_Class JavaLangString;
447     public static final jq_Class JavaLangSystem;
448     public static final jq_Class JavaLangThrowable;
449     public static final jq_Array AddressArray;
450     static {
451         loader = new PrimordialClassLoader();
452         initPrimitiveTypes();
453         JavaLangObject = (jq_Class)loader.getOrCreateBSType("Ljava/lang/Object;");
454         JavaLangClass = (jq_Class)loader.getOrCreateBSType("Ljava/lang/Class;");
455         JavaLangString = (jq_Class)loader.getOrCreateBSType("Ljava/lang/String;");
456         JavaLangSystem = (jq_Class)loader.getOrCreateBSType("Ljava/lang/System;");
457         JavaLangThrowable = (jq_Class)loader.getOrCreateBSType("Ljava/lang/Throwable;");
458         AddressArray = (jq_Array)loader.getOrCreateBSType("[Ljoeq/Memory/Address;");
459     }
460     
461     public static jq_Class getJavaLangObject() { return JavaLangObject; }
462     public static jq_Class getJavaLangClass() { return JavaLangClass; }
463     public static jq_Class getJavaLangString() { return JavaLangString; }
464     public static jq_Class getJavaLangSystem() { return JavaLangSystem; }
465     public static jq_Class getJavaLangThrowable() { return JavaLangThrowable; }
466     public static jq_Array getAddressArray() { return AddressArray; }
467     public static jq_Class getJavaLangException() { return (jq_Class)loader.getOrCreateBSType("Ljava/lang/Exception;"); }
468     public static jq_Class getJavaLangError() { return (jq_Class)loader.getOrCreateBSType("Ljava/lang/Error;"); }
469     public static jq_Class getJavaLangRuntimeException() { return (jq_Class)loader.getOrCreateBSType("Ljava/lang/RuntimeException;"); }
470     public static jq_Class getJavaLangNullPointerException() { return (jq_Class)loader.getOrCreateBSType("Ljava/lang/NullPointerException;"); }
471     public static jq_Class getJavaLangIndexOutOfBoundsException() { return (jq_Class)loader.getOrCreateBSType("Ljava/lang/IndexOutOfBoundsException;"); }
472     public static jq_Class getJavaLangArrayIndexOutOfBoundsException() { return (jq_Class)loader.getOrCreateBSType("Ljava/lang/ArrayIndexOutOfBoundsException;"); }
473     public static jq_Class getJavaLangArrayStoreException() { return (jq_Class)loader.getOrCreateBSType("Ljava/lang/ArrayStoreException;"); }
474     public static jq_Class getJavaLangNegativeArraySizeException() { return (jq_Class)loader.getOrCreateBSType("Ljava/lang/NegativeArraySizeException;"); }
475     public static jq_Class getJavaLangArithmeticException() { return (jq_Class)loader.getOrCreateBSType("Ljava/lang/ArithmeticException;"); }
476     public static jq_Class getJavaLangIllegalMonitorStateException() { return (jq_Class)loader.getOrCreateBSType("Ljava/lang/IllegalMonitorStateException;"); }
477     public static jq_Class getJavaLangClassCastException() { return (jq_Class)loader.getOrCreateBSType("Ljava/lang/ClassCastException;"); }
478     public static jq_Class getJavaLangClassLoader() { return (jq_Class)loader.getOrCreateBSType("Ljava/lang/ClassLoader;"); }
479     public static jq_Class getJavaLangReflectField() { return (jq_Class)loader.getOrCreateBSType("Ljava/lang/reflect/Field;"); }
480     public static jq_Class getJavaLangReflectMethod() { return (jq_Class)loader.getOrCreateBSType("Ljava/lang/reflect/Method;"); }
481     public static jq_Class getJavaLangReflectConstructor() { return (jq_Class)loader.getOrCreateBSType("Ljava/lang/reflect/Constructor;"); }
482     public static jq_Class getJavaLangThread() { return (jq_Class)loader.getOrCreateBSType("Ljava/lang/Thread;"); }
483     public static jq_Class getJavaLangRefFinalizer() { return (jq_Class)loader.getOrCreateBSType("Ljava/lang/ref/Finalizer;"); }
484     private final Map/*<Utf8, jq_Type>*/ bs_desc2type;
485     private jq_Type[] allTypes; private int numTypes;
486     private final List/*<ClasspathElement>*/ classpathList;
487 
488     public jq_Type[] getAllTypes() {
489         return allTypes;
490     }
491     
492     public int getNumTypes() {
493         return numTypes;
494     }
495     
496     public final Set/*<jq_Class>*/ getClassesThatReference(jq_Member m) {
497         HashSet s = new HashSet();
498         for (int i = 0; i < numTypes; ++i) {
499             jq_Type t = allTypes[i];
500             if (t instanceof jq_Class) {
501                 jq_Class k = (jq_Class) t;
502                 if (k.doesConstantPoolContain(m))
503                     s.add(k);
504             }
505         }
506         return s;
507     }
508     
509     public final jq_Class getOrCreateClass(String desc, DataInput in) {
510         jq_Class t = (jq_Class)getOrCreateBSType(Utf8.get(desc));
511         t.load(in);
512         return t;
513     }
514 
515     public final jq_Type getBSType(String desc) { return getBSType(Utf8.get(desc)); }
516     public final jq_Type getBSType(Utf8 desc) {
517         return (jq_Type)bs_desc2type.get(desc);
518     }
519     public final jq_Type getOrCreateBSType(String desc) { return getOrCreateBSType(Utf8.get(desc)); }
520     public final jq_Type getOrCreateBSType(Utf8 desc) {
521         if (jq.RunningNative)
522             return ClassLibInterface.DEFAULT.getOrCreateType(this, desc);
523         jq_Type t = (jq_Type)bs_desc2type.get(desc);
524         if (t == null) {
525             if (desc.isDescriptor(jq_ClassFileConstants.TC_CLASS)) {
526                 // as a side effect, the class type is registered.
527                 if (TRACE) out.println("Adding class type "+desc);
528                 t = jq_Class.newClass(this, desc);
529             } else if (desc.isDescriptor(jq_ClassFileConstants.TC_ARRAY)) {
530                 if (TRACE) out.println("Adding array type "+desc);
531                 Utf8 elementDesc = desc.getArrayElementDescriptor();
532                 jq_Type elementType = getOrCreateBSType(elementDesc); // recursion
533                 // as a side effect, the array type is registered.
534                 t = jq_Array.newArray(desc, this, elementType);
535             } else {
536                 // this code only gets executed at the very beginning, when creating primitive types.
537                 if (desc == Utf8.BYTE_DESC)
538                     t = jq_Primitive.newPrimitive(desc, "byte", 1);
539                 else if (desc == Utf8.CHAR_DESC)
540                     t = jq_Primitive.newPrimitive(desc, "char", 2);
541                 else if (desc == Utf8.DOUBLE_DESC)
542                     t = jq_Primitive.newPrimitive(desc, "double", 8);
543                 else if (desc == Utf8.FLOAT_DESC)
544                     t = jq_Primitive.newPrimitive(desc, "float", 4);
545                 else if (desc == Utf8.INT_DESC)
546                     t = jq_Primitive.newPrimitive(desc, "int", 4);
547                 else if (desc == Utf8.LONG_DESC)
548                     t = jq_Primitive.newPrimitive(desc, "long", 8);
549                 else if (desc == Utf8.SHORT_DESC)
550                     t = jq_Primitive.newPrimitive(desc, "short", 2);
551                 else if (desc == Utf8.BOOLEAN_DESC)
552                     t = jq_Primitive.newPrimitive(desc, "boolean", 1);
553                 else if (desc == Utf8.VOID_DESC)
554                     t = jq_Primitive.newPrimitive(desc, "void", 0);
555                 /*
556                 else if (desc == jq_Array.BYTE_ARRAY.getDesc()) return jq_Array.BYTE_ARRAY;
557                 else if (desc == jq_Array.CHAR_ARRAY.getDesc()) return jq_Array.CHAR_ARRAY;
558                 else if (desc == jq_Array.DOUBLE_ARRAY.getDesc()) return jq_Array.DOUBLE_ARRAY;
559                 else if (desc == jq_Array.FLOAT_ARRAY.getDesc()) return jq_Array.FLOAT_ARRAY;
560                 else if (desc == jq_Array.INT_ARRAY.getDesc()) return jq_Array.INT_ARRAY;
561                 else if (desc == jq_Array.LONG_ARRAY.getDesc()) return jq_Array.LONG_ARRAY;
562                 else if (desc == jq_Array.SHORT_ARRAY.getDesc()) return jq_Array.SHORT_ARRAY;
563                 else if (desc == jq_Array.BOOLEAN_ARRAY.getDesc()) return jq_Array.BOOLEAN_ARRAY;
564                  */
565                 else Assert.UNREACHABLE("bad descriptor! "+desc);
566             }
567             put_desc2type(desc, t);
568         }
569         return t;
570     }
571     
572     /*
573      * @param cName a string, not a descriptor.
574      * @author Chrislain Razafimahefa <razafima@cui.unige.ch>
575      */
576     public final void replaceClass(String cName)
577     {
578         Utf8 oldDesc = Utf8.get("L"+cName.replace('.', '/')+";") ;
579         jq_Type old = PrimordialClassLoader.getOrCreateType(this, oldDesc);
580         Assert._assert(old != null);
581         Assert._assert(oldDesc.isDescriptor(jq_ClassFileConstants.TC_CLASS));
582 
583         // now load 'new' with a fake name
584         Utf8 newDesc = Utf8.get("LREPLACE"+cName.replace('.', '/')+";") ;
585         jq_Class new_c = jq_Class.newClass(this, newDesc);
586         put_desc2type(newDesc, new_c);
587 
588         // take inputstream on OLD class, but load in NEW class.
589         DataInputStream in = null;
590         try {
591             in = getClassFileStream(oldDesc);
592             if (in == null) throw new NoClassDefFoundError(jq_Class.className(oldDesc));
593             new_c.load(in); // will generate the replacement
594         } catch (IOException x) {
595             x.printStackTrace(); // for debugging
596             throw new ClassFormatError(x.toString());
597         } finally {
598             try { if (in != null) in.close(); } catch (IOException _) { }
599         }
600     }
601     
602     public void unloadBSType(jq_Type t) {
603         bs_desc2type.remove(t.getDesc());
604         for (int i = 0; ; ++i) {
605             if (allTypes[i] == t) {
606                 numTypes--;
607                 System.arraycopy(allTypes, i+1, allTypes, i, numTypes - i);
608                 allTypes[numTypes] = null;
609                 break;
610             }
611         }
612     }
613     
614     public static final jq_Type getOrCreateType(ClassLoader cl, Utf8 desc) {
615         if (jq.RunningNative)
616             return ClassLibInterface.DEFAULT.getOrCreateType(cl, desc);
617         Assert._assert(cl == PrimordialClassLoader.loader);
618         return PrimordialClassLoader.loader.getOrCreateBSType(desc);
619     }
620     
621     public static final void unloadType(ClassLoader cl, jq_Type t) {
622         if (jq.RunningNative) {
623             ClassLibInterface.DEFAULT.unloadType(cl, t);
624             return;
625         }
626         Assert._assert(cl == PrimordialClassLoader.loader);
627         PrimordialClassLoader.loader.unloadBSType(t);
628     }
629 }