diff -ur -x CVS -x Make* /home/topic/kaffe/libraries/clib/native/Class.c libraries/clib/native/Class.c
--- /home/topic/kaffe/libraries/clib/native/Class.c	Thu May 30 23:03:51 2002
+++ libraries/clib/native/Class.c	Sun Jun  2 12:24:35 2002
@@ -35,139 +35,6 @@
 extern Hjava_lang_Object* buildStackTrace(struct _exceptionFrame*);
 
 /*
- * Convert string name to class object.
- */
-struct Hjava_lang_Class*
-java_lang_Class_forName(struct Hjava_lang_String* str, jbool doinit,
-	Hjava_lang_ClassLoader* loader)
-{
-	errorInfo einfo;
-	Hjava_lang_Class* clazz;
-	Utf8Const *utf8buf;
-	const char *buf;
-	int jlen;
-	jchar *js;
-
-	/*
-	 * NB: internally, we store class names as path names (with slashes
-	 *     instead of dots.  However, we must also prevent calls to
-	 *     "java/lang/Object" or "[[Ljava/lang/Object;" from succeeding.
-	 *	Since class names cannot have slashes, we reject all attempts
-	 *	to look up names that do.  Awkward.  Inefficient.
-	 */
-	js = STRING_DATA(str);
-	jlen = STRING_SIZE(str);
-	while (--jlen > 0) {
-		if (*js++ == '/') {
-			postExceptionMessage(&einfo,
-				JAVA_LANG(ClassNotFoundException),
-				"Cannot have slashes - use dots instead.");
-			throwError(&einfo);
-		}
-	}
-
-	/*
-	 * Note the following oddity:
-	 *
-	 * It is apparently perfectly legal to call forName for array types,
-	 * such as "[Ljava.lang.String;" or "[B".
-	 * However, it is wrong to call Class.forName("Ljava.lang.String;")
-	 *
-	 * This situation is similar to the constant pool resolution.  We
-	 * therefore do the same thing as in getClass in kaffevm/lookup.c,
-	 * that is, use either loadArray or loadClass depending on the name.
-	 *
-	 * This is somewhat described in Section 5.1.3 of the VM
-	 * Specification, titled "Array Classes".  This section seems to
-	 * imply that we must avoid asking a class loader to resolve such
-	 * array names (those starting with an [), and this is what calling
-	 * loadArray does.
-	 */
-
-	/* Convert string to utf8, converting '.' to '/' */
-	utf8buf = checkPtr(stringJava2Utf8ConstReplace(str, '.', '/'));
-	buf = utf8buf->data;
-
-	if (buf[0] == '[') {
-		clazz = loadArray(utf8buf, loader, &einfo);
-	}
-	else {
-		clazz = loadClass(utf8buf, loader, &einfo);
-	}
-
-	/* if an error occurred, throw an exception */
-	if (clazz == 0) {
-		/* The only checked exception that Class.forName() throws
-		 * is ClassNotFoundException.  This is an exception, not an
-		 * Error, which users often catch.
-		 *
-		 * However, Class.forName() can also throw errors, such as
-		 * NoClassDefFoundError, if for instance a superclass for
-		 * a class couldn't be found.
-		 *
-		 * When it throws which, we don't really know.  We try to be
-		 * compatible, so we upgrade the error to an exception if it's
-		 * (NoClassDefFoundError, this_class_name), or if it's a
-		 * VerifyError.
-		 * NB: 1.2 seems to be more consistent and throws
-		 * ClassNotFoundException in most cases.
-		 */
-		if ((einfo.type & KERR_EXCEPTION) && !strcmp(einfo.classname, "java.lang.VerifyError"))
-		{
-			errorInfo einfo_copy = einfo;
-			postExceptionMessage(&einfo,
-				JAVA_LANG(ClassNotFoundException),
-				"%s", einfo.mess);
-			discardErrorInfo(&einfo_copy);
-		} else
-		if ((einfo.type & KERR_EXCEPTION) && !strcmp(einfo.classname, "java.lang.NoClassDefFoundError"))
-		{
-			/*
-			 * However, we don't upgrade if it is a second attempt
-			 * to load a class whose loading has already failed.
-			 */
-			classEntry* centry;
-			centry = lookupClassEntry(utf8buf, loader, &einfo);
-			if (centry == 0 || (centry->class &&
-			    centry->class->state == CSTATE_FAILED)) {
-				utf8ConstRelease(utf8buf);
-				throwError(&einfo);
-			}
-
-			/* This is not quite what Sun does: they use the
-			 * classname, we use the pathname as the message
-			 * of the exception  (FIXME?)
-			 */
-			if (buf[0] == '[' || !strcmp(einfo.mess, buf)) {
-				errorInfo einfo_copy = einfo;
-				postExceptionMessage(&einfo,
-					JAVA_LANG(ClassNotFoundException),
-					"%s", einfo.mess);
-				discardErrorInfo(&einfo_copy);
-			}
-		}
-		utf8ConstRelease(utf8buf);
-		throwError(&einfo);
-	}
-	utf8ConstRelease(utf8buf);
-
-	/*
-	 * loadClass returns the class in state CSTATE_LINKED.
-	 *
-	 * Processing to CSTATE_COMPLETE will initialize the class, resolve
-	 * its constants and run its static initializers.
-	 *
-	 * The option to load a class via forName without initializing it
-	 * was introduced in 1.2, presumably for the convenience of
-	 * programs such as stub compilers.
-	 */
-	if (doinit && processClass(clazz, CSTATE_COMPLETE, &einfo) == false) {
-		throwError(&einfo);
-	}
-	return (clazz);
-}
-
-/*
  * Convert class to string name.
  */
 struct Hjava_lang_String*
