[Top][All Lists]
[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);
+ }
+
+}
- vm/reference reflection update,
Grzegorz B. Prokopski <=