Index: java/lang/Class.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/lang/Class.java,v retrieving revision 1.37 diff -u -r1.37 Class.java --- java/lang/Class.java 2 Jul 2005 20:32:38 -0000 1.37 +++ java/lang/Class.java 27 Jul 2005 11:13:13 -0000 @@ -156,11 +156,16 @@ */ public static Class forName(String name) throws ClassNotFoundException { - Class result = VMClass.forName (name); - if (result == null) - result = Class.forName(name, true, - VMStackWalker.getCallingClassLoader()); - return result; + ClassLoader cl = VMStackWalker.getCallingClassLoader(); + Class result = VMClass.forName(name); + if (result != null) + { + if (cl != null) + VMClassLoader.registerInitiatingLoader(cl, result); + return result; + } + else + return forName(name, true, cl); } /** @@ -216,13 +221,27 @@ } throw new ClassNotFoundException(name); } - if (name.startsWith("[")) - return VMClass.loadArrayClass(name, classloader); - Class c = classloader.loadClass(name); - classloader.resolveClass(c); - if (initialize) - VMClass.initialize(c); - return c; + else + { + // Take a shortcut, if possible. This is not just a performance + // tweak, but it also helps protect us from broken class loaders. + Class c = classloader.findLoadedClass(name); + if (c == null) + { + if (name.startsWith("[")) + { + c = VMClass.loadArrayClass(name, classloader); + VMClassLoader.registerInitiatingLoader(classloader, c); + return c; + } + c = classloader.loadClass(name); + VMClassLoader.registerInitiatingLoader(classloader, c); + } + classloader.resolveClass(c); + if (initialize) + VMClass.initialize(c); + return c; + } } /** Index: java/lang/ClassLoader.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/lang/ClassLoader.java,v retrieving revision 1.54 diff -u -r1.54 ClassLoader.java --- java/lang/ClassLoader.java 25 Jul 2005 14:28:42 -0000 1.54 +++ java/lang/ClassLoader.java 27 Jul 2005 11:13:14 -0000 @@ -480,7 +480,7 @@ Class retval = VMClassLoader.defineClass(this, name, data, offset, len, domain); if (! VMClassLoader.USE_VM_CACHE) - loadedClasses.put(retval.getName(), retval); + VMClassLoader.registerInitiatingLoader(this, retval); return retval; } Index: vm/reference/java/lang/VMClassLoader.java =================================================================== RCS file: /cvsroot/classpath/classpath/vm/reference/java/lang/VMClassLoader.java,v retrieving revision 1.29 diff -u -r1.29 VMClassLoader.java --- vm/reference/java/lang/VMClassLoader.java 26 Jul 2005 06:46:20 -0000 1.29 +++ vm/reference/java/lang/VMClassLoader.java 27 Jul 2005 11:13:19 -0000 @@ -292,9 +292,52 @@ /** * If the VM wants to keep its own cache, this method can be replaced. + * If the name represents an array type, the ultimate component type + * is looked up and the array type is created. */ static Class findLoadedClass(ClassLoader cl, String name) { - return (Class) cl.loadedClasses.get(name); + synchronized (cl.loadedClasses) + { + return (Class) cl.loadedClasses.get(name); + } + } + + /** + * This method is called by Class.forName() to notify the VM that a + * particular class loader should be recorded as the initiating loader for + * a class. Note that ClassLoader.findLoadedClass() should see classes that + * have been registered through this method. + * When the VM internally loads a class, it should call this method + * to record the class with the initiating class loader. + * Note that when an array type is registered, the ultimate component type + * is registered instead. + * + * @param cl Class loader instance (should not be null) + * @param c Class to be associated with this class loader + * @throws LinkageError if a different class with the same name was + * already loaded by this class loader. + */ + static void registerInitiatingLoader(ClassLoader cl, Class c) + throws LinkageError + { + synchronized (cl.loadedClasses) + { + Object prev = cl.loadedClasses.get(c.getName()); + if (prev != c) + { + if (prev != null) + throw new LinkageError("Duplicate class definition: " + + c.getName()); + if (c.isArray()) + { + Class componentType = c.getComponentType(); + while (componentType.isArray()) + componentType = componentType.getComponentType(); + registerInitiatingLoader(cl, componentType); + } + cl.loadedClasses.put(c.getName(), c); + } + } } }