diff -ur -x CVS -x Make* /home/topic/kaffe/libraries/clib/native/ClassLoader.c libraries/clib/native/ClassLoader.c
--- /home/topic/kaffe/libraries/clib/native/ClassLoader.c	Thu May 30 23:03:51 2002
+++ libraries/clib/native/ClassLoader.c	Sat Jun  1 01:55:08 2002
@@ -127,7 +127,7 @@
 java_lang_ClassLoader_resolveClass0(struct Hjava_lang_ClassLoader* this, struct Hjava_lang_Class* class)
 {
 	errorInfo info;
-	if (processClass(class, CSTATE_LINKED, &info) == false) {
+	if (processClass(class, CSTATE_COMPLETE, &info) == false) {
 		throwError(&info);
 	}
 }
diff -ur -x CVS -x Make* /home/topic/kaffe/libraries/clib/native/SystemClassLoader.c libraries/clib/native/SystemClassLoader.c
--- /home/topic/kaffe/libraries/clib/native/SystemClassLoader.c	Thu May 30 23:03:51 2002
+++ libraries/clib/native/SystemClassLoader.c	Sun Jun  2 11:37:42 2002
@@ -53,8 +53,14 @@
 
 		c = utf8ConstNew(name, len);
 		if (c) {
+		    if (c->data[0] == '[') {
+			clazz = loadArray(c, 0, &info);
+		    }
+		    else {
 			clazz = loadClass(c, 0, &info);
-			utf8ConstRelease(c);
+		    }
+
+		    utf8ConstRelease(c);
 		}
 	}
 
@@ -63,15 +69,40 @@
 		 * upgrade error to an exception if *this* class wasn't found.
 		 * See discussion in Class.forName()
 		 */
