commit-classpath
[Top][All Lists]
Advanced

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

vm/reference reflection update


From: Grzegorz B. Prokopski
Subject: vm/reference reflection update
Date: Sun, 28 Mar 2004 00:22:12 -0500

This patch adds to the reference implementation this reflection
functionality, which can be realized in Java. 

2004-03-28  Grzegorz B. Prokopski <address@hidden> 

        * Merged vm/reference implementation of these reflection elements,
        that can be realized in Java:
        vm/reference/java/lang/reflect/Constructor.java,
        vm/reference/java/lang/reflect/Field.java,
        vm/reference/java/lang/reflect/Makefile.am,
        vm/reference/java/lang/reflect/Method.java,
        vm/reference/java/lang/reflect/ReflectUtil.java.

-- 
Grzegorz B. Prokopski <address@hidden>
Debian GNU/Linux      http://www.debian.org
SableVM - LGPLed JVM  http://www.sablevm.org
Why SableVM ?!?       http://devel.sablevm.org/wiki/WhySableVM
Index: ChangeLog
===================================================================
RCS file: /cvsroot/classpath/classpath/ChangeLog,v
retrieving revision 1.1962
diff -u -r1.1962 ChangeLog
--- ChangeLog   28 Mar 2004 01:21:55 -0000      1.1962
+++ ChangeLog   28 Mar 2004 05:16:19 -0000
@@ -1,3 +1,13 @@
+2004-03-28  Grzegorz B. Prokopski <address@hidden>
+
+        * Merged vm/reference implementation of these reflection elements,
+        that can be realized in Java:
+        vm/reference/java/lang/reflect/Constructor.java,
+        vm/reference/java/lang/reflect/Field.java,
+        vm/reference/java/lang/reflect/Makefile.am,
+        vm/reference/java/lang/reflect/Method.java,
+        vm/reference/java/lang/reflect/ReflectUtil.java.
+
 2004-03-27  Grzegorz B. Prokopski <address@hidden>
 
         * configure.ac: Added --with-jvm= handling defaulting to none.
Index: vm/reference/java/lang/reflect/Constructor.java
===================================================================
RCS file: 
/cvsroot/classpath/classpath/vm/reference/java/lang/reflect/Constructor.java,v
retrieving revision 1.9
diff -u -r1.9 Constructor.java
--- vm/reference/java/lang/reflect/Constructor.java     15 Aug 2003 01:25:31 
-0000      1.9
+++ vm/reference/java/lang/reflect/Constructor.java     28 Mar 2004 05:16:31 
-0000
@@ -76,23 +76,21 @@
 public final class Constructor
 extends AccessibleObject implements Member
 {
-  private Class clazz;
-  private int slot;
+
+  private Class declaringClass;
   private Class[] parameterTypes;
   private Class[] exceptionTypes;
   
   /**
    * This class is uninstantiable except from native code.
    */
-  private Constructor(Class declaringClass,int slot)
-  {
-    this.clazz = declaringClass;
-    this.slot = slot;
-  }
 
-  private Constructor()
+  byte[] vmData;
+  private Constructor(byte[] vmData)
   {
+    this.vmData = vmData;
   }
+ 
 
   /**
    * Gets the class that declared this constructor.
@@ -100,9 +98,18 @@
    */
   public Class getDeclaringClass()
   {
-    return clazz;
+    if (declaringClass == null)
+      {
+       declaringClass = nativeGetDeclaringClass(vmData);
+      }
+
+    return declaringClass;
+
   }
 
+  public static native Class nativeGetDeclaringClass(byte[] vmData);
+
+
   /**
    * Gets the name of this constructor (the non-qualified name of the class
    * it was declared in).
@@ -110,7 +117,8 @@
    */
   public String getName()
   {
-    return getDeclaringClass().getName();
+    String qualifiedName = getDeclaringClass().getName();
+    return qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1);
   }
 
   /**
@@ -121,7 +129,12 @@
    * @return an integer representing the modifiers to this Member
    * @see Modifier
    */
-  public native int getModifiers();
+  public int getModifiers()
+  {
+    return nativeGetModifiers(vmData);
+  }
+  public native int nativeGetModifiers(byte[] vmData);
+
 
   /**
    * Get the parameter list for this constructor, in declaration order. If the
@@ -132,7 +145,11 @@
   public Class[] getParameterTypes()
   {
     if (parameterTypes == null)
-      return new Class[0];
+    {
+      parameterTypes =
+        ReflectUtil.getParameterTypes(nativeGetDescriptor(vmData));
+
+    }
     return parameterTypes;
   }
 
@@ -143,12 +160,17 @@
    *
    * @return a list of the types in the constructor's throws clause
    */
+
   public Class[] getExceptionTypes()
   {
     if (exceptionTypes == null)
-      return new Class[0];
+    {
+      exceptionTypes = nativeGetExceptionTypes(vmData);
+    }
     return exceptionTypes;
   }
