large Class.forName() patch

Mo DeJong mdejong at cygnus.com
Fri Jan 28 17:35:42 PST 2000


Hi all.

I have been working on getting Class.forName() working more like
the Sun JDK and I have a patch that I would like to get some comments
on. I have attached a file called ArrayForName.java which tests
the Class.forName() method and compares the result to an expected
result. First, try running this test case on the current CVS version
of Kaffe to see how many failures you get. Then apply the patch
called forname.patch and check out how many problems it fixes.

I feel good about almost all of the changes in the patch, except
for the first on (the one in file classMethod.c around line 1035).

I am not sure if this would break JNI code, or if was just the wrong
place to make the change. Could someone who knows more about the
internals check it out and suggest a better change if there is one?

thanks
Mo Dejong
Red Hat Inc.
-------------- next part --------------
public class ArrayForName {

    public static void testLoadArray() throws Exception {

	// Loading by built-in type ID is not allowed
	// int          != I
	// boolean      != Z
	// long         != J
	// float        != F
	// double       != D
	// byte         != B
        // short        != S
	// char         != C
	// void         != V

	expect("I", "Exception");
	expect("Z", "Exception");
	expect("J", "Exception");
	expect("F", "Exception");
	expect("D", "Exception");
	expect("B", "Exception");
	expect("S", "Exception");
	expect("C", "Exception");
	expect("V", "Exception");

	// Not possible to load by builtin type name

	expect("int",     "Exception");
	expect("boolean", "Exception");
	expect("long",    "Exception");
	expect("float",   "Exception");
	expect("double",  "Exception");
	expect("byte",    "Exception");
	expect("short",   "Exception");
	expect("char",    "Exception");
	expect("void",    "Exception");

	// Test loading an array by built-in type id
	// int[]        == [I
	// int[][]      == [[I
	// boolean[]    == [Z
	// boolean[][]  == [[Z
	// long[]       == [J
	// long[][]     == [[J
	// float[]      == [F
	// float[][]    == [[F
	// double[]     == [D
	// double[][]   == [[D
	// byte[]       == [B
	// byte[][]     == [[B
	// short[]      == [S
	// short[][]    == [[S
	// char[]       == [C
	// char[][]     == [[C

	expect("[I",  "int[]");
	expect("[[I", "int[][]");
	expect("[Z",  "boolean[]");
	expect("[[Z", "boolean[][]");
	expect("[J",  "long[]");
	expect("[[J", "long[][]");
	expect("[F",  "float[]");
	expect("[[F", "float[][]");
	expect("[D",  "double[]");
	expect("[[D", "double[][]");
	expect("[B",  "byte[]");
	expect("[[B", "byte[][]");
	expect("[S",  "short[]");
	expect("[[S", "short[][]");
	expect("[C",  "char[]");
	expect("[[C", "char[][]");

	// Array of type void is not allowed

	expect("[V",    "Exception");
	expect("[[V",   "Exception");
	expect("[[[V",  "Exception");

	// When loading an array using the built-in
	// type id, id must be at end of string

	expect("[II",   "Exception");
	expect("[ZZ",   "Exception");
	expect("[JJ",   "Exception");
	expect("[FF",   "Exception");
	expect("[DD",   "Exception");
	expect("[BB",   "Exception");
	expect("[SS",   "Exception");
	expect("[CC",   "Exception");
	expect("[ZZ",   "Exception");
	expect("[C;",   "Exception");
	expect("[C\0;", "Exception");

	// [L + Class + ;
	// Primitive Class name is not valid 

	expect("[Lint;",     "Exception");
	expect("[Lboolean;", "Exception");
	expect("[Llong;",    "Exception");
	expect("[Lfloat;",   "Exception");
	expect("[Ldouble;",  "Exception");
	expect("[Lbyte;",    "Exception");
	expect("[Lshort;",   "Exception");
	expect("[Lchar;",    "Exception");
	expect("[Lvoid;",    "Exception");

	// java.lang.Object[]     == [Ljava.lang.Object;
	// java.lang.Object[][]   == [[Ljava.lang.Object;
	// java.lang.String[]     == [Ljava.lang.String;
	// java.lang.String[][]   == [[Ljava.lang.String;

	expect("[Ljava.lang.Object;",  "java.lang.Object[]");
	expect("[[Ljava.lang.Object;", "java.lang.Object[][]");
	expect("[Ljava.lang.String;",  "java.lang.String[]");
	expect("[[Ljava.lang.String;", "java.lang.String[][]");

	// L + Class must follow 0-N [ characters

	expect("Ljava.lang.Object;", "Exception");
	expect("Ljava.lang.String;", "Exception");

	// Misc invalid class names

	expect("L",          "Exception");
	expect("L;",         "Exception");
	expect("LS;",        "Exception");
	expect("[LObject;",  "Exception");
	expect("[[LObject;", "Exception");
	expect("[LString;",  "Exception");
	expect("[[LString;", "Exception");
	expect("[[String;",  "Exception");
	expect("[[Object;",  "Exception");
	expect("[[int;",     "Exception");
	expect("LString;",   "Exception");
	expect("L;",         "Exception");
	expect("[[Q",        "Exception");
	expect("[void",      "Exception");
	expect("",           "Exception");
    }