-		if (!strcmp(info.classname, "java.lang.NoClassDefFoundError")
-		    && !strcmp(info.mess, name))
-		{
-			errorInfo info_tmp = info;
-			postExceptionMessage(&info,
-				JAVA_LANG(ClassNotFoundException), 
-				"%s", info.mess);
-			discardErrorInfo(&info_tmp);
+		if (!strcmp(info.classname, "java.lang.NoClassDefFoundError")) {
+			/*
+			 * However, we don't upgrade if it is a second attempt
+			 * to load a class whose loading has already failed.
+			 */
+			classEntry* centry;
+
+			stringJava2CBuf(str, name, len+1);
+			classname2pathname(name, name);
+			c = utf8ConstNew(name, len);
+
+			centry = lookupClassEntry(c, 0, &info);
+			if (centry == 0
+			    || (centry->class
+				&& centry->class->state == CSTATE_FAILED)) {
+				utf8ConstRelease(c);
+				throwError(&info);
+			}
+			utf8ConstRelease(c);
+
+			if (!strcmp(info.mess, name)) {
+				errorInfo info_tmp = info;
+				postExceptionMessage(&info,
+						     JAVA_LANG(ClassNotFoundException), 
+						     "%s", info.mess);
+				discardErrorInfo(&info_tmp);
+			}
+		}
+		else if ((info.type & KERR_EXCEPTION)
+			 && !strcmp(info.classname, "java.lang.NoClassDefFoundError"))
+                {
+
 		}
+
 		if (name != buffer) {
 			KFREE(name);
 		}
diff -ur -x CVS -x Make* /home/topic/kaffe/libraries/javalib/java/lang/Class.java libraries/javalib/java/lang/Class.java
--- /home/topic/kaffe/libraries/javalib/java/lang/Class.java	Thu May 30 23:04:14 2002
+++ libraries/javalib/java/lang/Class.java	Mon Jun  3 00:27:03 2002
@@ -35,32 +35,64 @@
 private Class() {
 }
 
-/*
- * We must use the ClassLoader associated with the calling method/class.
- * We must handle the special case of code like this:
- *
- *    Class c = Class.class;
- *    Method m = c.getMethod("forName", new Class[] { String.class });
- *    c = (Class)m.invoke(c, new Object[] { "Class2" });
- *
- * If we didn't, then we would detect java.lang.reflect.Method as the
- * calling class, and end up always using the bootstrap ClassLoader.
- * To deal with this, we skip over java.lang.reflect.Method.
- *
- * Since Method.invoke implementation has a java and a native part,
- * we need to skip both.
- */
 public static Class forName(String className) throws ClassNotFoundException {
-	Class callingClass = getStackClass(1);
-	if (callingClass != null
-	    && callingClass.getName().equals("java.lang.reflect.Method"))
-		callingClass = getStackClass(3);
-	return forName(className, true,
-	    callingClass == null ? null : callingClass.getClassLoader());
+	return forName(className, true, null);
 }
 
-public static native Class forName(String className,
-	boolean initialize, ClassLoader loader) throws ClassNotFoundException;
+public static Class forName(String className, boolean initialize, ClassLoader loader) throws ClassNotFoundException {
+        /*
+         * NB: internally, we store class names as path names (with slashes
+         *     instead of dots.  However, we must also prevent calls to
+         *     "java/lang/Object" or "[[Ljava/lang/Object;" from succeeding.
+         *      Since class names cannot have slashes, we reject all attempts
+         *      to look up names that do.  Awkward.  Inefficient.
+         */
+	if (className.indexOf('/') != -1) {
+		throw new ClassNotFoundException("Cannot have slashes - use dots instead.");
+	}
+
+	/* find the appropriate class loader */
+	if (loader == null) {
+
+		loader = CallStack.getCallersClassLoader();
+		/* if loader is null, then the calling class has been loaded by the
+		 * bootstrap class loader. We can use the system class loader to
+		 * load the requested class.
+		 */
+		if (loader == null) {
+			loader = SystemClassLoader.getClassLoader();
+		}
+	}
+
+	/* The only checked exception that Class.forName() throws
+	 * is ClassNotFoundException.  This is an exception, not an
+	 * Error, which users often catch.
+	 *
+	 * However, Class.forName() can also throw errors, such as
+	 * NoClassDefFoundError, if for instance a superclass for
+	 * a class couldn't be found.
+	 *
+	 * When it throws which, we don't really know.  We try to be
+	 * compatible, so we upgrade the error to an exception if it's
+	 * (NoClassDefFoundError, this_class_name), or if it's a
+	 * VerifyError.
+	 * NB: 1.2 seems to be more consistent and throws
+	 * ClassNotFoundException in most cases.
+	 */
+
+	Class cls = loader.findLoadedClass(className);
+
+	if (cls == null) {
+		try {
+			cls = loader.loadClass(className, initialize);
+		}
+		catch (VerifyError error) {
+			throw new ClassNotFoundException(error.getMessage());
+		}
+	}
+
+	return cls;
+}
 
 private String fullResourceName(String name) {
 	if (name.charAt(0) == '/') {
@@ -368,25 +400,95 @@
 	    + getName();
 }
 
+/* CallStack is used to encapsulate call stack based
+ * class loader inspection.
+ *
+ * It is used by Class.forName and other methods in 
+ * java.lang that need to get hold of the ClassLoader
+ * associated with their calling class.
+ */
+static class CallStack {
+	private Class [] classStack;
+
+	CallStack() {
+		classStack = SecurityManager.getClassContext0();
+	}
+
+	/* This method walks the call stack to find the
+	 * class loader of the calling class. It takes care
+	 * of recursive calls within library implementation,
+	 * and Method.invoke.
+	 */
+	static ClassLoader getCallersClassLoader() {
+		CallStack callStack = new CallStack();
+		/* This method is caling CallStack(),
+		 * and we want the method calling this method.
+		 * So the start frame is 2.
+		 */
+		int frame = 2;
+		Class callingClass = callStack.getStackClass(frame);
+
+		/* We could have been called recursively
+		 * within a class implementation. Then we
+		 * need to walk up the stack to find the
+		 * real calling class.
+		 */
+		if (null != callingClass
+		    && callStack.getStackClass(frame - 1) == callingClass) {
+			while (callStack.getStackClass(++frame) == callingClass) {
+			}
+
+			callingClass = callStack.getStackClass(frame);
+		}
+
+		/*
+		 * We must use the ClassLoader associated with the calling method/class.
+		 * We must handle the special case of code like this:
+		 *
+		 *    Class c = Class.class;
+		 *    Method m = c.getMethod("forName", new Class[] { String.class });
+		 *    c = (Class)m.invoke(c, new Object[] { "Class2" });
+		 *
+		 * If we didn't, then we would detect java.lang.reflect.Method as the
+		 * calling class, and end up always using the bootstrap ClassLoader.
+		 * To deal with this, we skip over java.lang.reflect.Method.
+		 *
+		 * Since Method.invoke implementation has a java and a native part,
+		 * we need to skip both.
+		 */
+
+		if (callingClass != null
+		    && callingClass.getName().equals("java.lang.reflect.Method")) {
+			frame += 2;
+			callingClass = callStack.getStackClass(frame);
+		}
+
+		if (callingClass != null) {
+			return callingClass.getClassLoader();
+		}
+
+		return null;
+	}
+
 /*
  * Determine the Class associated with the method N frames up the stack:
  *
  * Frame #      Method
  * -------      ------
  *   -2		SecurityManager.getClassContext0()
- *   -1		Class.getStackClass()
- *    0		The method calling Class.getStackClass()
- *    1		The method calling the method calling Class.getStackClass()
+ *   -1         Class.CallStack()
+ *    0		The method calling Class.CallStack()
+ *    1		The method calling the method calling Class.CallStack()
  *    2		...etc...
  *
  * Returns null if not found.
  */
-static Class getStackClass(int frame) {
-	Class[] classStack = SecurityManager.getClassContext0();
-	frame += 2;
-	if (frame >= 0 && frame < classStack.length)
-		return classStack[frame];
-	return null;
+	private Class getStackClass(int frame) {
+		frame += 2;
+		if (frame >= 0 && frame < classStack.length) {
+			return classStack[frame];
+		}
+		return null;
+	}
 }
-
 }
diff -ur -x CVS -x Make* /home/topic/kaffe/libraries/javalib/java/lang/Runtime.java libraries/javalib/java/lang/Runtime.java
--- /home/topic/kaffe/libraries/javalib/java/lang/Runtime.java	Thu May 30 23:04:14 2002
+++ libraries/javalib/java/lang/Runtime.java	Mon Jun  3 00:13:12 2002
@@ -123,7 +123,8 @@
 }
 
 public void loadLibrary(String libname) {
-	loadLibrary(libname, Class.getStackClass(1).getClassLoader());
+	loadLibrary(libname,
+		    Class.CallStack.getCallersClassLoader());
 }
 
 void loadLibrary(String libname, ClassLoader loader) {
@@ -151,7 +152,7 @@
 }
 
 public void load(String filename) {
-	load(filename, Class.getStackClass(1).getClassLoader());
+	load(filename, Class.CallStack.getCallersClassLoader());
 }
 
 void load(String filename, ClassLoader loader) {
diff -ur -x CVS -x Make* /home/topic/kaffe/libraries/javalib/java/lang/System.java libraries/javalib/java/lang/System.java
--- /home/topic/kaffe/libraries/javalib/java/lang/System.java	Thu May 30 23:04:13 2002
+++ libraries/javalib/java/lang/System.java	Mon Jun  3 00:12:38 2002
@@ -135,12 +135,12 @@
 
 public static void load(String filename) {
 	Runtime.getRuntime().load(filename,
-	    Class.getStackClass(1).getClassLoader());
+	    Class.CallStack.getCallersClassLoader());
 }
 
 public static void loadLibrary(String libname) {
 	Runtime.getRuntime().loadLibrary(libname,
-	    Class.getStackClass(1).getClassLoader());
+	    Class.CallStack.getCallersClassLoader());
 }
 
 public static String mapLibraryName(String fn) {
diff -ur -x CVS -x Make* /home/topic/kaffe/libraries/javalib/kaffe/lang/SystemClassLoader.java libraries/javalib/kaffe/lang/SystemClassLoader.java
--- /home/topic/kaffe/libraries/javalib/kaffe/lang/SystemClassLoader.java	Thu May 30 23:04:29 2002
+++ libraries/javalib/kaffe/lang/SystemClassLoader.java	Mon Jun  3 00:46:40 2002
@@ -28,6 +28,19 @@
 	super(null);		// this line is not really necessary!
 }
 
