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 }