Below is a subset of my current set of diffs for java.lang.Class. I'm sending them just for anyone to look at and for consideration for checking in. I think some of them could be useful for classpath. I'd be interested to hear what other people think.
Notes about this patch... - The 'vmData' field is VM specific, ignore that part. A neat idea stolen from SableVM. - The Class.initialize() method is from SableVM and I like it a lot as it simplifies the work that the JVM has to do for class initialization. Since initialization is a one time thing it's less important if things are slower. The integer thread ID might need to be generalized to long or byte[] or something. - Is the Class.forName() patch correct?? I just uncommented the code that was already there but commented out. - getComponentType() became native, this is probably VM specific. Seems like an obvious and easy native method though. - Several of the get*Field*(), get*Method*(), and get*Constructor() methods became non-native. This may make them slower (?) but for me it's worth it because it saves a lot of work in the VM. Cheers, -Archie __________________________________________________________________________ Archie Cobbs * Precision I/O * http://www.precisionio.com --- classpath/classpath-0.05/vm/reference/java/lang/Class.java Sat Oct 26 11:41:59 2002 +++ /home/archie/jc/classpath/java/lang/Class.java Thu Feb 27 17:24:32 2003 @@ -42,11 +42,14 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Member; import java.lang.reflect.Method; import java.net.URL; import java.security.AllPermission; import java.security.Permissions; import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.Arrays; import gnu.java.lang.ClassHelper; /* @@ -103,11 +106,102 @@ } /** + * Pointer to VM internal class structure. + */ + private final byte[] vmData; + + /** * Class is non-instantiable from Java code; only the VM can create * instances of this class. */ - private Class() + private Class(byte[] vmData) { + this.vmData = vmData; + } + + /* + * Class initialization mostly-in-Java copied from SableVM. + * The steps below follow the JVM spec, 2nd edition, sec. 2.17.5. + */ + private int initializing_thread; + private boolean erroneous_state; + + private native boolean isInitialized(); + private native void setInitialized(); + private native void step7(); + private native void step8(); + + private void initialize(int thread) throws InterruptedException + { + Error error; + + /* 1 */ + synchronized (this) + { + /* 2 */ + while (initializing_thread != 0 && initializing_thread != thread) + wait(); + + /* 3 */ + if (initializing_thread == thread) + return; + + /* 4 */ + if (isInitialized()) + return; + + /* 5 */ + if (erroneous_state) + throw new NoClassDefFoundError(); + + /* 6 */ + initializing_thread = thread; + } + + /* 7 */ + try { + step7(); + } + catch(Error e) { + synchronized(this) { + erroneous_state = true; + initializing_thread = 0; + notifyAll(); + throw e; + } + } + + /* 8 */ + try { + step8(); + + /* 9 */ + synchronized(this) { + setInitialized(); + initializing_thread = 0; + notifyAll(); + return; + } + } + + /* 10 */ + catch(Exception e) { + try { + error = new ExceptionInInitializerError(e); + } catch (OutOfMemoryError e2) { + error = e2; + } + } catch(Error e) { + error = e; + } + + /* 11 */ + synchronized(this) { + erroneous_state = true; + initializing_thread = 0; + notifyAll(); + throw error; + } } /** @@ -137,15 +231,11 @@ * @throws ExceptionInInitializerError if the class loads, but an exception * occurs during initialization */ - //XXX This does not need to be native. - public static native Class forName(String name) - throws ClassNotFoundException; - /* + public static Class forName(String name) throws ClassNotFoundException { return forName(name, true, VMSecurityManager.getClassContext()[1].getClassLoader()); } - */ /** * Use the specified classloader to load and link a class. If the loader @@ -313,7 +403,7 @@ * void V * array type [<em>element type</em> * class or interface, alone: <dotted name> - * class or interface, as element type: L<dotten name>; + * class or interface, as element type: L<dotted name>; * * @return the name of this class */ @@ -400,46 +490,7 @@ * @see Array * @since 1.1 */ - public Class getComponentType() - { - if (isArray()) - try - { - String name = getName(); - switch (name.charAt(1)) - { - case 'B': - return byte.class; - case 'C': - return char.class; - case 'D': - return double.class; - case 'F': - return float.class; - case 'I': - return int.class; - case 'J': - return long.class; - case 'S': - return short.class; - case 'Z': - return boolean.class; - default: - return null; - case '[': - name = name.substring(1); - break; - case 'L': - name = name.substring(2, name.length() - 1); - } - return Class.forName(name, false, getClassLoader()); - } - catch(ClassNotFoundException e) - { - // Shouldn't happen, but ignore it anyway. - } - return null; - } + public native Class getComponentType(); /** * Get the modifiers of this class. These can be decoded using Modifier, @@ -478,6 +529,20 @@ } /** + * Perform security checks common to all of the methods that + * get members of this Class. + */ + private void memberAccessCheck(int which) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkMemberAccess(this, which); + Package pkg = getPackage(); + if (pkg != null) + sm.checkPackageAccess(pkg.getName()); + } + } + + /** * If this is a nested or inner class, return the class that declared it. * If not, return null. * @@ -498,7 +563,22 @@ * @throws SecurityException if the security check fails * @since 1.1 */ - public native Class[] getClasses(); + public Class[] getClasses() { + memberAccessCheck(Member.PUBLIC); + return internalGetClasses(); + } + + /** + * Like <code>getClasses()</code> but without the security checks. + */ + private Class[] internalGetClasses() { + ArrayList list = new ArrayList(); + list.add(Arrays.asList(nativeGetDeclaredClasses(true))); + Class superClass = getSuperclass(); + if (superClass != null) + list.add(Arrays.asList(superClass.internalGetClasses())); + return (Class[])list.toArray(new Class[list.size()]); + } /** * Get all the public fields declared in this class or inherited from @@ -512,7 +592,28 @@ * @throws SecurityException if the security check fails * @since 1.1 */ - public native Field[] getFields(); + public Field[] getFields() { + memberAccessCheck(Member.PUBLIC); + return internalGetFields(); + } + + /** + * Like <code>getFields()</code> but without the security checks. + */ + private Field[] internalGetFields() { + ArrayList list = new ArrayList(); + list.add(Arrays.asList(nativeGetDeclaredFields(true))); + if (isInterface()) { + Class[] interfaces = getInterfaces(); + for (int i = 0; i < interfaces.length; i++) + list.add(Arrays.asList(interfaces[i].internalGetFields())); + } else { + Class superClass = getSuperclass(); + if (superClass != null) + list.add(Arrays.asList(superClass.internalGetFields())); + } + return (Field[])list.toArray(new Field[list.size()]); + } /** * Get all the public methods declared in this class or inherited from @@ -530,7 +631,25 @@ * @throws SecurityException if the security check fails * @since 1.1 */ - public native Method[] getMethods(); + public Method[] getMethods() { + memberAccessCheck(Member.PUBLIC); + return internalGetMethods(); + } + + /** + * Like <code>getMethods()</code> but without the security checks. + */ + private Method[] internalGetMethods() { + ArrayList list = new ArrayList(); + list.add(Arrays.asList(nativeGetDeclaredMethods(true))); + Class[] interfaces = getInterfaces(); + for (int i = 0; i < interfaces.length; i++) + list.add(Arrays.asList(interfaces[i].internalGetMethods())); + Class superClass = getSuperclass(); + if (superClass != null) + list.add(Arrays.asList(superClass.internalGetMethods())); + return (Method[])list.toArray(new Method[list.size()]); + } /** * Get all the public constructors of this class. This returns an array of @@ -544,7 +663,10 @@ * @throws SecurityException if the security check fails * @since 1.1 */ - public native Constructor[] getConstructors(); + public Constructor[] getConstructors() { + memberAccessCheck(Member.PUBLIC); + return nativeGetDeclaredConstructors(true); + } /** * Get a public field declared or inherited in this class, where name is @@ -561,7 +683,26 @@ * @see #getFields() * @since 1.1 */ - public native Field getField(String name) throws NoSuchFieldException; + public Field getField(String name) throws NoSuchFieldException { + memberAccessCheck(Member.PUBLIC); + Field[] fields = nativeGetDeclaredFields(true); + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + if (field.getName().equals(name)) + return field; + } + Class[] interfaces = getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + try { + return interfaces[i].getField(name); + } catch (NoSuchFieldException e) { + } + } + Class superclass = getSuperclass(); + if (superclass != null) + return superclass.getField(name); + throw new NoSuchFieldException(); + } /** * Get a public method declared or inherited in this class, where name is @@ -585,8 +726,62 @@ * @see #getMethods() * @since 1.1 */ - public native Method getMethod(String name, Class[] args) - throws NoSuchMethodException; + public Method getMethod(String name, Class[] args) + throws NoSuchMethodException { + memberAccessCheck(Member.PUBLIC); + for (Class c = this; c != null; c = c.getSuperclass()) { + Method match = matchMethod(c.nativeGetDeclaredMethods(true), name, args); + if (match != null) + return match; + } + throw new NoSuchMethodException(); + } + + /** + * Find the best matching method in <code>list</code> according to + * the definition of ``best matching'' used by <code>getMethod()</code> + * + * <p> + * Returns the method if any, otherwise <code>null</code>. + * + * @param list List of methods to search + * @param name Name of method + * @param args Method parameter types + * @see #getMethod() + */ + private static Method matchMethod(Method[] list, String name, Class[] args) { + Method match = null; + for (int i = 0; i < list.length; i++) { + Method method = list[i]; + if (!method.getName().equals(name)) + continue; + if (!matchParameters(args, method.getParameterTypes())) + continue; + if (match == null + || match.getReturnType().isAssignableFrom(method.getReturnType())) + match = method; + } + return match; + } + + /** + * Check for an exact match between parameter type lists. + * Either list may be <code>null</code> to mean a list of + * length zero. + */ + private static boolean matchParameters(Class[] types1, Class[] types2) { + if (types1 == null) + return types2 == null || types2.length == 0; + if (types2 == null) + return types1 == null || types1.length == 0; + if (types1.length != types2.length) + return false; + for (int i = 0; i < types1.length; i++) { + if (!types1[i].equals(types2[i])) + return false; + } + return true; + } /** * Get a public constructor declared in this class. If the constructor takes @@ -602,8 +797,16 @@ * @see #getConstructors() * @since 1.1 */ - public native Constructor getConstructor(Class[] args) - throws NoSuchMethodException; + public Constructor getConstructor(Class[] args) throws NoSuchMethodException { + memberAccessCheck(Member.PUBLIC); + Constructor[] constructors = nativeGetDeclaredConstructors(true); + for (int i = 0; i < constructors.length; i++) { + Constructor constructor = constructors[i]; + if (matchParameters(args, constructor.getParameterTypes())) + return constructor; + } + throw new NoSuchMethodException(); + } /** * Get all the declared member classes and interfaces in this class, but @@ -617,7 +820,17 @@ * @throws SecurityException if the security check fails * @since 1.1 */ - public native Class[] getDeclaredClasses(); + public Class[] getDeclaredClasses() { + memberAccessCheck(Member.DECLARED); + return nativeGetDeclaredClasses(false); + } + + /** + * Like <code>getDeclaredClasses()</code> but without the security checks. + * + * @param pulicOnly Only public classes should be returned + */ + private native Class[] nativeGetDeclaredClasses(boolean pulicOnly); /** * Get all the declared fields in this class, but not those inherited from @@ -631,7 +844,17 @@ * @throws SecurityException if the security check fails * @since 1.1 */ - public native Field[] getDeclaredFields(); + public Field[] getDeclaredFields() { + memberAccessCheck(Member.DECLARED); + return nativeGetDeclaredFields(false); + } + + /** + * Like <code>getDeclaredFields()</code> but without the security checks. + * + * @param pulicOnly Only public fields should be returned + */ + private native Field[] nativeGetDeclaredFields(boolean pulicOnly); /** * Get all the declared methods in this class, but not those inherited from @@ -649,7 +872,17 @@ * @throws SecurityException if the security check fails * @since 1.1 */ - public native Method[] getDeclaredMethods(); + public Method[] getDeclaredMethods() { + memberAccessCheck(Member.DECLARED); + return nativeGetDeclaredMethods(false); + } + + /** + * Like <code>getDeclaredMethods()</code> but without the security checks. + * + * @param pulicOnly Only public methods should be returned + */ + private native Method[] nativeGetDeclaredMethods(boolean pulicOnly); /** * Get all the declared constructors of this class. This returns an array of @@ -663,7 +896,19 @@ * @throws SecurityException if the security check fails * @since 1.1 */ - public native Constructor[] getDeclaredConstructors(); + public Constructor[] getDeclaredConstructors() { + memberAccessCheck(Member.DECLARED); + return nativeGetDeclaredConstructors(false); + } + + /** + * Like <code>getDeclaredConstructors()</code> but without + * the security checks. + * + * @param pulicOnly Only public constructors should be returned + */ + private native Constructor[] + nativeGetDeclaredConstructors(boolean publicOnly); /** * Get a field declared in this class, where name is its simple name. The @@ -678,8 +923,15 @@ * @see #getDeclaredFields() * @since 1.1 */ - public native Field getDeclaredField(String name) - throws NoSuchFieldException; + public Field getDeclaredField(String name) throws NoSuchFieldException { + memberAccessCheck(Member.DECLARED); + Field[] fields = nativeGetDeclaredFields(false); + for (int i = 0; i < fields.length; i++) { + if (fields[i].getName().equals(name)) + return fields[i]; + } + throw new NoSuchFieldException(); + } /** * Get a method declared in this class, where name is its simple name. The @@ -702,8 +954,14 @@ * @see #getDeclaredMethods() * @since 1.1 */ - public native Method getDeclaredMethod(String name, Class[] args) - throws NoSuchMethodException; + public Method getDeclaredMethod(String name, Class[] args) + throws NoSuchMethodException { + memberAccessCheck(Member.DECLARED); + Method match = matchMethod(nativeGetDeclaredMethods(false), name, args); + if (match != null) + return match; + throw new NoSuchMethodException(); + } /** * Get a constructor declared in this class. If the constructor takes no @@ -719,8 +977,17 @@ * @see #getDeclaredConstructors() * @since 1.1 */ - public native Constructor getDeclaredConstructor(Class[] args) - throws NoSuchMethodException; + public Constructor getDeclaredConstructor(Class[] args) + throws NoSuchMethodException { + memberAccessCheck(Member.DECLARED); + Constructor[] constructors = nativeGetDeclaredConstructors(false); + for (int i = 0; i < constructors.length; i++) { + Constructor constructor = constructors[i]; + if (matchParameters(args, constructor.getParameterTypes())) + return constructor; + } + throw new NoSuchMethodException(); + } /** * Get a resource using this class's package using the _______________________________________________ Classpath mailing list [EMAIL PROTECTED] http://mail.gnu.org/mailman/listinfo/classpath