Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: Bootstrap/PrimordialClassLoader.java


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