+  public static native Class[] nativeGetExceptionTypes(byte[] vmData);
+
 
   /**
    * Compare two objects to see if they are semantically equivalent.
@@ -251,11 +273,174 @@
     throws InstantiationException, IllegalAccessException,
            InvocationTargetException
   {
-    return constructNative(args, clazz, slot);
+    /* The following code is more of a hack, than real
+     * implementation, as it lacks checking and widening. To be
+     * fixed...*/
+
+    if (args == null)
+    {
+      args = new Object[0];
+    }
+
+    char[] paramTypes = getParamTypes();
+    int count = paramTypes.length;
+
+    for (int i = 0; i < count; i++)
+    {
+      /* In the future, we should handle primitive type widening. */
+      switch (paramTypes[i])
+      {
+      case 'Z':
+        {
+          /* using a wrapper array is simpler for the VM. */
+          boolean[] wrapper = new boolean[1];
+          wrapper[0] = ((Boolean) args[i]).booleanValue();
+          args[i] = wrapper;
+        }
+        break;
+
+      case 'B':
+        {
+          byte[] wrapper = new byte[1];
+          wrapper[0] = ((Byte) args[i]).byteValue();
+          args[i] = wrapper;
+        }
+        break;
+
+      case 'S':
+        {
+          short[] wrapper = new short[1];
+          wrapper[0] = ((Short) args[i]).shortValue();
+          args[i] = wrapper;
+        }
+        break;
+
+      case 'C':
+        {
+          char[] wrapper = new char[1];
+          wrapper[0] = ((Character) args[i]).charValue();
+          args[i] = wrapper;
+        }
+        break;
+
+      case 'I':
+        {
+          int[] wrapper = new int[1];
+          wrapper[0] = ((Integer) args[i]).intValue();
+          args[i] = wrapper;
+        }
+        break;
+
+      case 'J':
+        {
+          long[] wrapper = new long[1];
+          wrapper[0] = ((Long) args[i]).longValue();
+          args[i] = wrapper;
+        }
+        break;
+
+      case 'F':
+        {
+          float[] wrapper = new float[1];
+          wrapper[0] = ((Float) args[i]).floatValue();
+          args[i] = wrapper;
+        }
+        break;
+
+      case 'D':
+        {
+          double[] wrapper = new double[1];
+          wrapper[0] = ((Double) args[i]).doubleValue();
+          args[i] = wrapper;
+        }
+        break;
+
+      case 'L':
+        {
+          /* should be checking type */
+        }
+        break;
+      default:
+        throw new InternalError();
+      }
+    }
+
+    return constructNative(vmData, paramTypes, args);
+
+  }
+
+  private static native Object constructNative(byte[] vmData, char[] 
paramTypes, Object[] args)
+  throws InstantiationException, IllegalAccessException,
+        InvocationTargetException;
+
+  private static native String nativeGetDescriptor(byte[] vmData);
+
+  private char[] paramTypes;
+
+  private char[] getParamTypes()
+{
+    if(paramTypes == null)
+    {
+      char[] array = nativeGetDescriptor(vmData).toCharArray();
+      int count = 0;
+      int i = 0;
+      char c;
+
+      while ((c = array[++i]) != ')')
+      {
+        switch (c)
+        {
+        case 'Z':
+        case 'B':
+        case 'S':
+        case 'C':
+        case 'I':
+        case 'J':
+        case 'F':
+        case 'D':
+          {
+            array[count++] = c;
+          }
+          break;
+
+        case 'L':
+          {
+            array[count++] = 'L';
+
+            /* skip to next ';' */
+            while (array[++i] != ';')
+              ;
+          }
+          break;
+
+        case '[':
+          {
+            array[count++] = 'L';
+
+            /* skip all '[' */
+            while (array[++i] == '[')
+              ;
+
+            if (array[i] == 'L')
+            {
+              /* skip to next ';' */
+              while (array[++i] != ';')
+                ;
+            }
+          }
+          break;
+
+        default:
+          throw new InternalError();
+        }
+      }
+
+      char[] types = new char[count];
+      System.arraycopy(array, 0, types, 0, count);
+      paramTypes = types;
+    }
+
+    return paramTypes;
   }
 
-  private native Object constructNative(Object[] args, Class declaringClass,
-                                        int slot)
-    throws InstantiationException, IllegalAccessException,
-           InvocationTargetException;
 }
Index: vm/reference/java/lang/reflect/Field.java
===================================================================
RCS file: 
/cvsroot/classpath/classpath/vm/reference/java/lang/reflect/Field.java,v
retrieving revision 1.7
diff -u -r1.7 Field.java
--- vm/reference/java/lang/reflect/Field.java   15 Aug 2003 01:25:31 -0000      
1.7
+++ vm/reference/java/lang/reflect/Field.java   28 Mar 2004 05:16:31 -0000
@@ -62,6 +62,7 @@
  *
  * @author John Keiser
  * @author Eric Blake <address@hidden>
+ * @author David Belanger <address@hidden>
  * @see Member
  * @see Class
  * @see Class#getField(String)