    static void expect(String clsName, String expected) throws Exception {
	String result = loadByName(clsName);

	if (! result.equals(expected)) {
	    StringBuffer msg = new StringBuffer();

	    msg.append("for clsName \"" + clsName + "\" expected \"" +
		       expected + "\" but got \"" + result + "\"");

	    /*
	    throw new RuntimeException(msg.toString());
	    */
	    System.err.println(msg.toString());
	}
    }

    static String loadByName(String clsName) throws Exception {
    	try {
	    Class c = Class.forName(clsName);
	    if (c == null) {
		// This should never happen
		throw new NullPointerException("Class.forName(" +
		    clsName + ") returned null");
	    }
	    return getNameFromClass( c );
	} catch (IllegalArgumentException e) { // JDK 1.1
	    return "Exception";
	} catch (ClassNotFoundException e) { // JDK 1.2
	    return "Exception";
	}
    }

    static String getNameFromClass(Class type) {
	StringBuffer name = new StringBuffer();
    
	while (type.isArray()) {
	    name.append("[]");
	    type = type.getComponentType();
	}
	name.insert(0,type.getName());
	return name.toString();
    }
    
    public static void main(String[] argv) throws Exception {
	testLoadArray();	
    }
}





/*


  // These are error conditions that need to be handled by the JVM!


    public static void main(String[] argv) throws Exception {
	try {
	    Class.forName("[[[LInteger;");
	} catch (ClassNotFoundException e) {
	    System.out.println("caught 1");
	}

	try {
	    Class.forName("[int");
	} catch (IllegalArgumentException e) { // JDK 1.1
	    System.out.println("caught 2");
	} catch (ClassNotFoundException e) { // JDK 1.2
	    System.out.println("caught 2");
	} 
    }


*/



/*


for clsName "[[String;" expected "Exception" but got "short[][]"
for clsName "[[Lint;" expected "Exception" but got "int[][]"
for clsName "[[CC" expected "Exception" but got "char[][]"



for clsName "[II" expected "Exception" but got "int[]"
for clsName "[ZZ" expected "Exception" but got "boolean[]"
for clsName "[JJ" expected "Exception" but got "long[]"
for clsName "[FF" expected "Exception" but got "float[]"
for clsName "[DD" expected "Exception" but got "double[]"
for clsName "[BB" expected "Exception" but got "byte[]"
for clsName "[SS" expected "Exception" but got "short[]"
for clsName "[CC" expected "Exception" but got "char[]"


for clsName "[[String;" expected "Exception" but got "short[][]"
for clsName "[[Lint;" expected "Exception" but got "int[][]"




After the FIX!!


for clsName "[[Lint;" expected "Exception" but got "int[][]"

*/



/*
Final output

Sun
% java ArrayForName


Kaffe
for clsName "[C" expected "Exception" but got "char[]"
for clsName "[C;" expected "Exception" but got "char[]"

*/
-------------- next part --------------
Index: kaffe/kaffevm/classMethod.c
===================================================================
RCS file: /cvs/kaffe/kaffe/kaffe/kaffevm/classMethod.c,v
retrieving revision 1.75
diff -u -r1.75 classMethod.c
--- kaffe/kaffevm/classMethod.c	2000/01/19 11:04:31	1.75
+++ kaffe/kaffevm/classMethod.c	2000/01/29 01:19:59
@@ -1035,6 +1035,18 @@
 		}
 	}
 
+	/* This is kind of strange, but Sun's implementation
+	   does not allow lookups like Class.forName("int"),
+	   so if this is a primitive type, we just pretend
+	   it could not be found. It would be handy to load
+	   "int" or "char" by name, but oh well */
+
+	if (CLASS_IS_PRIMITIVE(clazz))
+	{
+		postException(einfo, JAVA_LANG(VerifyError));
+		clazz = 0;
+	}
+
 	return (clazz);
 }
 
