classpath
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

java.lang.Class patches


From: Archie Cobbs
Subject: java.lang.Class patches
Date: Thu, 27 Feb 2003 21:26:19 -0800 (PST)

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: &lt;dotted name&gt;
-   * class or interface, as element type: L&lt;dotten name&gt;;
+   * class or interface, as element type: L&lt;dotted name&gt;;
    *
    * @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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]