@@ -74,10 +75,23 @@
 public final class Field
 extends AccessibleObject implements Member
 {
-  private Class declaringClass;
-  private String name;
   private int slot;
 
+  private String name;
+  private Class declaringClass;
+  private Class type;
+
+ 
+
+
+  byte[] vmData;
+  private  Field(byte[] vmData)
+  {
+    this.vmData = vmData;
+  }
+
+
+
   /**
    * This class is uninstantiable except natively.
    */
@@ -95,8 +109,14 @@
    */
   public Class getDeclaringClass()
   {
+    if (declaringClass == null)
+    {
+      declaringClass = nativeGetDeclaringClass(vmData);
+    }
     return declaringClass;
   }
+  public static native Class nativeGetDeclaringClass(byte[] vmData);
+
 
   /**
    * Gets the name of this field.
@@ -104,8 +124,14 @@
    */
   public String getName()
   {
+    if (name == null)
+    {
+      name = nativeGetName(vmData);
+    }
     return name;
   }
+  public static native String nativeGetName(byte[] vmData);
+
 
   /**
    * Gets the modifiers this field uses.  Use the <code>Modifier</code>
@@ -116,18 +142,31 @@
    * @return an integer representing the modifiers to this Member
    * @see Modifier
    */
-  public native int getModifiers();
+  public int getModifiers() {
+    return nativeGetModifiers(vmData);    
+  }
+  private native int nativeGetModifiers(byte[] vmData);
 
   /**
    * Gets the type of this field.
    * @return the type of this field
    */
-  public native Class getType();
+  public Class getType()
+  {
+    if (type == null)
+    {
+      type = nativeGetType(vmData);
+    }
+    return type;
+  }
+  public static native Class nativeGetType(byte[] vmData);
+
+ 
 
   /**
    * Compare two objects to see if they are semantically equivalent.
    * Two Fields are semantically equivalent if they have the same declaring
-   * class, name, and type. Since you can't creat a Field except through
+   * class, name, and type. Since you can't create a Field except through
    * the VM, this is just the == relation.
    *
    * @param o the object to compare to
@@ -176,6 +215,16 @@
     sb.append(getName());
     return sb.toString();
   }
+
+
+  // DB:
+  //
+  // ****** TODO: Add checks to the get.../set... methods.
+  //
+  // All checks are done on the Java side for simplicity.
+  //
+
+
  
   /**
    * Get the value of this Field.  If it is primitive, it will be wrapped
@@ -217,9 +266,90 @@
    * @see #getFloat(Object)
    * @see #getDouble(Object)
    */
-  public native Object get(Object o)
+  public Object get(Object o)
+    throws IllegalAccessException
+  {
+
+    // Checks are delegated to the getTYPE methods
+
+    Class type;
+    type = getType();
+    if (type == Boolean.TYPE) {
+      return getBoolean(o) ? Boolean.TRUE : Boolean.FALSE;
+    } else if (type == Byte.TYPE) {
+      return new Byte(getByte(o));
+    } else if (type == Short.TYPE) {
+      return new Short(getShort(o));
+    } else if (type == Character.TYPE) {
+      return new Character(getChar(o));
+    } else if (type == Integer.TYPE) {
+      return new Integer(getInt(o));
+    } else if (type == Long.TYPE) {
+      return new Long(getLong(o));
+    } else if (type == Float.TYPE) {
+      return new Float(getFloat(o));
+    } else if (type == Double.TYPE) {
+      return new Double(getDouble(o));
+    } else {
+      // for this one, we do the checks here
+
+      checkField(type, o, null);
+      
+      return nativeGetReference(vmData, o);
+
+    }
+  }
+  private native Object nativeGetReference(byte[] vmData, Object o)
     throws IllegalAccessException;
 
+  // Performs some checks fields access getTYPE() methods.
+  private void checkField(Object o, Class acceptType) {
+    checkField(getType(), o, new Class[] { acceptType } );
+  }
+  private void checkField(Object o, Class[] acceptTypes) {
+    checkField(getType(), o, acceptTypes);
+  }
+  
+  //
+  // If acceptTypes is null, the any field type is good.
+  //
+  private void checkField(Class type, Object o, Class[] acceptTypes) {
+    if (!Modifier.isStatic(getModifiers())) {
+      // instance field checks
+      if (o == null) {
+       throw new NullPointerException();
+      }
+
+      if (!(getDeclaringClass().isInstance(o))) {
+       throw new IllegalArgumentException();
+      }
+    }
+
+
+    // access check
+  
+    // *** TODO ***
+
+
+
+
+    // Acceptable field types
+    // Ex: getBoolean can only be perform on a field of type boolean
+    if (acceptTypes != null) {
+      boolean ok = false;  // assume not okay
+      for (int i = 0; i < acceptTypes.length; i++) {
+       if (type == acceptTypes[i]) {
+         ok = true;
+         break;
+       }
+      }
+      if (!ok) {
+       throw new IllegalArgumentException();
+      }
+    }
+  }
+
+
   /**
    * Get the value of this boolean Field. If the field is static,
    * <code>o</code> will be ignored.
@@ -237,8 +367,15 @@
    *         class initialization, which then failed
    * @see #get(Object)
    */
-  public native boolean getBoolean(Object o)
+  public boolean getBoolean(Object o)
+    throws IllegalAccessException
+  {
+    checkField(o, Boolean.TYPE);
+    return nativeGetBoolean(vmData, o);
+  }
+  private native boolean nativeGetBoolean(byte[] vmData, Object o)
     throws IllegalAccessException;
+  
 
   /**
    * Get the value of this byte Field. If the field is static,
@@ -257,9 +394,17 @@
    *         class initialization, which then failed
    * @see #get(Object)
    */
-  public native byte getByte(Object o)
+  public byte getByte(Object o)
+    throws IllegalAccessException
+  {
+    checkField(o, Byte.TYPE);
+    return nativeGetByte(vmData, o);
+  }
+
+  private native byte nativeGetByte(byte[] vmData, Object o)
     throws IllegalAccessException;
 
+
   /**
    * Get the value of this Field as a char. If the field is static,
    * <code>o</code> will be ignored.
@@ -275,7 +420,14 @@
    *         class initialization, which then failed
    * @see #get(Object)
    */
-  public native char getChar(Object o)
+  public char getChar(Object o)
+    throws IllegalAccessException
+  {
+    checkField(o, Character.TYPE);
+    return nativeGetChar(vmData, o);
+  }
+
+  private native char nativeGetChar(byte[] vmData, Object o)
     throws IllegalAccessException;
 
   /**
@@ -295,7 +447,12 @@
    *         class initialization, which then failed
    * @see #get(Object)
    */
-  public native short getShort(Object o)
+  public short getShort(Object o)
+    throws IllegalAccessException {
+    checkField(o, new Class[] { Byte.TYPE, Short.TYPE });
+    return nativeGetShort(vmData, o);
+  }
+  private native short nativeGetShort(byte[] vmData, Object o)
     throws IllegalAccessException;
 
   /**
@@ -315,7 +472,14 @@
    *         class initialization, which then failed
    * @see #get(Object)
    */
-  public native int getInt(Object o)
+  public int getInt(Object o)
+    throws IllegalAccessException
+  {
+    checkField(o, new Class[] { Byte.TYPE, Short.TYPE,
+                             Character.TYPE, Integer.TYPE } );
+    return nativeGetInt(vmData, o);
+  }
+  private native int nativeGetInt(byte[] vmData, Object o)
     throws IllegalAccessException;
 
   /**
@@ -335,7 +499,15 @@
    *         class initialization, which then failed
    * @see #get(Object)
    */
-  public native long getLong(Object o)
+  public long getLong(Object o)
+    throws IllegalAccessException
+  {
+    checkField(o, new Class[] { Byte.TYPE, Short.TYPE, Character.TYPE,
+                             Integer.TYPE, Long.TYPE });
+    return nativeGetLong(vmData, o);
+  }
+
+  private native long nativeGetLong(byte[] vmData, Object o)
     throws IllegalAccessException;
 
   /**
@@ -355,7 +527,14 @@
    *         class initialization, which then failed
    * @see #get(Object)
    */
-  public native float getFloat(Object o)
+  public float getFloat(Object o)
+    throws IllegalAccessException
+  {
+    checkField(o, new Class[] { Byte.TYPE, Short.TYPE, Character.TYPE,
+                             Integer.TYPE, Long.TYPE, Float.TYPE });
+    return nativeGetFloat(vmData, o);       
+  }
+  public native float nativeGetFloat(byte[] vmData, Object o)
     throws IllegalAccessException;
 
   /**
@@ -376,7 +555,15 @@
    *         class initialization, which then failed
    * @see #get(Object)
    */
-  public native double getDouble(Object o)
+  public double getDouble(Object o)
+    throws IllegalAccessException
+  {
+    checkField(o, new Class[] { Byte.TYPE, Short.TYPE, Character.TYPE,
+                               Integer.TYPE, Long.TYPE, Float.TYPE,
+                               Double.TYPE });
+    return nativeGetDouble(vmData, o);
+  }
+  private native double nativeGetDouble(byte[] vmData, Object o)
     throws IllegalAccessException;
 
   /**
@@ -424,9 +611,63 @@
    * @see #setFloat(Object, float)
    * @see #setDouble(Object, double)
    */
-  public native void set(Object o, Object value)
+  public void set(Object o, Object value)
+    throws IllegalAccessException
+  {
+
+    // Checks are delegated to the setTYPE methods
+
+    Class type;
+
+    type = getType();
+
+    if (type.isPrimitive()) {
+      // this is a primitive field, unwrap
+
+      if (value instanceof Boolean) {
+       setBoolean(o, ((Boolean) value).booleanValue());
+      } else if (value instanceof Byte) {
+       setByte(o, ((Byte) value).byteValue());
+      } else if (value instanceof Short) {
+       setShort(o, ((Short) value).shortValue());
+      } else if (value instanceof Character) {
+       setChar(o, ((Character) value).charValue());
+      } else if (value instanceof Integer) {
+       setInt(o, ((Integer) value).intValue());
+      } else if (value instanceof Long) {
+       setLong(o, ((Long) value).longValue());
+      } else if (value instanceof Float) {
+       setFloat(o, ((Float) value).floatValue());
+      } else if (value instanceof Double) {
+       setDouble(o, ((Double) value).doubleValue());
+      } else {
+       // unable to unwrap
+       throw new IllegalArgumentException();
+      }
+
+    } else {
+      // reference type
+
+      checkField(type, o, null);
+      
+      // cannot store reference A into field of type B if A is
+      // not instance of B
+      if (!type.isInstance(value)) {
+       throw new IllegalArgumentException();
+      }
+
+      nativeSetReference(vmData, o, value);
+
+    }
+
+  }
+
+  private native void nativeSetReference(byte[] vmData,
+                                        Object o,
+                                        Object value)
     throws IllegalAccessException;
 
+
   /**
    * Set this boolean Field. If the field is static, <code>o</code> will be
    * ignored.
@@ -444,9 +685,17 @@
    *         class initialization, which then failed
    * @see #set(Object, Object)
    */
-  public native void setBoolean(Object o, boolean value)
+  public void setBoolean(Object o, boolean value)
+    throws IllegalAccessException
+  {
+    checkField(o, Boolean.TYPE);
+    nativeSetBoolean(vmData, o, value);
+  }
+
+  private native void nativeSetBoolean(byte[] vmData, Object o, boolean value)
     throws IllegalAccessException;
 
+
   /**
    * Set this byte Field. If the field is static, <code>o</code> will be
    * ignored.
@@ -464,7 +713,15 @@
    *         class initialization, which then failed
    * @see #set(Object, Object)
    */
-  public native void setByte(Object o, byte value)
+  public void setByte(Object o, byte value)
+    throws IllegalAccessException
+  {
+    checkField(o, new Class[] { Byte.TYPE, Short.TYPE, Integer.TYPE,
+                               Long.TYPE, Float.TYPE, Double.TYPE });
+    nativeSetByte(vmData, o, value);
+  }
+
+  private native void nativeSetByte(byte[] vmData, Object o, byte value)
     throws IllegalAccessException;
 
   /**
@@ -484,9 +741,18 @@
    *         class initialization, which then failed
    * @see #set(Object, Object)
    */
-  public native void setChar(Object o, char value)
+  public void setChar(Object o, char value)
+    throws IllegalAccessException
+  {
+    checkField(o, new Class[] { Character.TYPE, Integer.TYPE, Long.TYPE,
+                               Float.TYPE, Double.TYPE } );
+    nativeSetChar(vmData, o, value);
+  }
+
+  private native void nativeSetChar(byte[] vmData, Object o, char value)
     throws IllegalAccessException;
 
+
   /**
    * Set this short Field. If the field is static, <code>o</code> will be
    * ignored.
@@ -504,7 +770,15 @@
    *         class initialization, which then failed
    * @see #set(Object, Object)
    */
-  public native void setShort(Object o, short value)
+  public void setShort(Object o, short value)
+    throws IllegalAccessException
+  {
+    checkField(o, new Class[] { Short.TYPE, Integer.TYPE, Long.TYPE,
+                               Float.TYPE, Double.TYPE });
+    nativeSetShort(vmData, o, value);
+  }
+
+  private native void nativeSetShort(byte[] vmData, Object o, short value)
     throws IllegalAccessException;
 
   /**
@@ -524,9 +798,18 @@
    *         class initialization, which then failed
    * @see #set(Object, Object)
    */
-  public native void setInt(Object o, int value)
+  public void setInt(Object o, int value)
+    throws IllegalAccessException
+  {
+    checkField(o, new Class[] { Integer.TYPE, Long.TYPE, Float.TYPE,
+                               Double.TYPE });
+    nativeSetInt(vmData, o, value);
+  }
+
+  private native void nativeSetInt(byte[] vmData, Object o, int value)
     throws IllegalAccessException;
 
+
   /**
    * Set this long Field. If the field is static, <code>o</code> will be
    * ignored.
@@ -544,9 +827,16 @@
    *         class initialization, which then failed
    * @see #set(Object, Object)
    */
-  public native void setLong(Object o, long value)
+  public void setLong(Object o, long value)
+    throws IllegalAccessException {
+    checkField(o, new Class[] { Long.TYPE, Float.TYPE, Double.TYPE });
+    nativeSetLong(vmData, o, value);
+  }
+
+  private native void nativeSetLong(byte[] vmData, Object o, long value)
     throws IllegalAccessException;
 
+
   /**
    * Set this float Field. If the field is static, <code>o</code> will be
    * ignored.
@@ -564,8 +854,17 @@
    *         class initialization, which then failed
    * @see #set(Object, Object)
    */
-  public native void setFloat(Object o, float value)
+  public void setFloat(Object o, float value)
+    throws IllegalAccessException
+  {
+    // DB: why float or long, why not double also?
+    checkField(o, new Class[] { Float.TYPE, Long.TYPE });
+    nativeSetFloat(vmData, o, value);
+  }
+
+  private native void nativeSetFloat(byte[] vmData, Object o, float value)
     throws IllegalAccessException;
+  
 
   /**
    * Set this double Field. If the field is static, <code>o</code> will be
@@ -584,6 +883,14 @@
    *         class initialization, which then failed
    * @see #set(Object, Object)
    */
-  public native void setDouble(Object o, double value)
+  public void setDouble(Object o, double value)
+    throws IllegalAccessException
+  {
+    checkField(o, Double.TYPE);
+    nativeSetDouble(vmData, o, value);
+  }
+
+  private native void nativeSetDouble(byte[] vmData, Object o, double value)
     throws IllegalAccessException;
+
 }