@@ -1110,12 +1122,13 @@
 	}
 	class = loadClass(utf8, NULL, einfo);
 	utf8ConstRelease(utf8);
+
 	if (class != 0) {
 		if (processClass(class, CSTATE_COMPLETE, einfo) == true) {
 			return (class);
 		}
 	}
-	return (0);
+	return (NULL);
 }
 
 /*
@@ -2281,12 +2294,18 @@
 	/* If we couldn't resolve the element type, there's no way we can
 	 * construct the array type.
 	 */
-	if (c == 0) {
-		return (0);
+	if (c == NULL) {
+		return (NULL);
 	}
 
 	/* Build signature for array type */
 	if (CLASS_IS_PRIMITIVE (c)) {
+		/* An array of type void is not allowed */
+		if (strcmp(CLASS_CNAME(c), "void") == 0) {
+			postException(einfo, JAVA_LANG(VerifyError));
+			return (NULL);
+		}
+
 		arr_class = CLASS_ARRAY_CACHE(c);
 		if (arr_class) {
 			return (arr_class);
@@ -2304,12 +2323,12 @@
 	arr_name = utf8ConstNew(sig, -1);	/* release before returning */
 	if (!arr_name) {
 		postOutOfMemory(einfo);
-		return 0;
+		return (NULL);
 	}
 	centry = lookupClassEntry(arr_name, c->loader, einfo);
 	if (centry == 0) {
 		utf8ConstRelease(arr_name);
-		return (0);
+		return (NULL);
 	}
 
 	if (centry->class != 0) {
Index: kaffe/kaffevm/itypes.c
===================================================================
RCS file: /cvs/kaffe/kaffe/kaffe/kaffevm/itypes.c,v
retrieving revision 1.17
diff -u -r1.17 itypes.c
--- kaffe/kaffevm/itypes.c	1999/11/29 23:44:10	1.17
+++ kaffe/kaffevm/itypes.c	2000/01/29 01:19:59
@@ -131,21 +131,49 @@
 Hjava_lang_Class*
 classFromSig(const char** strp, Hjava_lang_ClassLoader* loader, errorInfo *einfo)
 {
-	Hjava_lang_Class* cl;
+	Hjava_lang_Class* cl = NULL;
 	Utf8Const* utf8;
 	const char* start;
 	const char* end;
 
 	switch (*(*strp)++) {
-	case 'V': return (voidClass);
-	case 'I': return (intClass);
-	case 'Z': return (booleanClass);
-	case 'S': return (shortClass);
-	case 'B': return (byteClass);
-	case 'C': return (charClass);
-	case 'F': return (floatClass);
-	case 'D': return (doubleClass);
-	case 'J': return (longClass);
+	case 'V':
+	    if (cl == NULL)
+		cl = voidClass;
+	case 'I':
+	    if (cl == NULL)
+		cl = intClass;
+	case 'Z':
+	    if (cl == NULL)
+		cl = booleanClass;
+	case 'S':
+	    if (cl == NULL)
+		cl = shortClass;
+	case 'B':
+	    if (cl == NULL)
+		cl = byteClass;
+	case 'C':
+	    if (cl == NULL)
+		cl = charClass;
+	case 'F':
+	    if (cl == NULL)
+		cl = floatClass;
+	case 'D':
+	    if (cl == NULL)
+		cl = doubleClass;
+	case 'J':
+	    if (cl == NULL)
+		cl = longClass;
+
+	    if (cl != NULL) {
+		/* If build in type char is not at the end of the string, malformed signature */
+		if (*(*strp) != 0) {
+		    postException(einfo, JAVA_LANG(VerifyError));
+		    return (NULL);
+		}
+	    }
+
+	    return (cl);
 	case '[': return (lookupArray(classFromSig(strp, loader, einfo),
 				      einfo));
 	case 'L':
@@ -159,11 +187,17 @@
 		utf8 = utf8ConstNew(start, end - start);
 		if (!utf8) {
 			postOutOfMemory(einfo);
-			return 0;
+			return (NULL);
 		}
 		cl = loadClass(utf8, loader, einfo);
 		utf8ConstRelease(utf8);
-		return(cl);
+
+		/* Only class names can appear after a [L in the class name */
+		if (cl && CLASS_IS_PRIMITIVE(cl)) {
+			postException(einfo, JAVA_LANG(VerifyError));
+			cl = NULL;
+		}
+		return (cl);
 	default:
 		/* malformed signature */
 		postException(einfo, JAVA_LANG(VerifyError));


More information about the kaffe mailing list