+private static String componentType(String name) {
+	int componentStart = name.lastIndexOf('[') + 1;
+	if (name.charAt(componentStart) == 'L' && name.endsWith(";")) {
+		return name.substring(componentStart + 1, name.length() - 1);
+	}
+	else if (name.length() - componentStart > 1) {
+		return name.substring(componentStart);
+	}
+	else {
+		return name.substring(componentStart - 1);
+	}
+}
+
 public static ClassLoader getClassLoader() {
 	return (singleton);
 }
@@ -85,6 +98,27 @@
 }
 
 protected Class findClass(String name) throws ClassNotFoundException {
+	/* Arrays of void are not allowed.
+	 * The simplest way to handle it is here.
+	 */
+	if (name.endsWith("[V")) {
+		throw new ClassNotFoundException(name);
+	}
+	/* Arrays of bad types would throw a NoClassDefFoundError.
+	 * Catch it here, and rethrow as ClassNotFoundException.
+	 */
+	else if (name.startsWith("[")
+		 && name.length() >= 3) {
+		try {
+			/* load the component type */
+			String componentName = componentType(name);
+			loadClass(componentName);
+		}
+		catch (NoClassDefFoundError error) {
+			throw new ClassNotFoundException(error.getMessage());
+		}
+	}
+
 	return findClass0(name);
 }
 