Index: vm/reference/java/lang/reflect/Makefile.am
===================================================================
RCS file: 
/cvsroot/classpath/classpath/vm/reference/java/lang/reflect/Makefile.am,v
retrieving revision 1.1
diff -u -r1.1 Makefile.am
--- vm/reference/java/lang/reflect/Makefile.am  22 Dec 1998 03:25:40 -0000      
1.1
+++ vm/reference/java/lang/reflect/Makefile.am  28 Mar 2004 05:16:31 -0000
@@ -3,4 +3,5 @@
 EXTRA_DIST = \
 Constructor.java \
 Field.java \
-Method.java
+Method.java \
+ReflectUtil.java
Index: vm/reference/java/lang/reflect/Method.java
===================================================================
RCS file: 
/cvsroot/classpath/classpath/vm/reference/java/lang/reflect/Method.java,v
retrieving revision 1.10
diff -u -r1.10 Method.java
--- vm/reference/java/lang/reflect/Method.java  15 Aug 2003 01:25:31 -0000      
1.10
+++ vm/reference/java/lang/reflect/Method.java  28 Mar 2004 05:16:31 -0000
@@ -76,10 +76,22 @@
 public final class Method
 extends AccessibleObject implements Member
 {
-  Class declaringClass;
-  String name;
   int slot;
 
+  byte[] vmData;
+  private  Method(byte[] vmData)
+  {
+    this.vmData = vmData;
+  }
+
+  private String name;
+  private Class declaringClass;
+  private Class returnType;
+  private Class[] parameterTypes;
+  private Class[] exceptionTypes;
+
+
+
   /**
    * This class is uninstantiable.
    */
@@ -97,8 +109,14 @@
    */
   public Class getDeclaringClass()
   {
+    if (declaringClass == null)
+    {
+      declaringClass = nativeGetDeclaringClass(vmData);
+    }
     return declaringClass;
   }
+  private static native Class nativeGetDeclaringClass(byte[] vmData);
+
 
   /**
    * Gets the name of this method.
@@ -106,8 +124,14 @@
    */
   public String getName()
   {
+    if (name == null)
+    {
+      name = nativeGetName(vmData);
+    }
     return name;
   }
+  public static native String nativeGetName(byte[] vmData);
+
 
   /**
    * Gets the modifiers this method uses.  Use the <code>Modifier</code>
@@ -118,13 +142,26 @@
    * @return an integer representing the modifiers to this Member
    * @see Modifier
    */
-  public native int getModifiers();
+  public int getModifiers()
+  {
+    /* DB: Modified prototype of native method. */
+    return nativeGetModifiers(vmData);
+  }
+  private static native int nativeGetModifiers(byte[] vmData);
 
   /**
    * Gets the return type of this method.
    * @return the type of this method
    */
-  public native Class getReturnType();
+  public Class getReturnType()
+  {
+
+    if (returnType == null)
+    {
+      returnType = ReflectUtil.getReturnType(nativeGetDescriptor(vmData));
+    }
+    return returnType;
+  }
 
   /**
    * Get the parameter list for this method, in declaration order. If the
@@ -132,7 +169,16 @@
    *
    * @return a list of the types of the method's parameters
    */
-  public native Class[] getParameterTypes();
+  public Class[] getParameterTypes()
+  {
+    if (parameterTypes == null)
+    {
+      parameterTypes =
+        ReflectUtil.getParameterTypes(nativeGetDescriptor(vmData));
+    }
+    return parameterTypes;
+  }
+
 
   /**
    * Get the exception types this method says it throws, in no particular
@@ -141,7 +187,16 @@
    *
    * @return a list of the types in the method's throws clause
    */
-  public native Class[] getExceptionTypes();
+  public Class[] getExceptionTypes()
+  {
+    if (exceptionTypes == null)
+    {
+      exceptionTypes = nativeGetExceptionTypes(vmData);
+    }
+    return exceptionTypes;
+  }
+  public static native Class[] nativeGetExceptionTypes(byte[] vmData);
+
 
   /**
    * Compare two objects to see if they are semantically equivalent.
@@ -275,16 +330,375 @@
    *         class initialization, which then failed
    */
   public Object invoke(Object o, Object[] args)
-    throws IllegalAccessException, InvocationTargetException
+  throws IllegalAccessException, InvocationTargetException
+  {
+    /* The following code is more of a hack, than real
+     * implementation, as it lacks checking and widening. To be
+     * fixed...*/
+
+    if (args == null) {
+      args = new Object[0];
+    } else {
+      /*
+       * If args actual type is not Object[], allocate an Object[]
+       * and copy the args to that array.
+       *
+       * If this is not done, an ArrayStoreException may result
+       * in the following code.
+       *
+       * ex: Boolean[] passed.
+       *
+       *     boolean[] wrapper = new boolean[1];
+       *     wrapper[0] = ((Boolean) args[i]).booleanValue();
+       * --> args[i] = wrapper;
+       *
+       * ArrayStoreException since boolean[] is not assignable to
+       * type Boolean.
+       *
+       */
+      if (args.getClass() != Object[].class) {
+       Object[] newArgs;
+       newArgs = new Object[args.length];
+       for (int i = 0; i < args.length; i++) {
+         newArgs[i] = args[i];
+       }
+       // ugly, changing param value
+       args = newArgs;
+      }
+
+    }
+
+    char[] paramTypes = getParamTypes();
+    int count = paramTypes.length;
+
+    for (int i = 0; i < count; i++)
+    {
+      /* In the future, we should handle primitive type widening. */
+      switch (paramTypes[i])
+      {
+      case 'Z':
+        {
+          /* using a wrapper array is simpler for the VM. */
+          boolean[] wrapper = new boolean[1];
+          wrapper[0] = ((Boolean) args[i]).booleanValue();
+          args[i] = wrapper;
+        }
+        break;
+
+      case 'B':
+        {
+          byte[] wrapper = new byte[1];
+          wrapper[0] = ((Byte) args[i]).byteValue();
+          args[i] = wrapper;
+        }
+        break;
+
+      case 'S':
+        {
+          short[] wrapper = new short[1];
+          wrapper[0] = ((Short) args[i]).shortValue();
+          args[i] = wrapper;
+        }
+        break;
+
+      case 'C':
+        {
+          char[] wrapper = new char[1];
+          wrapper[0] = ((Character) args[i]).charValue();
+          args[i] = wrapper;
+        }
+        break;
+
+      case 'I':
+        {
+          int[] wrapper = new int[1];
+          wrapper[0] = ((Integer) args[i]).intValue();
+          args[i] = wrapper;
+        }
+        break;
+
+      case 'J':
+        {
+          long[] wrapper = new long[1];
+          wrapper[0] = ((Long) args[i]).longValue();
+          args[i] = wrapper;
+        }
+        break;
+
+      case 'F':
+        {
+          float[] wrapper = new float[1];
+          wrapper[0] = ((Float) args[i]).floatValue();
+          args[i] = wrapper;
+        }
+        break;
+
+      case 'D':
+        {
+          double[] wrapper = new double[1];
+          wrapper[0] = ((Double) args[i]).doubleValue();
+          args[i] = wrapper;
+        }
+        break;
+
+      case 'L':
+        {
+          /* should be checking type */
+        }
+        break;
+
+      default:
+        throw new InternalError();
+      }
+    }
+
+    Object result;
+
+    switch (resultType)
+    {
+    case 'Z':
+      {
+        boolean[] wrapper = new boolean[1];
+        result = wrapper;
+      }
+      break;
+
+    case 'B':
+      {
+        byte[] wrapper = new byte[1];
+        result = wrapper;
+      }
+      break;
+
+    case 'S':
+      {
+        short[] wrapper = new short[1];
+        result = wrapper;
+      }
+      break;
+
+    case 'C':
+      {
+        char[] wrapper = new char[1];
+        result = wrapper;
+      }
+      break;
+
+    case 'I':
+      {
+        int[] wrapper = new int[1];
+        result = wrapper;
+      }
+      break;
+
+    case 'J':
+      {
+        long[] wrapper = new long[1];
+        result = wrapper;
+      }
+      break;
+
+    case 'F':
+      {
+        float[] wrapper = new float[1];
+        result = wrapper;
+      }
+      break;
+
+    case 'D':
+      {
+        double[] wrapper = new double[1];
+        result = wrapper;
+      }
+      break;
+
+    case 'L':
+      {
+        Object[] wrapper = new Object[1];
+        result = wrapper;
+      }
+      break;
+
+    case 'V':
+      {
+        result = null;
+      }
+      break;
+
+    default:
+      throw new InternalError();
+    }
+
+    // invoke the thing.
+    invokeNative(vmData, paramTypes, resultType, o, args, result);
+
+    // unwrap and rewrap the result appropriately
+    switch (resultType)
+    {
+    case 'Z':
+      {
+        boolean[] wrapper = (boolean[]) result;
+        return new Boolean(wrapper[0]);
+      }
+
+    case 'B':
+      {
+        byte[] wrapper = (byte[]) result;
+        return new Byte(wrapper[0]);
+      }
+
+    case 'S':
+      {
+        short[] wrapper = (short[]) result;
+        return new Short(wrapper[0]);
+      }
+
+    case 'C':
+      {
+        char[] wrapper = (char[]) result;
+        return new Character(wrapper[0]);
+      }
+
+    case 'I':
+      {
+        int[] wrapper = (int[]) result;
+        return new Integer(wrapper[0]);
+      }
+
+    case 'J':
+      {
+        long[] wrapper = (long[]) result;
+        return new Long(wrapper[0]);
+      }
+
+    case 'F':
+      {
+        float[] wrapper = (float[]) result;
+        return new Float(wrapper[0]);
+      }
+
+    case 'D':
+      {
+        double[] wrapper = (double[]) result;
+        return new Double(wrapper[0]);
+      }
+
+    case 'L':
+      {
+        Object[] wrapper = (Object[]) result;
+        return wrapper[0];
+      }
+
+    case 'V':
+      {
+        return null;
+      }
+
+    default:
+      throw new InternalError();
+    }
+  }
+
+  private static native void invokeNative(byte[] vmData, char[] paramTypes, 
char resultType, Object o, Object[] args, Object result)
+  throws IllegalAccessException, InvocationTargetException;
+
+  private static native String nativeGetDescriptor(byte[] vmData);
+
+  private char[] paramTypes;
+  private char resultType;
+
+  private char[] getParamTypes()
   {
-    return invokeNative(o, args, declaringClass, slot);
+    if(paramTypes == null)
+    {
+      char[] array = nativeGetDescriptor(vmData).toCharArray();
+      int count = 0;
+      int i = 0;
+      char c;
+
+      while ((c = array[++i]) != ')')
+      {
+        switch (c)
+        {
+        case 'Z':
+        case 'B':
+        case 'S':
+        case 'C':
+        case 'I':
+        case 'J':
+        case 'F':
+        case 'D':
+          {
+            array[count++] = c;
+          }
+          break;
+
+        case 'L':
+          {
+            array[count++] = 'L';
+
+            /* skip to next ';' */
+            while (array[++i] != ';')
+              ;
+          }
+          break;
+
+        case '[':
+          {
+            array[count++] = 'L';
+
+            /* skip all '[' */
+            while (array[++i] == '[')
+              ;
+
+            if (array[i] == 'L')
+            {
+              /* skip to next ';' */
+              while (array[++i] != ';')
+                ;
+            }
+          }
+          break;
+
+        default:
+          throw new InternalError();
+        }
+      }
+
+      switch (c = array[++i])
+      {
+      case 'Z':
+      case 'B':
+      case 'S':
+      case 'C':
+      case 'I':
+      case 'J':
+      case 'F':
+      case 'D':
+      case 'L':
+      case 'V':
+        {
+          resultType = c;
+        }
+        break;
+
+      case '[':
+        {
+          resultType = 'L';
+        }
+        break;
+
+      default:
+        throw new InternalError();
+      }
+
+      char[] types = new char[count];
+      System.arraycopy(array, 0, types, 0, count);
+      paramTypes = types;
+    }
+
+    return paramTypes;
   }
 
-  /*
-   * NATIVE HELPERS
-   */
 
-  private native Object invokeNative(Object o, Object[] args,
-                                     Class declaringClass, int slot)
-    throws IllegalAccessException, InvocationTargetException;
 }
diff -ru ./classpath/vm/reference/java/lang/reflect/ReflectUtil.java 
./svm-cp-merge/vm/reference/java/lang/reflect/Method.java
--- ./classpath/vm/reference/java/lang/reflect/ReflectUtil.java 2003-08-14 
21:25:31.000000000 -0400
+++ ./svm-cp-merge/vm/reference/java/lang/reflect/ReflectUtil.java      
2004-03-27 21:38:07.000000000 -0500
@@ -0,0 +1,227 @@
+/* ReflectUtil.java --
+   Copyright (C) 2003 David Belanger <address@hidden>
+ 
+This file is part of GNU Classpath.
+ 
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+ 
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+ 
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+ 
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.lang.reflect;
+
+/**
+ * Common methods needed by several reflection classes.
+ *
+ *
+ *
+ * @author David BĂ©langer
+ *
+ *
+ */
+class ReflectUtil
+{
+
+  /**
+   * Returns the <code>Class</code> that represents the type
+   * specificied by <code>name</name>. (ex: "I", "V", "Ljava/lang/String;")
+   *
+   */
+  public static Class typeToClass(String name)
+  {
+    char c;
+
+    c = name.charAt(0);
+
+    switch (c)
+    {
+    case 'Z':
+      return boolean.class;
+    case 'B':
+      return byte.class;
+    case 'S':
+      return short.class;
+    case 'C':
+      return char.class;
+    case 'I':
+      return int.class;
+    case 'J':
+      return long.class;
+    case 'F':
+      return float.class;
+    case 'D':
+      return double.class;
+    case 'V':  // got also that type for return types
+      return void.class;
+    case 'L':
+      {
+        String formalName;
+        // check needed?
+        if (name.charAt(name.length() - 1) != ';')
+        {
+          throw new InternalError("Invalid class name format");
+        }
+        formalName = name.substring(1, name.length() - 1);  // remove ';'
+        formalName = formalName.replace('/', '.');
+        try
+        {
+          return Class.forName(formalName);
+        }
+        catch (ClassNotFoundException e)
+        {
+          throw new InternalError(e.toString());
+        }
+      }
+    case '[':
+      // formal name for arrays example: "[Ljava.lang.String;"
+      {
+        String formalName;
+
+        formalName = name.replace('/', '.');
+
+        /*
+        int indexL;
+
+        formalName = name;
+        indexL = formalName.lastIndexOf('[') + 1;
+        if (formalName.charAt(indexL) == 'L') {
+          // remove L and ;
+          formalName = formalName.substring(0, indexL) +
+            formalName.substring(indexL + 1, formalName.length() - 1);
+          // '/' => '.'
+          formalName = formalName.replace('/', '.');
+        }
+        */
+        try
+        {
+          return Class.forName(formalName);
+        }
+        catch (ClassNotFoundException e)
+        {
+          throw new InternalError(e.toString());
+        }
+      }
+    default:
+      throw new InternalError("Unknown type:" + name);
+    }
+  }
+
+  /**
+   * Creates an array of <code>Class</code> that represents the
+   * type described by <code>names</code>.  Names have same format
+   * as method signature.
+   */
+  public static Class[] namesToClasses(String[] names)
+  {
+    Class[] classes;
+
+    classes = new Class[names.length];
+    for (int i = 0; i < names.length; i++)
+    {
+      classes[i] = typeToClass(names[i]);
+    }
+    return classes;
+  }
+
+  public static Class getReturnType(String descriptor)
+  {
+    return typeToClass(descriptor.substring(descriptor.indexOf(')') + 1));
+  }
+
+  public static Class[] getParameterTypes(String desc)
+  {
+    String[] names;
+    int count;
+    int i;
+    String descriptor;
+
+    // count them
+    count = 0;
+    i = 0;
+    descriptor = desc.substring(desc.indexOf('(') + 1, desc.indexOf(')'));
+    while (i < descriptor.length())
+    {
+      if (descriptor.charAt(i) == '[')
+      {
+        i++;
+        continue;
+      }
+      if (descriptor.charAt(i) == 'L')
+      {
+        while (descriptor.charAt(++i) != ';')
+        {
+          // skip char
+        }
+      }
+      count++;
+      i++;
+    }
+    //    System.out.println("===> desciptor: " + descriptor);
+    //    System.out.println("===> nbparam  : " + count);
+
+    // parse them
+    names = new String[count];
+    for (i = 0; i < count; i++)
+    {
+      names[i] = "";
+    }
+    int index = 0;
+    i = 0;
+    while (i < descriptor.length())
+    {
+      if (descriptor.charAt(i) == '[')
+      {
+        names[index] += "[";
+        i++;
+        continue;
+      }
+      if (descriptor.charAt(i) == 'L')
+      {
+        String s;
+        s = descriptor.substring(i, descriptor.indexOf(';', i) + 1);
+        names[index] += s;
+        i += s.length();
+      }
+      else
+      {
+        names[index] += descriptor.charAt(i);
+        i++;
+      }
+      index++;
+    }
+    /*
+    for (i = 0; i < count; i++) {
+      System.out.println("===> names[" + i + "] = " + names[i]);
+    }
+    */
+    return namesToClasses(names);
+  }
+
+}

reply via email to

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