diff options
author | John Keiser <shalom@gnu.org> | 1998-06-21 06:20:58 +0000 |
---|---|---|
committer | John Keiser <shalom@gnu.org> | 1998-06-21 06:20:58 +0000 |
commit | 940dc05ba3e2e6a0b2991dfe611efe06718263ec (patch) | |
tree | 9f74365e4d1773001ed65c8667c98f4f534b5310 | |
parent | 3d1f1f0cf141196448fe634d79e5ef029676a38e (diff) | |
download | classpath-940dc05ba3e2e6a0b2991dfe611efe06718263ec.tar.gz |
Initial Revision
-rw-r--r-- | java/lang/reflect/Array.java | 518 | ||||
-rwxr-xr-x | java/lang/reflect/Constructor.java | 260 | ||||
-rwxr-xr-x | java/lang/reflect/DEPENDENCIES | 9 | ||||
-rw-r--r-- | java/lang/reflect/Field.java | 385 | ||||
-rw-r--r-- | java/lang/reflect/InvocationTargetException.java | 65 | ||||
-rw-r--r-- | java/lang/reflect/Member.java | 59 | ||||
-rw-r--r-- | java/lang/reflect/Method.java | 295 | ||||
-rw-r--r-- | java/lang/reflect/Modifier.java | 240 | ||||
-rw-r--r-- | java/lang/reflect/README | 23 | ||||
-rwxr-xr-x | java/lang/reflect/STATUS | 17 | ||||
-rwxr-xr-x | java/lang/reflect/TODO | 6 | ||||
-rwxr-xr-x | native/lib/DEPENDENCIES | 5 | ||||
-rwxr-xr-x | native/lib/README | 27 | ||||
-rwxr-xr-x | native/lib/STATUS | 8 | ||||
-rwxr-xr-x | native/lib/jcl.c | 53 | ||||
-rwxr-xr-x | native/lib/jcl.h | 23 | ||||
-rwxr-xr-x | native/lib/jnilink.c | 162 | ||||
-rwxr-xr-x | native/lib/jnilink.h | 35 | ||||
-rwxr-xr-x | native/lib/primlib.c | 497 | ||||
-rw-r--r-- | native/lib/primlib.h | 65 | ||||
-rwxr-xr-x | native/vmi/DEPENDENCIES | 14 | ||||
-rwxr-xr-x | native/vmi/README | 9 | ||||
-rwxr-xr-x | native/vmi/STATUS | 3 | ||||
-rw-r--r-- | native/vmi/TODO | 28 | ||||
-rwxr-xr-x | native/vmi/vmi.c | 206 | ||||
-rwxr-xr-x | native/vmi/vmi.h | 129 |
26 files changed, 3141 insertions, 0 deletions
diff --git a/java/lang/reflect/Array.java b/java/lang/reflect/Array.java new file mode 100644 index 000000000..6f443ffba --- /dev/null +++ b/java/lang/reflect/Array.java @@ -0,0 +1,518 @@ +/* + * java.lang.reflect.Array: part of the Java Class Libraries project. + * Copyright (C) 1998 John Keiser + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +package java.lang.reflect; + +/** + ** Array is a set of static helper functions that allow you to create and manipulate arrays + ** without knowing their type.<P> + ** + ** <B>Note:</B> This class uses a Class object to tell what type of thing to work with. If you wish + ** to work with primitive types, you may still use the Class functions; there are Class types + ** defined that represent each different primitive type. They are <code>java.lang.Boolean.TYPE, + ** java.lang.Byte.TYPE, </code>etc. These are not to be confused with the classes + ** <code>java.lang.Boolean, java.lang.Byte</code>, etc., which are real classes.<P> + ** + ** <B>Also:</B> If the type of the array is primitive, the accessor functions will wrap the returned + ** value in the appropriate class type (boolean = java.lang.Boolean, etc.).<P> + ** + ** <B>Performance note:</B> This class performs best when it does not have to convert primitive types. The further + ** along the chain it has to convert, the worse performance will be. You're best off using the array as whatever + ** type it already is, and then converting the result. You will do even worse if you do this and use the generic + ** set() function. + ** + ** @author John Keiser + ** @version 1.1.0, 31 May 1998 + ** @see java.lang.Boolean#TYPE + ** @see java.lang.Byte#TYPE + ** @see java.lang.Short#TYPE + ** @see java.lang.Character#TYPE + ** @see java.lang.Integer#TYPE + ** @see java.lang.Long#TYPE + ** @see java.lang.Float#TYPE + ** @see java.lang.Double#TYPE + **/ +public final class Array { + // Make this class uninstantiable. + private Array() {}; + + /** Creates a new single-dimensioned array. Will return null if the array is Void. + ** @param componentType the type of the array to create. + ** @param length the length of the array to create. + ** @exception NegativeArraySizeException when length is less than 0. + ** @return the created array, cast to an Object. + **/ + public static Object newInstance(Class componentType, int length) + throws NegativeArraySizeException { + if(componentType.isAssignableFrom(objectClass)) { + return createObjectArray(componentType, length); + } else if(componentType==Byte.TYPE) { + return new byte[length]; + } else if(componentType==Character.TYPE) { + return new char[length]; + } else if(componentType==Short.TYPE) { + return new short[length]; + } else if(componentType==Integer.TYPE) { + return new int[length]; + } else if(componentType==Long.TYPE) { + return new long[length]; + } else if(componentType==Float.TYPE) { + return new float[length]; + } else if(componentType==Double.TYPE) { + return new double[length]; + } else if(componentType==Void.TYPE) { + return null; + } else { + return null; + } + } + + /** Creates a new multi-dimensioned array. Returns null if array is Void. + ** @param componentType the type of the array to create. + ** @param dimensions the dimensions of the array to create. Each element in the + ** <code>dimensions</code> represents another dimension of the created + ** array. Thus, <code>newInstance(java.lang.Boolean, {1,2,3})</code> + ** is the same as <code>new java.lang.Boolean[1][2][3]</code>. + ** @exception NegativeArraySizeException when any of the dimensions is less than 0. + ** @exception IllegalArgumentException if the the size of <code>dimensions</code> is 0 + ** or exceeds the maximum number of array dimensions + ** the underlying JVM can handle. + ** @return the created array, cast to an Object. + **/ + public static Object newInstance(Class componentType, int[] dimensions) + throws IllegalArgumentException, + NegativeArraySizeException { + + if(dimensions.length<=0) { + throw new IllegalArgumentException("Empty dimensions array."); + } + return createDimensionedArray(componentType, dimensions, dimensions.length - 1); + } + + + /** Gets the array length. + ** @param array the array. + ** @return the length of the array. + ** @exception IllegalArgumentException if <code>array</code> is not an array. + **/ + public static native int getLength(Object array) + throws IllegalArgumentException; + + /** Gets an element of an array. Primitive elements will be wrapped in the corresponding class type.<P> + ** + ** <B>Note:</B> For performance reasons, all true booleans will return the same true object (Boolean.TRUE) + ** and all false booleans will return the same false object (Boolean.FALSE). + ** + ** @param array the array to access. + ** @param index the array index to access. + ** @exception IllegalArgumentException if <code>array</code> is not an array. + ** @exception ArrayIndexOutOfBoundsException if <code>index</code> is out of bounds. + ** @return the element at index <code>index</code> in the array <code>array</code>. + **/ + public static Object get(Object array, int index) + throws IllegalArgumentException, + ArrayIndexOutOfBoundsException { + if(array instanceof Object[]) { + return ((Object[])array)[index]; + } else if(array instanceof boolean[]) { + return ((boolean[])array)[index] ? Boolean.TRUE : Boolean.FALSE; + } else if(array instanceof byte[]) { + return new Byte(((byte[])array)[index]); + } else if(array instanceof char[]) { + return new Character(((char[])array)[index]); + } else if(array instanceof short[]) { + return new Short(((short[])array)[index]); + } else if(array instanceof int[]) { + return new Integer(((int[])array)[index]); + } else if(array instanceof long[]) { + return new Long(((long[])array)[index]); + } else if(array instanceof float[]) { + return new Float(((float[])array)[index]); + } else if(array instanceof double[]) { + return new Double(((double[])array)[index]); + } else { + throw new IllegalArgumentException(); + } + } + + /** Gets an element of a boolean array. + ** @param array the array to access. + ** @param index the array index to access. + ** @exception IllegalArgumentException if <code>array</code> is not a boolean array. + ** @exception ArrayIndexOutOfBoundsException if <code>index</code> is out of bounds. + ** @return the boolean element at index <code>index</code> in the array <code>array</code>. + **/ + public static boolean getBoolean(Object array, int index) + throws IllegalArgumentException, + ArrayIndexOutOfBoundsException { + if(array instanceof boolean[]) { + return ((boolean[])array)[index]; + } else { + throw new IllegalArgumentException(); + } + } + + /** Gets an element of a byte array. + ** @param array the array to access. + ** @param index the array index to access. + ** @exception IllegalArgumentException if <code>array</code> is not a byte array. + ** @exception ArrayIndexOutOfBoundsException if <code>index</code> is out of bounds. + ** @return the byte element at index <code>index</code> in the array <code>array</code>. + **/ + public static byte getByte(Object array, int index) + throws IllegalArgumentException, + ArrayIndexOutOfBoundsException { + if(array instanceof byte[]) { + return ((byte[])array)[index]; + } else { + throw new IllegalArgumentException(); + } + } + + /** Gets an element of a short array. + ** @param array the array to access. + ** @param index the array index to access. + ** @exception IllegalArgumentException if the elements of <code>array</code> cannot be + ** converted via widening conversion to a short. + ** @exception ArrayIndexOutOfBoundsException if <code>index</code> is out of bounds. + ** @return the short element at index <code>index</code> in the array <code>array</code>. + **/ + public static short getShort(Object array, int index) + throws IllegalArgumentException, + ArrayIndexOutOfBoundsException { + if(array instanceof short[]) { + return ((short[])array)[index]; + } else { + return getByte(array,index); + } + } + + /** Gets an element of a char array. + ** @param array the array to access. + ** @param index the array index to access. + ** @exception IllegalArgumentException if <code>array</code> is not a char array. + ** @exception ArrayIndexOutOfBoundsException if <code>index</code> is out of bounds. + ** @return the char element at index <code>index</code> in the array <code>array</code>. + **/ + public static char getChar(Object array, int index) + throws IllegalArgumentException, + ArrayIndexOutOfBoundsException { + if(array instanceof char[]) { + return ((char[])array)[index]; + } else { + throw new IllegalArgumentException(); + } + } + + /** Gets an element of an int array. + ** @param array the array to access. + ** @param index the array index to access. + ** @exception IllegalArgumentException if the elements of <code>array</code> cannot be + ** converted via widening conversion to an int. + ** @exception ArrayIndexOutOfBoundsException if <code>index</code> is out of bounds. + ** @return the int element at index <code>index</code> in the array <code>array</code>. + **/ + public static int getInt(Object array, int index) + throws IllegalArgumentException, + ArrayIndexOutOfBoundsException { + if(array instanceof int[]) { + return ((int[])array)[index]; + } else if(array instanceof char[]) { + return ((char[])array)[index]; + } else { + return getShort(array,index); + } + } + + /** Gets an element of a long array. + ** @param array the array to access. + ** @param index the array index to access. + ** @exception IllegalArgumentException if the elements of <code>array</code> cannot be + ** converted via widening conversion to a long. + ** @exception ArrayIndexOutOfBoundsException if <code>index</code> is out of bounds. + ** @return the long element at index <code>index</code> in the array <code>array</code>. + **/ + public static long getLong(Object array, int index) + throws IllegalArgumentException, + ArrayIndexOutOfBoundsException { + if(array instanceof long[]) { + return ((long[])array)[index]; + } else { + return getInt(array,index); + } + } + + /** Gets an element of a float array. + ** @param array the array to access. + ** @param index the array index to access. + ** @exception IllegalArgumentException if the elements of <code>array</code> cannot be + ** converted via widening conversion to a float. + ** @exception ArrayIndexOutOfBoundsException if <code>index</code> is out of bounds. + ** @return the float element at index <code>index</code> in the array <code>array</code>. + **/ + public static float getFloat(Object array, int index) + throws IllegalArgumentException, + ArrayIndexOutOfBoundsException { + if(array instanceof float[]) { + return ((float[])array)[index]; + } else { + return getLong(array,index); + } + } + + /** Gets an element of a double array. + ** @param array the array to access. + ** @param index the array index to access. + ** @exception IllegalArgumentException if the elements of <code>array</code> cannot be + ** converted via widening conversion to a double. + ** @exception ArrayIndexOutOfBoundsException if <code>index</code> is out of bounds. + ** @return the double element at index <code>index</code> in the array <code>array</code>. + **/ + public static double getDouble(Object array, int index) + throws IllegalArgumentException, + ArrayIndexOutOfBoundsException { + if(array instanceof double[]) { + return ((double[])array)[index]; + } else { + return getFloat(array,index); + } + } + + + /** Sets an element of an array. If the array is primitive, then the new value must be of the + ** corresponding wrapper type (boolean = java.lang.Boolean).<P> + ** + ** + ** @param array the array to set a value of. + ** @param index the array index to set the value to. + ** @param value the value to set. + ** @exception IllegalArgumentException if <code>array</code> is not an array. + ** @exception ArrayIndexOutOfBoundsException if <code>index</code> is out of bounds. + **/ + public static void set(Object array, int index, Object value) + throws IllegalArgumentException, + ArrayIndexOutOfBoundsException { + if(array instanceof Object[]) { + ((Object[])array)[index] = value; + } else if(value instanceof Boolean) { + setBoolean(array,index,((Boolean)value).booleanValue()); + } else if(value instanceof Byte) { + setByte(array,index,((Byte)value).byteValue()); + } else if(value instanceof Character) { + setChar(array,index,((Character)value).charValue()); + } else if(value instanceof Short) { + setShort(array,index,((Short)value).shortValue()); + } else if(value instanceof Integer) { + setInt(array,index,((Integer)value).intValue()); + } else if(value instanceof Long) { + setLong(array,index,((Long)value).longValue()); + } else if(value instanceof Float) { + setFloat(array,index,((Float)value).floatValue()); + } else if(value instanceof Double) { + setDouble(array,index,((Double)value).doubleValue()); + } else { + throw new IllegalArgumentException(); + } + } + + /** Sets an element of a boolean array. + ** + ** @param array the array to set a value of. + ** @param index the array index to set the value to. + ** @param value the value to set. + ** @exception IllegalArgumentException if <code>array</code> is not a boolean array. + ** @exception ArrayIndexOutOfBoundsException if <code>index</code> is out of bounds. + **/ + public static void setBoolean(Object array, int index, boolean value) + throws IllegalArgumentException, + ArrayIndexOutOfBoundsException { + if(array instanceof boolean[]) { + ((boolean[])array)[index] = value; + } else { + throw new IllegalArgumentException(); + } + } + + /** Sets an element of a byte array. + ** + ** @param array the array to set a value of. + ** @param index the array index to set the value to. + ** @param value the value to set. + ** @exception IllegalArgumentException if the value cannot be converted via widening + ** conversion to the type of <code>array</code>. + ** @exception ArrayIndexOutOfBoundsException if <code>index</code> is out of bounds. + **/ + public static void setByte(Object array, int index, byte value) + throws IllegalArgumentException, + ArrayIndexOutOfBoundsException { + if(array instanceof byte[]) { + ((byte[])array)[index] = value; + } else { + setShort(array,index,value); + } + } + + /** Sets an element of a char array. + ** + ** @param array the array to set a value of. + ** @param index the array index to set the value to. + ** @param value the value to set. + ** @exception IllegalArgumentException if the value cannot be converted via widening + ** conversion to the type of <code>array</code>. + ** @exception ArrayIndexOutOfBoundsException if <code>index</code> is out of bounds. + **/ + public static void setChar(Object array, int index, char value) + throws IllegalArgumentException, + ArrayIndexOutOfBoundsException { + if(array instanceof char[]) { + ((char[])array)[index] = value; + } else { + setInt(array,index,value); + } + } + + /** Sets an element of a short array. + ** + ** @param array the array to set a value of. + ** @param index the array index to set the value to. + ** @param value the value to set. + ** @exception IllegalArgumentException if the value cannot be converted via widening + ** conversion to the type of <code>array</code>. + ** @exception ArrayIndexOutOfBoundsException if <code>index</code> is out of bounds. + **/ + public static void setShort(Object array, int index, short value) + throws IllegalArgumentException, + ArrayIndexOutOfBoundsException { + if(array instanceof short[]) { + ((short[])array)[index] = value; + } else { + setInt(array,index,value); + } + } + + /** Sets an element of an int array. + ** + ** @param array the array to set a value of. + ** @param index the array index to set the value to. + ** @param value the value to set. + ** @exception IllegalArgumentException if the value cannot be converted via widening + ** conversion to the type of <code>array</code>. + ** @exception ArrayIndexOutOfBoundsException if <code>index</code> is out of bounds. + **/ + public static void setInt(Object array, int index, int value) + throws IllegalArgumentException, + ArrayIndexOutOfBoundsException { + if(array instanceof float[]) { + ((int[])array)[index] = value; + } else { + setLong(array,index,value); + } + } + + /** Sets an element of a long array. + ** + ** @param array the array to set a value of. + ** @param index the array index to set the value to. + ** @param value the value to set. + ** @exception IllegalArgumentException if the value cannot be converted via widening + ** conversion to the type of <code>array</code>. + ** @exception ArrayIndexOutOfBoundsException if <code>index</code> is out of bounds. + **/ + public static void setLong(Object array, int index, long value) + throws IllegalArgumentException, + ArrayIndexOutOfBoundsException { + if(array instanceof long[]) { + ((long[])array)[index] = value; + } else { + setFloat(array,index,value); + } + } + + /** Sets an element of a float array. + ** + ** @param array the array to set a value of. + ** @param index the array index to set the value to. + ** @param value the value to set. + ** @exception IllegalArgumentException if the value cannot be converted via widening + ** conversion to the type of <code>array</code>. + ** @exception ArrayIndexOutOfBoundsException if <code>index</code> is out of bounds. + **/ + public static void setFloat(Object array, int index, float value) + throws IllegalArgumentException, + ArrayIndexOutOfBoundsException { + if(array instanceof float[]) { + ((float[])array)[index] = value; + } else { + setDouble(array,index,value); + } + } + + /** Sets an element of a double array. + ** + ** @param array the array to set a value of. + ** @param index the array index to set the value to. + ** @param value the value to set. + ** @exception IllegalArgumentException if <code>array</code> is not a double array. + ** @exception ArrayIndexOutOfBoundsException if <code>index</code> is out of bounds. + **/ + public static void setDouble(Object array, int index, double value) + throws IllegalArgumentException, + ArrayIndexOutOfBoundsException { + if(array instanceof double[]) { + ((double[])array)[index] = value; + } else { + throw new IllegalArgumentException(); + } + } + + + /* + * PRIVATE HELPERS + */ + + private static Class objectClass; + static { + try { + objectClass = Class.forName("java.lang.Object"); + } catch(Exception E) { + } + } + + private static Object createDimensionedArray(Class type, int[] dimensions, int dimensionToAdd) + throws IllegalArgumentException, + NegativeArraySizeException { + if(dimensionToAdd > 0) { + Object toAdd = createDimensionedArray(type,dimensions,dimensionToAdd-1); + Class thisType = toAdd.getClass(); + Object[] retval = (Object[])createObjectArray(thisType, dimensions[dimensionToAdd]); + if(dimensions[dimensionToAdd]>0) { + retval[0] = toAdd; + } + for(int i=1;i<dimensions[dimensionToAdd];i++) { + retval[i] = createDimensionedArray(type,dimensions,dimensionToAdd-1); + } + return retval; + } else { + return newInstance(type,dimensions[0]); + } + } + + private static native Object createObjectArray(Class type, int dim); +}
\ No newline at end of file diff --git a/java/lang/reflect/Constructor.java b/java/lang/reflect/Constructor.java new file mode 100755 index 000000000..12a161940 --- /dev/null +++ b/java/lang/reflect/Constructor.java @@ -0,0 +1,260 @@ +/* + * java.lang.reflect.Constructor: part of the Java Class Libraries project. + * Copyright (C) 1998 John Keiser + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +package java.lang.reflect; + +/** + ** Constructor represents a constructor of a class. + ** It will allow you to create a new instance of the class or get generic information about the constructor.<P> + ** + ** <B>Note:</B> This class returns and accepts types as Classes, even primitive types; there are Class + ** types defined that represent each different primitive type. They are <code>java.lang.Boolean.TYPE, + ** java.lang.Byte.TYPE, </code>etc. These are not to be confused with the classes + ** <code>java.lang.Boolean, java.lang.Byte</code>, etc., which are real classes.<P> + ** + ** <STRONG>Implementation note:</STRONG> I am using non-native methods for almost everything here. It's a tradeoff. + ** If all the functions are going to be called at least once, then it's better to have the constructor pass in all the + ** information about the class and store it in the class because JNI overhead will be saved when the information + ** is accessed. If many of them will not be called, then the overhead of grabbing that information once was not + ** worth it. Especially true of getExceptionTypes() and getArgumentTypes(). I am considering making those two + ** lazily-accessed--grabbed natively the first time they are accessed and then cached thereafter. getExceptionTypes() + ** is not extremely likely to be called at all.<P> + ** + ** <STRONG>Serialization:</STROMG>Note that this is not a serializable class. It is entirely feasible to make it + ** serializable, but this is on Sun, not me.<P> + ** + ** <STRONG>Access and Security:</STRONG> Once this Constructor is created by java.lang.Class (which does its own + ** security check), any object may query it for information like parameter types, exception types, etc. + ** However, the Constructor may only be invoked using standard Java language access controls. The JLS says that + ** reflective access to all private, public and protected reflective members is granted to any class which + ** can be linked against the reflected member. Link-level enforcement is the enforcement of public, private, + ** protected and default access rules, based on the caller's relationship to the class (same package, + ** subclass, or unrelated). Thus, if you couldn't normally invoke this constructor from the calling class, you + ** can't do it using a Constructor object either.<P> + ** + ** The relevant section of the VM spec on link-security is <A + ** HREF='http://java.sun.com/docs/books/vmspec/html/Concepts.doc.html#22574'>2.16.3</A>, under Resolution. + ** A summary of the appropriate rules follows.<P> + ** + ** <STRONG>Summary of access rules</STRONG><BR> + ** Two checks are done, and they are the same checks--on both the member's class and the member itself: + ** <UL> + ** <LI>If the caller is the same class as the member's class, then it can access the member no matter + ** what.</LI> + ** <LI>If the caller is in the same package as the member's class, then the member's class and the member + ** itself must both be public, protected or default access.</LI> + ** <LI>If the caller is a subclass of the member's class, then the member's class and the member itself must + ** both be public or protected access.</LI> + ** <LI>If the caller is in the same package as the member's class, then the member's class and the member must + ** be public access.</LI> + ** </UL> + ** <P> + ** + ** As far as I can tell from the fairly confusing <A + ** HREF='http://java.sun.com/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc.html'>Inner + ** Classes Specification</A>, there should be no change to these rules from the addition of inner + ** classes in 1.1.<P> + ** + ** <STRONG>Version note:</STRONG> In 1.2, the security checks can be disabled in the AccessibleObject + ** interface. But this ain't 1.2. :)<P> + ** + ** <STRONG>BUGS:</STRONG> The maximum size of a signature right now is 4096 characters because I'm using + ** a static buffer when I calculate them. While fine for most purposes, it is for pathological cases that + ** specs are built. I'm not sure how I'll handle this yet. + ** + ** @author John Keiser + ** @version 1.1.0, 31 May 1998 + ** @see Member + ** @see java.lang.Class#getConstructor(Object[]) + ** @see java.lang.Class#getDeclaredConstructor(Object[]) + ** @see java.lang.Class#getConstructors() + ** @see java.lang.Class#getDeclaredConstructors() + **/ + +public final class Constructor implements Member { + private Class declaringClass; + private int modifiers; + private Class[] parameterTypes; + private Class[] exceptionTypes; + + /* Native State Stuff */ + private final int native_state = System.identityHashCode(this); + static { + initNativeState(); + } + + /* This is for JCL to call only. */ + private Constructor(Class declaringClass, int modifiers, + Class[] parameterTypes, Class[] exceptionTypes) { + this.declaringClass = declaringClass; + this.modifiers = modifiers; + this.parameterTypes = parameterTypes; + this.exceptionTypes = exceptionTypes; + + String className = declaringClass.getName(); + int lastDot = className.lastIndexOf('.'); + if(lastDot == -1) { + this.name = className; + } else { + this.name = className.substring(lastDot+1); + } + } + + /** Gets the class that declared this constructor. + ** <B>It is unclear whether this returns the class that actually syntactically declared + ** the member, or the class where the Constructor object was gotten from.</B> + ** @return the class that declared this member. + **/ + public Class getDeclaringClass() { + return declaringClass; + } + + /** Gets the modifiers this constructor uses. Use the <code>Modifier</code> + ** class to interpret the values. + ** A Constructor may only have the modifiers public, private and protected. + ** @see Modifier + ** @return an integer representing the modifiers to this Member. + **/ + public int getModifiers() { + return modifiers; + } + + /** Gets the name of this constructor (the non-qualified name of the class it was declared in). + ** @return the name of this constructor. + **/ + public String getName() { + return getDeclaringClass().getName(); + } + + /** Get the parameter list for this constructor. + ** @return a list of classes representing the names of the constructor's parameters. + **/ + public Class[] getParameterTypes() { + return parameterTypes; + } + + /** Get the exception types this constructor says it throws. + ** @return a list of classes representing the exception types. + **/ + public Class[] getExceptionTypes() { + return parameterTypes; + } + + /** Compare two objects to see if they are semantically equivalent. + ** Two Constructors are semantically equivalent if they have the same declaring class and the + ** same parameter list. <B>Though I really don't see how two different Constructor objects with + ** identical parameters could be created.</B> + ** @param o the object to compare to. + ** @return <code>true<code> if they are equal; <code>false</code> if not. + **/ + public boolean equals(Object o) { + if(this == o) { + return true; + } + if(o instanceof Constructor) { + Constructor c = (Constructor)o; + if(!getDeclaringClass().equals(c.getDeclaringClass())) { + return false; + } + Class[] p1 = getParameterTypes(); + Class[] p2 = c.getParameterTypes(); + if(p1.length != p2.length) { + return false; + } + for(int i=0;i<p1.length;i++) { + if(!p1.equals(p2)) { + return false; + } + } + return true; + } else { + return false; + } + } + + /** Get the hash code for the Constructor. + ** Constructor hash code is the hash code of the declaring class's name. + ** @return the hash code for the object. + **/ + public int hashCode() { + return getDeclaringClass().getName().hashCode(); + } + + /** Get a String representation of the Constructor. + ** A Constructor's String representation is <modifiers> <classname>(<paramtypes>). + ** Example: <code>public java.lang.Thread(java.lang.Runnable,int)</code> + ** @return the String representation of the Constructor. + **/ + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append(Modifier.toString(getModifiers())); + sb.append(' '); + sb.append(getDeclaringClass().getName()); + sb.append('('); + Class[] c = getParameterTypes(); + if(c.length > 0) { + sb.append(c[0].getName()); + for(int i = 1; i < c.length; i++) { + sb.append(','); + sb.append(c[i].getName()); + } + } + return sb.toString(); + } + + /** Create a new instance of the object the constructor can construct. + ** The constructor will permit widening argument conversions, but not narrowing conversions. + ** @param args the arguments to the constructor. + ** @return the newly created object. + ** @exception InstantiationException if the class is abstract. <B>Never mind that there + ** should be no constructors in an abstract class.</B> + ** @exception IllegalAccessException if the constructor could not normally be called + ** by the Java code (i.e. it is not public). + ** @exception IllegalArgumentException if the number of arguments is incorrect, or if the + ** arguments cannot be converted to the actual argument + ** types, even with a widening conversion. + ** @exception InvocationTargetException if the constructor throws an exception. + **/ + public Object newInstance(Object args[]) + throws InstantiationException, + IllegalAccessException, + IllegalArgumentException, + InvocationTargetException { + return constructNative(args, declaringClass, modifiers, parameterTypes, args.length == parameterTypes.length ? args.length : -1); + } + + /* + * STATIC NATIVE HELPERS + */ + + private static native void initNativeState(); + + /* + * NATIVE HELPERS + */ + protected void finalize() { + finalizeNative(); + } + + private native void finalizeNative(); + + private native Object constructNative(Object[] args, Class declaringClass, + int modifiers, Class[] parameterTypes, int argLength); +} diff --git a/java/lang/reflect/DEPENDENCIES b/java/lang/reflect/DEPENDENCIES new file mode 100755 index 000000000..2593b7854 --- /dev/null +++ b/java/lang/reflect/DEPENDENCIES @@ -0,0 +1,9 @@ +DEPENDENCIES of java.lang.reflect Java side. + +1.1: +No known direct dependencies on 1.2 or even 1.1-specific +stuff. While java.lang.Class methods defined in 1.1 are +the only way to create these classes, once they are created +they do not depend on any 1.1-specific methods. The native +side, however, is a different story, so this stuff really +couldn't run on 1.0. diff --git a/java/lang/reflect/Field.java b/java/lang/reflect/Field.java new file mode 100644 index 000000000..0b397203a --- /dev/null +++ b/java/lang/reflect/Field.java @@ -0,0 +1,385 @@ +/* + * java.lang.reflect.Field: part of the Java Class Libraries project. + * Copyright (C) 1998 John Keiser + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +package java.lang.reflect; + +/** + ** The Field class represents a member variable of a class. + ** It allows you to read and manipulate that variable.<P> + ** + ** <B>Note:</B> This class returns and accepts types as Classes, even primitive types; there are Class + ** types defined that represent each different primitive type. They are <code>java.lang.Boolean.TYPE, + ** java.lang.Byte.TYPE, </code>etc. These are not to be confused with the classes + ** <code>java.lang.Boolean, java.lang.Byte</code>, etc., which are real classes.<P> + ** + ** Also note that this is not a serializable class. It is entirely feasible to make it serializable + ** using the Externalizable interface, but this is on Sun, not me. + ** + ** @author John Keiser + ** @version 1.1.0, 31 May 1998 + ** @see Member + ** @see java.lang.Class#getField(String) + ** @see java.lang.Class#getDeclaredField(String) + ** @see java.lang.Class#getFields() + ** @see java.lang.Class#getDeclaredFields() + **/ +public final class Field implements Member { + private Class declaringClass; + private String name; + private int modifiers; + private Class type; + + /* Native State Stuff */ + final int native_state = System.identityHashCode(this); + static { + initNativeState(); + } + + /** This is only for JCL to call. **/ + Field(Class declaringClass, int modifiers, String name, Class type) { + this.declaringClass = declaringClass; + this.modifiers = modifiers; + this.name = name; + this.type = type; + } + + /** Gets the class that declared this field. + ** <B>It is unclear whether this returns the class that actually syntactically declared + ** the member, or the class where the Field object was gotten from.</B> + ** @return the class that declared this member. + **/ + public Class getDeclaringClass() { + return declaringClass; + } + + /** Gets the modifiers this field uses. Use the <code>Modifier</code> + ** class to interpret the values. A field can only have the following + ** modifiers: public, private, protected, static, final, transient, and volatile. + ** @see Modifier + ** @return an integer representing the modifiers to this Member. + **/ + public int getModifiers() { + return modifiers; + } + + /** Gets the name of this field. + ** @return the name of this field. + **/ + public String getName() { + return name; + } + + /** Gets the type of this field. + ** @return the type of this field. + **/ + public Class getType() { + return type; + } + + /** Compare two objects to see if they are semantically equivalent. + ** Two Fields are semantically equivalent if they have the same declaring class and the + ** same name. + ** @param o the object to compare to. + ** @return <code>true<code> if they are equal; <code>false</code> if not. + **/ + public boolean equals(Object o) { + if(this == o) { + return true; + } else { + return (o instanceof Field) + && getDeclaringClass().equals(((Field)o).getDeclaringClass()) + && getName().equals(((Field)o).getName()); + } + } + + /** Get the hash code for the Field. + ** The Field hash code is the hash code of its name XOR'd with the hash code of its class name. + ** @return the hash code for the object. + **/ + public int hashCode() { + return getDeclaringClass().getName().hashCode() ^ getName().hashCode(); + } + + /** Get a String representation of the Field. + ** A Field's String representation is <modifiers> <type> <class>.<fieldname>. + ** Example: <code>public transient boolean gnu.parse.Parser.parseComplete</code> + ** @return the String representation of the Constructor. + **/ + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append(Modifier.toString(getModifiers())); + sb.append(' '); + sb.append(getType().getName()); + sb.append(' '); + sb.append(getDeclaringClass().getName()); + sb.append('.'); + sb.append(getName()); + return sb.toString(); + } + + /** Get the value of this Field. If it is primitive, it will be wrapped in the + ** appropriate wrapper type (boolean = java.lang.Boolean) + ** If the field is static, <code>o</code> will be ignored. + ** @param o the object to get the value of this Field from. + ** @return the value of the Field. + ** @exception IllegalAccessException if you could not normally access this field + ** (i.e. it is not public). + ** @exception IllegalArgumentException if this field is not a field of <code>o</code>. + **/ + public native Object get(Object o) + throws IllegalAccessException, + IllegalArgumentException; + + /** Get the value of this boolean Field. + ** If the field is static, <code>o</code> will be ignored. + ** @param o the object to get the value of this Field from. + ** @return the value of the Field. + ** @exception IllegalAccessException if you could not normally access this field + ** (i.e. it is not public). + ** @exception IllegalArgumentException if this is not a boolean field of <code>o</code>. + **/ + public native boolean getBoolean(Object o) + throws IllegalAccessException, + IllegalArgumentException; + + /** Get the value of this byte Field. + ** If the field is static, <code>o</code> will be ignored. + ** @param o the object to get the value of this Field from. + ** @return the value of the Field. + ** @exception IllegalAccessException if you could not normally access this field + ** (i.e. it is not public). + ** @exception IllegalArgumentException if this is not a byte field of <code>o</code>. + **/ + public native byte getByte(Object o) + throws IllegalAccessException, + IllegalArgumentException; + + /** Get the value of this Field as a short. + ** If the field is static, <code>o</code> will be ignored. + ** @param o the object to get the value of this Field from. + ** @return the value of the Field. + ** @exception IllegalAccessException if you could not normally access this field + ** (i.e. it is not public). + ** @exception IllegalArgumentException if this is not a field of <code>o</code> or is + ** a field of <code>o</code> but cannot be converted + ** via a widening conversion to a short. + **/ + public native short getShort(Object o) + throws IllegalAccessException, + IllegalArgumentException; + + /** Get the value of this Field as a char. + ** If the field is static, <code>o</code> will be ignored. + ** @param o the object to get the value of this Field from. + ** @return the value of the Field. + ** @exception IllegalAccessException if you could not normally access this field + ** (i.e. it is not public). + ** @exception IllegalArgumentException if this is not a field of <code>o</code> or is + ** a field of <code>o</code> but cannot be converted + ** via a widening conversion to a char. + **/ + public native char getChar(Object o) + throws IllegalAccessException, + IllegalArgumentException; + + /** Get the value of this Field as an int. + ** If the field is static, <code>o</code> will be ignored. + ** @param o the object to get the value of this Field from. + ** @return the value of the Field. + ** @exception IllegalAccessException if you could not normally access this field + ** (i.e. it is not public). + ** @exception IllegalArgumentException if this is not a field of <code>o</code> or is + ** a field of <code>o</code> but cannot be converted + ** via a widening conversion to an int. + **/ + public native int getInt(Object o) + throws IllegalAccessException, + IllegalArgumentException; + + /** Get the value of this Field as a long. + ** If the field is static, <code>o</code> will be ignored. + ** @param o the object to get the value of this Field from. + ** @return the value of the Field. + ** @exception IllegalAccessException if you could not normally access this field + ** (i.e. it is not public). + ** @exception IllegalArgumentException if this is not a field of <code>o</code> or is + ** a field of <code>o</code> but cannot be converted + ** via a widening conversion to a long. + **/ + public native long getLong(Object o) + throws IllegalAccessException, + IllegalArgumentException; + + /** Get the value of this Field as a float. + ** If the field is static, <code>o</code> will be ignored. + ** @param o the object to get the value of this Field from. + ** @return the value of the Field. + ** @exception IllegalAccessException if you could not normally access this field + ** (i.e. it is not public). + ** @exception IllegalArgumentException if this is not a field of <code>o</code> or is + ** a field of <code>o</code> but cannot be converted + ** via a widening conversion to a float. + **/ + public native float getFloat(Object o) + throws IllegalAccessException, + IllegalArgumentException; + + /** Get the value of this Field as a double. + ** If the field is static, <code>o</code> will be ignored. + ** @param o the object to get the value of this Field from. + ** @return the value of the Field. + ** @exception IllegalAccessException if you could not normally access this field + ** (i.e. it is not public). + ** @exception IllegalArgumentException if this is not a field of <code>o</code> or is + ** a field of <code>o</code> but cannot be converted + ** via a widening conversion to a double. + **/ + public native double getDouble(Object o) + throws IllegalAccessException, + IllegalArgumentException; + + /** Set this Field. If it is a primitive field, the value passed must be wrapped in + ** the appropriate wrapped type (boolean = java.lang.Boolean) + ** If the field is static, <code>o</code> will be ignored. + ** @param o the object to set this Field on. + ** @param value the value to set this Field to. + ** @exception IllegalAccessException if you could not normally access this field + ** (i.e. it is not public). + ** @exception IllegalArgumentException if <code>value</code> cannot be converted by a + ** widening conversion to the underlying type of + ** the Field. + **/ + public native void set(Object o, Object value) + throws IllegalAccessException, + IllegalArgumentException; + + /** Set this boolean Field. + ** If the field is static, <code>o</code> will be ignored. + ** @param o the object to set this Field on. + ** @param value the value to set this Field to. + ** @exception IllegalAccessException if you could not normally access this field + ** (i.e. it is not public). + ** @exception IllegalArgumentException if this field is not a primitive boolean field. + **/ + public native void setBoolean(Object o, boolean value) + throws IllegalAccessException, + IllegalArgumentException; + + /** Set this byte Field. + ** If the field is static, <code>o</code> will be ignored. + ** @param o the object to set this Field on. + ** @param value the value to set this Field to. + ** @exception IllegalAccessException if you could not normally access this field + ** (i.e. it is not public). + ** @exception IllegalArgumentException if a byte cannot be converted via a widening + ** conversion to the type of this field. + **/ + public native void setByte(Object o, byte value) + throws IllegalAccessException, + IllegalArgumentException; + + /** Set this short Field. + ** If the field is static, <code>o</code> will be ignored. + ** @param o the object to set this Field on. + ** @param value the value to set this Field to. + ** @exception IllegalAccessException if you could not normally access this field + ** (i.e. it is not public). + ** @exception IllegalArgumentException if a byte cannot be converted via a widening + ** conversion to the type of this field. + **/ + public native void setShort(Object o, short value) + throws IllegalAccessException, + IllegalArgumentException; + + /** Set this char Field. + ** If the field is static, <code>o</code> will be ignored. + ** @param o the object to set this Field on. + ** @param value the value to set this Field to. + ** @exception IllegalAccessException if you could not normally access this field + ** (i.e. it is not public). + ** @exception IllegalArgumentException if a char cannot be converted via a widening + ** conversion to the type of this field. + **/ + public native void setChar(Object o, char value) + throws IllegalAccessException, + IllegalArgumentException; + + /** Set this int Field. + ** If the field is static, <code>o</code> will be ignored. + ** @param o the object to set this Field on. + ** @param value the value to set this Field to. + ** @exception IllegalAccessException if you could not normally access this field + ** (i.e. it is not public). + ** @exception IllegalArgumentException if an int cannot be converted via a widening + ** conversion to the type of this field. + **/ + public native void setInt(Object o, int value) + throws IllegalAccessException, + IllegalArgumentException; + + /** Set this long Field. + ** If the field is static, <code>o</code> will be ignored. + ** @param o the object to set this Field on. + ** @param value the value to set this Field to. + ** @exception IllegalAccessException if you could not normally access this field + ** (i.e. it is not public). + ** @exception IllegalArgumentException if a long cannot be converted via a widening + ** conversion to the type of this field. + **/ + public native void setLong(Object o, long value) + throws IllegalAccessException, + IllegalArgumentException; + + /** Set this float Field. + ** If the field is static, <code>o</code> will be ignored. + ** @param o the object to set this Field on. + ** @param value the value to set this Field to. + ** @exception IllegalAccessException if you could not normally access this field + ** (i.e. it is not public). + ** @exception IllegalArgumentException if a float cannot be converted via a widening + ** conversion to the type of this field. + **/ + public native void setFloat(Object o, float value) + throws IllegalAccessException, + IllegalArgumentException; + + /** Set this double Field. + ** If the field is static, <code>o</code> will be ignored. + ** @param o the object to set this Field on. + ** @param value the value to set this Field to + ** @exception IllegalAccessException if you could not normally access this field + ** (i.e. it is not public). + ** @exception IllegalArgumentException if this field is not a primitive double field. + **/ + public native void setDouble(Object o, double value) + throws IllegalAccessException, + IllegalArgumentException; + + /* + * STATIC NATIVE HELPERS + */ + + static native void initNativeState(); + + /* + * NATIVE HELPERS + */ + protected native void finalize(); +}
\ No newline at end of file diff --git a/java/lang/reflect/InvocationTargetException.java b/java/lang/reflect/InvocationTargetException.java new file mode 100644 index 000000000..b6eb30ad0 --- /dev/null +++ b/java/lang/reflect/InvocationTargetException.java @@ -0,0 +1,65 @@ +/* + * java.lang.reflect.InvocationTargetException: part of the Java Class Libraries project. + * Copyright (C) 1998 John Keiser + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +package java.lang.reflect; + +/** + ** InvocationTargetException is sort of a way to "wrap" whatever exception comes up when a method or + ** constructor is called via Reflection. + ** + ** @author John Keiser + ** @version 1.1.0, 31 May 1998 + ** @see Method#invoke(Object,Object[]) + ** @see Constructor#newInstance(Object[]) + **/ + +public class InvocationTargetException extends Exception { + private Throwable targetException; + + /** <B>I am not sure if I'm supposed to copy the protected functions from the spec or not ... ?</B> **/ + protected InvocationTargetException() { + super(); + this.targetException = null; + } + + /** Create an <code>InvocationTargetException</code> using another exception. + ** @param targetException the exception to wrap + **/ + public InvocationTargetException(Throwable targetException) { + super("Invoked method threw " + targetException.getClass().getName()); + this.targetException = targetException; + } + + /** Create an <code>InvocationTargetException</code> using another exception and an error message. + ** @param targetException the exception to wrap + ** @param err an extra reason for the exception-throwing + **/ + public InvocationTargetException(Throwable targetException, String err) { + super(err); + this.targetException = targetException; + } + + /** Get the wrapped (targeted) exception. + ** @return the targeted exception. + **/ + public Throwable getTarget() { + return targetException; + } +} diff --git a/java/lang/reflect/Member.java b/java/lang/reflect/Member.java new file mode 100644 index 000000000..131a48dce --- /dev/null +++ b/java/lang/reflect/Member.java @@ -0,0 +1,59 @@ +/* + * java.lang.reflect.Member: part of the Java Class Libraries project. + * Copyright (C) 1998 John Keiser + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +package java.lang.reflect; + +/** + ** Member is an interface that represents any member of a class; i.e. a field, a method or a constructor. + ** You can get information about the declaring class, name or modifiers of the member with this interface. + ** @author John Keiser + ** @version 1.1.0, 31 May 1998 + **/ +public interface Member { + /** Represents all members, whether public, private, protected or package-protected. + ** Used in java.lang.SecurityManager.checkMemberAccess() to determine the type of members + ** to access. + **/ + public static final int DECLARED = 0; + + /** Represents public members only. Used in java.lang.SecurityManager.checkMemberAccess() + ** to determine the type of members to access. + **/ + public static final int PUBLIC = 1; + + /** Gets the class that declared this member. + ** <STRONG>It is unclear whether this returns the class that actually syntactically declared + ** the member, or the class where the <code>Member</code> object was gotten from.</STRONG> + ** @return the class that declared this member. + **/ + public abstract Class getDeclaringClass(); + + /** Gets the modifiers this member uses. Use the <code>Modifier</code> + ** class to interpret the values. + ** @see Modifier + ** @return an integer representing the modifiers to this Member. + **/ + public abstract int getModifiers(); + + /** Gets the name of this member. + ** @return the name of this member. + **/ + public abstract String getName(); +}
\ No newline at end of file diff --git a/java/lang/reflect/Method.java b/java/lang/reflect/Method.java new file mode 100644 index 000000000..7504ebded --- /dev/null +++ b/java/lang/reflect/Method.java @@ -0,0 +1,295 @@ +/* + * java.lang.reflect.Method: part of the Java Class Libraries project. + * Copyright (C) 1998 John Keiser + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +package java.lang.reflect; + +/** + ** Method is a class which represents a method. + ** You may get information about it and make calls on it.<P> + ** + ** <STRONG>Note:</STRONG> This class returns and accepts types as Classes, even primitive types; there are Class + ** types defined that represent each different primitive type. They are <code>java.lang.Boolean.TYPE, + ** java.lang.Byte.TYPE, </code>etc. These are not to be confused with the classes + ** <code>java.lang.Boolean, java.lang.Byte</code>, etc., which are real classes.<P> + ** + ** <STRONG>Implementation note:</STRONG> I am using non-native methods for almost everything here. It's a tradeoff. + ** If all the functions are going to be called at least once, then it's better to have the constructor pass in all the + ** information about the class and store it in the class because JNI overhead will be saved when the information + ** is accessed. If many of them will not be called, then the overhead of grabbing that information once was not + ** worth it. Especially true of getExceptionTypes() and getArgumentTypes(). I am considering making those two + ** lazily-accessed--grabbed natively the first time they are accessed and then cached thereafter. getExceptionTypes() + ** is not extremely likely to be called at all.<P> + ** + ** <STRONG>Serialization:</STROMG>Note that this is not a serializable class. It is entirely feasible to make it + ** serializable, but this is on Sun, not me.<P> + ** + ** <STRONG>Access and Security:</STRONG> Once this Method is created by java.lang.Class (which does its own + ** security check), any object may query it for information like parameter types, exception types, etc. + ** However, the Method may only be invoked using standard Java language access controls. The JLS says that + ** reflective access to all private, public and protected reflective members is granted to any class which + ** can be linked against the reflected member. Link-level enforcement is the enforcement of public, private, + ** protected and default access rules, based on the caller's relationship to the class (same package, + ** subclass, or unrelated). Thus, if you couldn't normally invoke this method from the calling class, you + ** can't do it using a Method object either.<P> + ** + ** The relevant section of the VM spec on link-security is <A + ** HREF='http://java.sun.com/docs/books/vmspec/html/Concepts.doc.html#22574'>2.16.3</A>, under Resolution. + ** A summary of the appropriate rules follows.<P> + ** + ** <STRONG>Summary of access rules</STRONG><BR> + ** Two checks are done, and they are the same checks--on both the member's class and the member itself: + ** <UL> + ** <LI>If the caller is the same class as the member's class, then it can access the member no matter + ** what.</LI> + ** <LI>If the caller is in the same package as the member's class, then the member's class and the member + ** itself must both be public, protected or default access.</LI> + ** <LI>If the caller is a subclass of the member's class, then the member's class and the member itself must + ** both be public or protected access.</LI> + ** <LI>If the caller is in the same package as the member's class, then the member's class and the member must + ** be public access.</LI> + ** </UL> + ** <P> + ** + ** As far as I can tell from the fairly confusing <A + ** HREF='http://java.sun.com/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc.html'>Inner + ** Classes Specification</A>, there should be no change to these rules from the addition of inner + ** classes in 1.1.<P> + ** + ** <STRONG>Version note:</STRONG> In 1.2, the security checks can be disabled in the AccessibleObject + ** interface. But this ain't 1.2. :)<P> + ** + ** <STRONG>BUGS:</STRONG> The maximum size of a signature right now is 4096 characters because I'm using + ** a static buffer when I calculate them. While fine for most purposes, it is for pathological cases that + ** specs are built. I'm not sure how I'll handle this yet. + ** + ** @author John Keiser + ** @version 1.1.0, 31 May 1998 + ** @see Member + ** @see java.lang.Class#getMethod(String,Object[]) + ** @see java.lang.Class#getDeclaredMethod(String,Object[]) + ** @see java.lang.Class#getMethods() + ** @see java.lang.Class#getDeclaredMethods() + **/ + +public final class Method implements Member { + Class declaringClass; + String name; + int modifiers; + Class returnType; + Class[] parameterTypes; + Class[] exceptionTypes; + + /* Preprocessed information */ + private int[] targetArgTypes; + private int targetRetType; + private String methodSignature; + + /* Native State Stuff */ + final int native_state = System.identityHashCode(this); + static { + initNativeState(); + } + + /** For use by JCL only. **/ + private Method(Class declaringClass, int modifiers, String name, + Class returnType, Class[] parameterTypes, Class[] exceptionTypes) { + this.declaringClass = declaringClass; + this.modifiers = modifiers; + this.name = name; + this.returnType = returnType; + this.parameterTypes = parameterTypes; + this.exceptionTypes = exceptionTypes; + }; + + /** Gets the class that declared this method. + ** <STRONG>It is unclear whether this returns the class that actually syntactically declared + ** the member, or the class where the Method object was gotten from.</STRONG> + ** @return the class that declared this member. + **/ + public Class getDeclaringClass() { + return declaringClass; + } + + /** Gets the modifiers this method uses. Use the <code>Modifier</code> + ** class to interpret the values. + ** A Method may only have the modifiers public, private, protected, abstract, + ** static, final, synchronized, and native. + ** @see Modifier + ** @return an integer representing the modifiers to this Member. + **/ + public int getModifiers() { + return modifiers; + } + + /** Gets the name of this method. + ** @return the name of this method. + **/ + public String getName() { + return name; + } + + /** Gets the return type of this method. + ** @return the type of this method. + **/ + public Class getReturnType() { + return returnType; + } + + /** Get the parameter list for this method. + ** @return a list of classes representing the names of the method's parameters. + **/ + public Class[] getParameterTypes() { + return parameterTypes; + } + + /** Get the exception types this method says it throws. + ** @return a list of classes representing the exception types. + **/ + public Class[] getExceptionTypes() { + return exceptionTypes; + } + + /** Compare two objects to see if they are semantically equivalent. + ** Two Methods are semantically equivalent if they have the same declaring class, name, + ** and parameter list. <STRONG>Though I really don't see how two different Method objects + ** with identical parameters could be created.</STRONG> + ** @param o the object to compare to. + ** @return <code>true<code> if they are equal; <code>false</code> if not. + **/ + public boolean equals(Object o) { + if(this == o) { + return true; + } + if(o instanceof Constructor) { + Constructor c = (Constructor)o; + if(!getDeclaringClass().equals(c.getDeclaringClass())) { + return false; + } + if(!getName().equals(c.getName())) { + return false; + } + Class[] p1 = getParameterTypes(); + Class[] p2 = c.getParameterTypes(); + if(p1.length != p2.length) { + return false; + } + for(int i=0;i<p1.length;i++) { + if(!p1.equals(p2)) { + return false; + } + } + return true; + } else { + return false; + } + } + + /** Get the hash code for the Method. + ** Constructor hash code is the hash code of the declaring class's name XOR'd with the method name. + ** @return the hash code for the object. + **/ + public int hashCode() { + return getDeclaringClass().getName().hashCode() ^ getName().hashCode(); + } + + /** Get a String representation of the Constructor. + ** A Constructor's String representation is <modifiers> <returntype> <methodname>(<paramtypes>). + ** Example: <code>public static int run(java.lang.Runnable,int)</code> + ** @return the String representation of the Constructor. + **/ + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append(Modifier.toString(getModifiers())); + sb.append(' '); + sb.append(getReturnType()); + sb.append(' '); + sb.append(getDeclaringClass().getName()); + sb.append('.'); + sb.append(getName()); + sb.append('('); + Class[] c = getParameterTypes(); + if(c.length > 0) { + sb.append(c[0].getName()); + for(int i = 1; i < c.length; i++) { + sb.append(','); + sb.append(c[i].getName()); + } + } + sb.append(')'); + return sb.toString(); + } + + + /** Invoke the method.<P> + ** The method will permit widening argument conversions, but not narrowing conversions.<P> + ** For static methods, declaringClass is used for the Method lookup, not the class of the Object + ** being invoked on.<P> + ** For instance methods, the method in the class of the Object itself is invoked.<P> + ** + ** The permissions and workings of this method are the same as if you had invoked the method in Java + ** using ((<declaringClass>)o).<methodName>(<args>). If your object had enough permissions to do + ** that, then this call will succeed.<P> + ** + ** <STRONG>Robustness Note:</STRONG> if the method returns an Object of the wrong type somehow, then + ** that will not be checked by invoke(). Shouldn't happen anyway, but this information is included + ** for completeness. + ** + ** @param o the object to invoke the method on. + ** @param args the arguments to the method. + ** @return the return value of the method, wrapped in the appropriate wrapper if it is primitive. + ** @exception IllegalAccessException if the method could not normally be called + ** by the Java code (see note at beginning of class + ** for more information). + ** @exception IllegalArgumentException if the number of arguments is incorrect; if the + ** arguments cannot be converted to the actual argument + ** types, even with a widening conversion; for instance + ** methods, if the Object invoked on is not of appropriate + ** type. + ** @exception InvocationTargetException if the method throws an exception. + **/ + public Object invoke(Object o, Object[] args) + throws IllegalAccessException, + IllegalArgumentException, + InvocationTargetException { + int length = (args.length == parameterTypes.length) ? args.length : -1; + return invokeNative(o, args, declaringClass, name, modifiers, returnType, parameterTypes, length); + } + + protected void finalize() { + finalizeNative(modifiers); + } + + /* + * STATIC NATIVE HELPERS + */ + + private static native void initNativeState(); + + /* + * NATIVE HELPERS + */ + + private native void finalizeNative(int modifiers); + + private native Object invokeNative(Object o, Object[] args, + Class declaringClass, String name, int modifiers, + Class returnType, Class[] parameterTypes, + int length); +}
\ No newline at end of file diff --git a/java/lang/reflect/Modifier.java b/java/lang/reflect/Modifier.java new file mode 100644 index 000000000..876e84a1c --- /dev/null +++ b/java/lang/reflect/Modifier.java @@ -0,0 +1,240 @@ +/* + * java.lang.reflect.Modifier: part of the Java Class Libraries project. + * Copyright (C) 1998 John Keiser + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +package java.lang.reflect; + +/** + ** Modifier is a helper class with static methods to determine whether an int returned from getModifiers() + ** represents static, public, protected, native, final, etc... and provides an additional method to print + ** out all of the modifiers in an int in order.<P> + ** + ** The methods in this class use the bitmask values in the VM spec to determine the modifiers of an int. + ** This means that a VM must return a standard mask, conformant with the VM spec. I don't know if this is how + ** Sun does it, but I'm willing to bet money that it is. + ** + ** @author John Keiser + ** @version 1.1.0, 31 May 1998 + ** @see Member#getModifiers() + ** @see Method#getModifiers() + ** @see Field#getModifiers() + ** @see Constructor#getModifiers() + ** @see Class#getModifiers() + **/ +public class Modifier { + /** <STRONG>This constructor really shouldn't be here ... there are no instance methods or variables of this + ** class, so instantiation is worthless. However, this function is in the 1.1 spec, so it is added for + ** completeness.</STRONG> + **/ + public Modifier() {} + + /** Public: accessible from any other class. **/ + public static final int PUBLIC = 0x0001; + + /** Private: accessible only from the declaring class. **/ + public static final int PRIVATE = 0x0002; + + /** Protected: accessible only to subclasses. **/ + public static final int PROTECTED = 0x0004; + + /** Static: field or method - can be accessed or invoked without an instance of the declaring class. **/ + public static final int STATIC = 0x0008; + + /** Final:<BR> + ** <UL> + ** <LI> Class: no subclasses allowed. </LI> + ** <LI> Field: cannot be changed. </LI> + ** <LI> Method: cannot be overriden. </LI> + ** </UL> + **/ + public static final int FINAL = 0x0010; + + /** Synchronized: lock the class while calling this method. **/ + public static final int SYNCHRONIZED = 0x0020; + + /** Volatile: cannot be cached.<P> **/ + public static final int VOLATILE = 0x0040; + + /** Transient: not serialized or deserialized. **/ + public static final int TRANSIENT = 0x0080; + + /** Native: use JNI to call this method. **/ + public static final int NATIVE = 0x0100; + + /** Interface: is an interface. **/ + public static final int INTERFACE = 0x0200; + + /** Abstract: class - may not be instantiated; method - may not be called. **/ + public static final int ABSTRACT = 0x0400; + + + /* NOTE: THIS IS HERE BECAUSE IT IS IN THE VM SPEC. I INCLUDE IT FOR COMPLETENESS. IT ATTACHES TO A CLASS AND MEANS "Treat superclasses specially in invokespecial". Note that it is the same as synchronized. Reuse of the constant. *shudder* */ + private static final int SUPER = 0x0020; + + + + /** Check whether the given modifier is public. + ** @param mod the modifier. + ** @return <code>true</code> if public, <code>false</code> otherwise. + **/ + public static boolean isPublic(int mod) { return (mod & PUBLIC) != 0; } + + /** Check whether the given modifier is private. + ** @param mod the modifier. + ** @return <code>true</code> if private, <code>false</code> otherwise. + **/ + public static boolean isPrivate(int mod) { return (mod & PRIVATE) != 0; } + + /** Check whether the given modifier is protected. + ** @param mod the modifier. + ** @return <code>true</code> if protected, <code>false</code> otherwise. + **/ + public static boolean isProtected(int mod) { return (mod & PROTECTED) != 0; } + + /** Check whether the given modifier is static. + ** @param mod the modifier. + ** @return <code>true</code> if static, <code>false</code> otherwise. + **/ + public static boolean isStatic(int mod) { return (mod & STATIC) != 0; } + + /** Check whether the given modifier is final. + ** @param mod the modifier. + ** @return <code>true</code> if final, <code>false</code> otherwise. + **/ + public static boolean isFinal(int mod) { return (mod & FINAL) != 0; } + + /** Check whether the given modifier is synchronized. + ** @param mod the modifier. + ** @return <code>true</code> if synchronized, <code>false</code> otherwise. + **/ + public static boolean isSynchronized(int mod) { return (mod & SYNCHRONIZED) != 0; } + + /** Check whether the given modifier is volatile. + ** @param mod the modifier. + ** @return <code>true</code> if volatile, <code>false</code> otherwise. + **/ + public static boolean isVolatile(int mod) { return (mod & VOLATILE) != 0; } + + /** Check whether the given modifier is transient. + ** @param mod the modifier. + ** @return <code>true</code> if transient, <code>false</code> otherwise. + **/ + public static boolean isTransient(int mod) { return (mod & TRANSIENT) != 0; } + + /** Check whether the given modifier is native. + ** @param mod the modifier. + ** @return <code>true</code> if native, <code>false</code> otherwise. + **/ + public static boolean isNative(int mod) { return (mod & NATIVE) != 0; } + + /** Check whether the given modifier is an interface. + ** @param mod the modifier. + ** @return <code>true</code> if an interface, <code>false</code> otherwise. + **/ + public static boolean isInterface(int mod) { return (mod & INTERFACE) != 0; } + + /** Check whether the given modifier is abstract. + ** @param mod the modifier. + ** @return <code>true</code> if abstract, <code>false</code> otherwise. + **/ + public static boolean isAbstract(int mod) { return (mod & ABSTRACT) != 0; } + + /** Get a string representation of all the modifiers represented by the object. + ** The keywords are printed in this order: + ** <code><public|private|protected> abstract static final synchronized native transient volatile interface</code><P> + ** + ** <STRONG>This is, near as I can tell, the "canonical order" of modifiers mentioned by Sun in the reference + ** implementation. I have inferred this from the order of printing in the Field, Method and Constructor + ** classes.</STRONG><P> + ** + ** <STRONG>Another note:</STRONG> I am not certain whether interface should be printed out. This needs to be tested + ** on Sun's implementation. + ** + ** @param mod the modifier. + ** @return the String representing the modifiers. + **/ + public static String toString(int mod) { + StringBuffer sb = new StringBuffer(); + if(isPublic(mod)) { + sb.append("public"); + } else if(isPrivate(mod)) { + sb.append("private"); + } else if(isProtected(mod)) { + sb.append("protected"); + } + + if(isAbstract(mod)) { + if(sb.length() > 0) { + sb.append(' '); + } + sb.append("abstract"); + } + + if(isStatic(mod)) { + if(sb.length() > 0) { + sb.append(' '); + } + sb.append("static"); + } + + if(isFinal(mod)) { + if(sb.length() > 0) { + sb.append(' '); + } + sb.append("final"); + } + + if(isSynchronized(mod)) { + if(sb.length() > 0) { + sb.append(' '); + } + sb.append("synchronized"); + } + + if(isNative(mod)) { + if(sb.length() > 0) { + sb.append(' '); + } + sb.append("native"); + } + + if(isTransient(mod)) { + if(sb.length() > 0) { + sb.append(' '); + } + sb.append("transient"); + } + + if(isVolatile(mod)) { + if(sb.length() > 0) { + sb.append(' '); + } + sb.append("volatile"); + } + + if(isInterface(mod)) { + if(sb.length() > 0) { + sb.append(' '); + } + sb.append("interface"); + } + + return sb.toString(); + } +}
\ No newline at end of file diff --git a/java/lang/reflect/README b/java/lang/reflect/README new file mode 100644 index 000000000..52efdc4bf --- /dev/null +++ b/java/lang/reflect/README @@ -0,0 +1,23 @@ +README for java.lang.reflect: + + +Jun 20 1998 - John Keiser - initial revision, 1.1.0 + +OK, the Java side was easy. + +The difficult part is the native side, and while that has gone somewhere, there +is so much integration between the VM and class libraries in Sun's version that +a whole new API had to be created (the VMI being the prominent one). JCL +Reflection will likely never work with Sun's JDK 1.1 unless we manage some real +magic. Therefore I am targeting it to Japhar and Kaffe 1.1, where we at least +have some ability to create VMI functionality. + +I am not even certain if Sun's JDK 1.2 will be able to support JCL Reflection. +I am not getting my hopes up. Unless their JVMDI spec improves, it will be +impossible to do so efficiently, and probably impossible in any case, without +knowing their internal structures so that we can . + +This whole thing has been compiled but has never run. I am checking this in +right now so that Geoffrey Berry, who is working on Serialization, will have +some starting points, especially in regards to his native code. + diff --git a/java/lang/reflect/STATUS b/java/lang/reflect/STATUS new file mode 100755 index 000000000..aca52c64b --- /dev/null +++ b/java/lang/reflect/STATUS @@ -0,0 +1,17 @@ +STATUS of java.lang.reflect Java side + +THIS CODE IS ABSOLUTELY ENTIRELY UNTESTED. IT HAS NEVER ONCE BEEN RUN. CURRENTLY INTENDED FOR REFERENCE ONLY. + +JDK1.1: +INTERFACES: +Member - complete, untested. + +CLASSES: +Array - complete, untested. +Method - complete, untested. +Modifier - complete, untested. +Field - incomplete. Compiles, but I may still change the modifiers (+ or - native) on some of the methods. +Constructor - complete, untested. + +EXCEPTIONS: +InvocationTargetException - complete, untested. Worried about compatibility with Sun's implementation. diff --git a/java/lang/reflect/TODO b/java/lang/reflect/TODO new file mode 100755 index 000000000..a11fd35c9 --- /dev/null +++ b/java/lang/reflect/TODO @@ -0,0 +1,6 @@ +TODO for java.lang.reflect Java side + +- Field needs to be overhauled for efficiency the way Method and Constructor + have been. +- Testing needs to be written. +- See native TODO. diff --git a/native/lib/DEPENDENCIES b/native/lib/DEPENDENCIES new file mode 100755 index 000000000..f70c669b7 --- /dev/null +++ b/native/lib/DEPENDENCIES @@ -0,0 +1,5 @@ +DEPENDENCIES for generic JCL libs: + +JCL: JNI +JNILINK: JNI,JCL,VMI +PRIMLIB: JNI,JCL diff --git a/native/lib/README b/native/lib/README new file mode 100755 index 000000000..1424b06b6 --- /dev/null +++ b/native/lib/README @@ -0,0 +1,27 @@ +README for generic JCL libs: + + +Jun 20 1998: John Keiser +Initial Revision: 1.1.0 + +OK, everything in the JCL libs is 1.1-compliant: if it uses +anything that could be VM-specific, it pawns the job off on +the VMI, whose job it is to interface to the virtual +machine. Some of these dependencies will go away with +JVMDI in 1.2, but until then, VMI is the way to go. + +jcl.h is for generically useful stuff: right now most of +the functions it has do some simple function, check for +errors, and throw an appropriate exception if an error +occurs. + +primlib.h is a way of caching the reflective types and the +wrapper types and does a little conversion between types to +boot. + +jnilink.h allows you to do typical linker functions: +caching of the methodID if it is final, private, or static +method and thus cannot be overriden; or re-resolution of +the methodID for each different class. Even re-resolution +can be made efficient by making it VM-specific; I.E. +caching the slot number instead of the name and signature. diff --git a/native/lib/STATUS b/native/lib/STATUS new file mode 100755 index 000000000..2f8ba2e31 --- /dev/null +++ b/native/lib/STATUS @@ -0,0 +1,8 @@ +STATUS for generic JCL libs: + +1.1: + +JNILINK: compiled, untested. +PRIMLIB: compiled, untested. +JCL: compiled, untested. + diff --git a/native/lib/jcl.c b/native/lib/jcl.c new file mode 100755 index 000000000..796715847 --- /dev/null +++ b/native/lib/jcl.c @@ -0,0 +1,53 @@ +#include <jcl.h> +#include <malloc.h> + +JNIEXPORT void JNICALL JCL_ThrowException(JNIEnv * env, char * className, char * errMsg) { + jclass excClass = (*env)->FindClass(env, className); + if((*env)->ExceptionOccurred(env)) { + return; + } + (*env)->ThrowNew(env, excClass, errMsg); +} + +JNIEXPORT void * JNICALL JCL_malloc(JNIEnv * env, size_t size) { + void * mem = malloc(size); + if(mem == NULL) { + JCL_ThrowException(env, "java/lang/OutOfMemoryError", "malloc() failed."); + return NULL; + } + return mem; +} + +JNIEXPORT char * JNICALL JCL_jstring_to_cstring(JNIEnv * env, jstring s) { + char* cstr; + if(s == NULL) { + JCL_ThrowException(env, "java/lang/NullPointerException","Null string"); + return NULL; + } + cstr = (char*)(*env)->GetStringUTFChars(env, s, NULL); + if(cstr == NULL) { + JCL_ThrowException(env, "java/lang/InternalError", "GetStringUTFChars() failed."); + return NULL; + } + return cstr; +} + +JNIEXPORT void JNICALL JCL_free_cstring(JNIEnv * env, jstring s, char * cstr) { + (*env)->ReleaseStringUTFChars(env, s, cstr); +} + +JNIEXPORT jint JNICALL JCL_MonitorEnter(JNIEnv * env, jobject o) { + jint retval = (*env)->MonitorEnter(env,o); + if(retval != 0) { + JCL_ThrowException(env, "java/lang/InternalError", "MonitorEnter() failed."); + } + return retval; +} + +JNIEXPORT jint JNICALL JCL_MonitorExit(JNIEnv * env, jobject o) { + jint retval = (*env)->MonitorExit(env,o); + if(retval != 0) { + JCL_ThrowException(env, "java/lang/InternalError", "MonitorExit() failed."); + } + return retval; +} diff --git a/native/lib/jcl.h b/native/lib/jcl.h new file mode 100755 index 000000000..657a181fc --- /dev/null +++ b/native/lib/jcl.h @@ -0,0 +1,23 @@ +#ifndef __JCL_H__ +#define __JCL_H__ + +#include <jni.h> + +JNIEXPORT void JNICALL JCL_ThrowException(JNIEnv * env, char * className, char * errMsg); +JNIEXPORT void * JNICALL JCL_malloc(JNIEnv * env, size_t size); +JNIEXPORT char * JNICALL JCL_jstring_to_cstring(JNIEnv * env, jstring s); +JNIEXPORT void JNICALL JCL_free_cstring(JNIEnv * env, jstring s, char * cstr); +JNIEXPORT jint JNICALL JCL_MonitorEnter(JNIEnv * env, jobject o); +JNIEXPORT jint JNICALL JCL_MonitorExit(JNIEnv * env, jobject o); + +#define JCL_RETHROW_EXCEPTION(env) if((*(env))->ExceptionOccurred((env)) != NULL) return NULL; + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#endif
\ No newline at end of file diff --git a/native/lib/jnilink.c b/native/lib/jnilink.c new file mode 100755 index 000000000..31f8c1a19 --- /dev/null +++ b/native/lib/jnilink.c @@ -0,0 +1,162 @@ +#include "jnilink.h" +#include <string.h> +#include <vmi.h> +#include <jcl.h> + +#include <malloc.h> + +typedef struct jniMethodInfo { + int isStatic; + union { + struct { + char * name; + char * sig; + } dynamic; + jmethodID statID; + } data; +} jniMethodInfo; + +/* These functions are called to get the link pointers. */ +/* One possible optimization for Japhar would be to store the slot number of the method in the linkPtr. + * Another, which works for JNI too, is to see if the class or method is final and simply store the jmethodID. + * For JNI, the linkPtr must point to a struct containing the name and sig so that it can be re-resolved for + * every object. + */ +JNIEXPORT linkPtr JNICALL LINK_LinkMethod (JNIEnv * env, jclass clazz, char * name, char * sig) { + jniMethodInfo * m; + + jint classMods; + jint methodMods; + vmiError vmiErr; + + jmethodID theMethod; + + m = JCL_malloc(env, sizeof(jniMethodInfo)); + if(m == NULL) + return NULL; + + vmiErr = VMI_GetClassModifiers(env, clazz, &classMods); + if(vmiErr != VMI_ERROR_NONE) { + VMI_ThrowAppropriateException(env, vmiErr); + free(m); + return NULL; + } + + theMethod = (*env)->GetMethodID(env, clazz, name, sig); + if((*env)->ExceptionOccurred(env)) { + free(m); + return NULL; + } + + if(classMods & VMI_MOD_FINAL) { + m->isStatic = TRUE; + } else { + vmiErr = VMI_GetMethodModifiers(env, theMethod, &methodMods); + if(vmiErr != VMI_ERROR_NONE) { + VMI_ThrowAppropriateException(env, vmiErr); + free(m); + return NULL; + } + + if(methodMods & VMI_MOD_FINAL || methodMods & VMI_MOD_STATIC || methodMods & VMI_MOD_PRIVATE) { + m->isStatic = TRUE; + } else { + if(!strcmp(name,"<init>")) + m->isStatic = TRUE; + else + m->isStatic = FALSE; + } + } + + if(m->isStatic) { + m->data.statID = theMethod; + } else { + m->data.dynamic.name = JCL_malloc(env, strlen(name) + 1); + if(m->data.dynamic.name == NULL) { + free(m); + return NULL; + } + + strcpy(m->data.dynamic.name, name); + + m->data.dynamic.sig = JCL_malloc(env, strlen(sig) + 1); + if(m->data.dynamic.sig == NULL) { + free(m->data.dynamic.name); + free(m->data.dynamic.sig); + return NULL; + } + + strcpy(m->data.dynamic.sig, sig); + } +} + +/* Do we need to re-resolve fields based on objects? I don't think so, but I could be wrong ... */ +JNIEXPORT linkPtr JNICALL LINK_LinkField (JNIEnv * env, jclass clazz, char * name, char * sig) { + return (linkPtr)(*env)->GetFieldID(env, clazz, name, sig); +} + +JNIEXPORT linkPtr JNICALL LINK_LinkClass (JNIEnv * env, char * name) { + jclass c = (*env)->FindClass(env, name); + if((*env)->ExceptionOccurred(env)) { + return NULL; + } + return (linkPtr)(*env)->NewGlobalRef(env, c); +} + + +/* The GetXXX functions can be inlined. */ +/* Note: GetMethod does actual resolution of the method based on the object type. + * The object in question *must* be of the correct type. No type checking is done. + * If the object is NULL, then the jmethodID will be NULL as well, and no exception + * will be thrown. If the method is not found, a MethodNotFoundException will be + * thrown. + */ +JNIEXPORT jmethodID JNICALL LINK_GetMethod (JNIEnv * env, linkPtr methodLink, jobject obj) { + jniMethodInfo * m; + jclass objClass; + + m = (jniMethodInfo *)methodLink; + if(m->isStatic) { + return m->data.statID; + } else { + if(obj == NULL) { + JCL_ThrowException(env, "java/lang/NullPointerException", "Attempt to access non-static method with null object in LINK_GetMethod"); + return NULL; + } + objClass = (*env)->GetObjectClass(env, obj); + return (*env)->GetMethodID(env, objClass, m->data.dynamic.name, m->data.dynamic.sig); + } +} + +JNIEXPORT jfieldID JNICALL LINK_GetField (JNIEnv * env, linkPtr fieldLink) { + return (jfieldID)fieldLink; +} + +JNIEXPORT jclass JNICALL LINK_GetClass (JNIEnv * env, linkPtr classLink) { + return (jclass)classLink; +} + + +/* These are for when the class referencing the symbols is unloaded; it +destroys any object references + * the linker might have kept around. + */ +JNIEXPORT void JNICALL LINK_UnlinkMethod (JNIEnv * env, linkPtr methodLink) { + jniMethodInfo * m = (jniMethodInfo *)methodLink; + if(m != NULL) { + if(!m->isStatic) { + if(m->data.dynamic.name != NULL) free(m->data.dynamic.name); + if(m->data.dynamic.sig != NULL) free(m->data.dynamic.sig); + } + free(m); + } +} + +JNIEXPORT void JNICALL LINK_UnlinkField (JNIEnv * env, linkPtr fieldLink) { + return; +} + +JNIEXPORT void JNICALL LINK_UnlinkClass (JNIEnv * env, linkPtr classLink) { + if(classLink != NULL) + (*env)->DeleteGlobalRef(env, (jclass)classLink); +} diff --git a/native/lib/jnilink.h b/native/lib/jnilink.h new file mode 100755 index 000000000..4d55da15e --- /dev/null +++ b/native/lib/jnilink.h @@ -0,0 +1,35 @@ +#ifndef __JNILINK_H__ +#define __JNILINK_H__ + +#include <jni.h> + +typedef void* linkPtr; + +/* These functions are called to get the link pointers. */ +/* One possible optimization for Japhar would be to store the slot number of the method in the linkPtr. + * Another, which works for JNI too, is to see if the class or method is final and simply store the jmethodID. + * For JNI, the linkPtr must point to a struct containing the name and sig so that it can be re-resolved for + * every object. + */ +JNIEXPORT linkPtr JNICALL LINK_LinkMethod (JNIEnv * env, jclass class, char * name, char * sig); +/* Do we need to re-resolve fields based on objects? I don't think so, but I could be wrong ... */ +JNIEXPORT linkPtr JNICALL LINK_LinkField (JNIEnv * env, jclass class, char * name, char * sig); +JNIEXPORT linkPtr JNICALL LINK_LinkClass (JNIEnv * env, char * name); + +/* The GetXXX functions can be inlined. */ +/* Note: GetMethod does actual resolution of the method based on the object type. + * The object in question *must* be of the correct type. No type checking is done. + */ +JNIEXPORT jmethodID JNICALL LINK_GetMethod (JNIEnv * env, linkPtr methodLink, jobject obj); +JNIEXPORT jfieldID JNICALL LINK_GetField (JNIEnv * env, linkPtr fieldLink); +JNIEXPORT jclass JNICALL LINK_GetClass (JNIEnv * env, linkPtr classLink); + +/* These are for when the class referencing the symbols is unloaded; it +destroys any object references + * the linker might have kept around. + */ +JNIEXPORT void JNICALL LINK_UnlinkMethod (JNIEnv * env, linkPtr methodLink); +JNIEXPORT void JNICALL LINK_UnlinkField (JNIEnv * env, linkPtr fieldLink); +JNIEXPORT void JNICALL LINK_UnlinkClass (JNIEnv * env, linkPtr classLink); + +#endif diff --git a/native/lib/primlib.c b/native/lib/primlib.c new file mode 100755 index 000000000..50feb9ae4 --- /dev/null +++ b/native/lib/primlib.c @@ -0,0 +1,497 @@ +#include <primlib.h> +#include <jcl.h> + +static jclass nativeWrapClass[PRIMLIB_NUMTYPES] = {NULL,NULL,NULL, NULL,NULL,NULL, + NULL,NULL,NULL, NULL,NULL,NULL}; + +static jclass nativeTypeClass[PRIMLIB_NUMTYPES] = {NULL,NULL,NULL, NULL,NULL,NULL, + NULL,NULL,NULL, NULL,NULL,NULL}; + +static jmethodID nativeWrapClassConstructor[PRIMLIB_NUMTYPES] = {NULL,NULL,NULL, NULL,NULL,NULL, + NULL,NULL,NULL, NULL,NULL,NULL}; + +static jmethodID nativeWrapClassAccessor[PRIMLIB_NUMTYPES] = {NULL,NULL,NULL, NULL,NULL,NULL, + NULL,NULL,NULL, NULL,NULL,NULL}; + +static char * nativeWrapClassName[PRIMLIB_NUMTYPES] = { + NULL, + NULL, + "java/lang/Boolean", + "java/lang/Byte", + "java/lang/Character", + "java/lang/Short", + "java/lang/Integer", + "java/lang/Long", + "java/lang/Float", + "java/lang/Double", + "java/lang/Void", + NULL + }; + +static char * nativeWrapClassConstructorSig[PRIMLIB_NUMTYPES] = { + NULL, + NULL, + "(Z)V", + "(B)V", + "(C)V", + "(S)V", + "(I)V", + "(J)V", + "(F)V", + "(D)V", + "()V", + NULL + }; + +static char * nativeWrapClassAccessorName[PRIMLIB_NUMTYPES] = { + NULL, + NULL, + "booleanValue", + "byteValue", + "charValue", + "shortValue", + "intValue", + "longValue", + "floatValue", + "doubleValue", + NULL, + NULL +}; + +static char * nativeWrapClassAccessorSig[PRIMLIB_NUMTYPES] = { + NULL, + NULL, + "()Z", + "()B", + "()C", + "()S", + "()I", + "()J", + "()F", + "()D", + NULL, + NULL +}; + + +JNIEXPORT jclass JNICALL PRIMLIB_GetNativeWrapClass(JNIEnv * env, int reflectType) { + jclass retval = nativeWrapClass[reflectType]; + if(retval == NULL) { + switch(reflectType) { + case PRIMLIB_BOOLEAN: + case PRIMLIB_BYTE: + case PRIMLIB_CHAR: + case PRIMLIB_SHORT: + case PRIMLIB_INT: + case PRIMLIB_LONG: + case PRIMLIB_FLOAT: + case PRIMLIB_DOUBLE: + case PRIMLIB_VOID: + return nativeWrapClass[reflectType] = (jclass)(*env)->NewGlobalRef(env, (*env)->FindClass(env, nativeWrapClassName[reflectType])); + case PRIMLIB_UNKNOWN: + case PRIMLIB_OBJECT: + case PRIMLIB_NULL: + default: + return NULL; + } + } else { + return retval; + } +} + +JNIEXPORT jclass JNICALL PRIMLIB_GetNativeTypeClass(JNIEnv * env, int reflectType) { + jclass retval = nativeTypeClass[reflectType]; + jfieldID typeField; + jclass wrapClass; + + if(retval == NULL) { + wrapClass = PRIMLIB_GetNativeWrapClass(env, reflectType); + if((*env)->ExceptionOccurred(env)) { + return NULL; + } + typeField = (*env)->GetFieldID(env, wrapClass, "TYPE", "Ljava/lang/Class"); + if((*env)->ExceptionOccurred(env)) { + return NULL; + } + switch(reflectType) { + case PRIMLIB_BOOLEAN: + case PRIMLIB_BYTE: + case PRIMLIB_CHAR: + case PRIMLIB_SHORT: + case PRIMLIB_INT: + case PRIMLIB_LONG: + case PRIMLIB_FLOAT: + case PRIMLIB_DOUBLE: + case PRIMLIB_VOID: + return nativeTypeClass[reflectType] = (jclass)(*env)->NewGlobalRef(env, (jclass)(*env)->GetStaticObjectField(env, wrapClass, typeField)); + case PRIMLIB_UNKNOWN: + case PRIMLIB_OBJECT: + case PRIMLIB_NULL: + default: + return NULL; + } + } else { + return retval; + } +} + +JNIEXPORT jmethodID JNICALL PRIMLIB_GetNativeWrapClassConstructor(JNIEnv * env, int reflectType) { + jmethodID retval = nativeWrapClassConstructor[reflectType]; + if(retval == NULL) { + switch(reflectType) { + case PRIMLIB_BOOLEAN: + case PRIMLIB_BYTE: + case PRIMLIB_CHAR: + case PRIMLIB_SHORT: + case PRIMLIB_INT: + case PRIMLIB_LONG: + case PRIMLIB_FLOAT: + case PRIMLIB_DOUBLE: + case PRIMLIB_VOID: + return nativeWrapClassConstructor[reflectType] = (*env)->GetMethodID(env, PRIMLIB_GetNativeWrapClass(env,reflectType), "<init>", nativeWrapClassConstructorSig[reflectType]); + case PRIMLIB_UNKNOWN: + case PRIMLIB_OBJECT: + case PRIMLIB_NULL: + default: + return NULL; + } + } else { + return retval; + } +} + +JNIEXPORT jmethodID JNICALL PRIMLIB_GetNativeWrapClassAccessor(JNIEnv * env, int reflectType) { + jmethodID retval = nativeWrapClassAccessor[reflectType]; + if(retval == NULL) { + switch(reflectType) { + case PRIMLIB_BOOLEAN: + case PRIMLIB_BYTE: + case PRIMLIB_CHAR: + case PRIMLIB_SHORT: + case PRIMLIB_INT: + case PRIMLIB_LONG: + case PRIMLIB_FLOAT: + case PRIMLIB_DOUBLE: + return nativeWrapClassAccessor[reflectType] = (*env)->GetMethodID(env, PRIMLIB_GetNativeWrapClass(env,reflectType), nativeWrapClassAccessorName[reflectType], nativeWrapClassAccessorSig[reflectType]); + case PRIMLIB_VOID: + case PRIMLIB_UNKNOWN: + case PRIMLIB_OBJECT: + case PRIMLIB_NULL: + default: + return NULL; + } + } else { + return retval; + } +} + + + +JNIEXPORT jobject JNICALL PRIMLIB_WrapBoolean(JNIEnv * env, jboolean b) { + jmethodID construct = PRIMLIB_GetNativeWrapClassConstructor(env, PRIMLIB_BOOLEAN); + JCL_RETHROW_EXCEPTION(env); + return (*env)->NewObject(env, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_BOOLEAN), construct, b); +} + +JNIEXPORT jobject JNICALL PRIMLIB_WrapByte (JNIEnv * env, jbyte b) { + jmethodID construct = PRIMLIB_GetNativeWrapClassConstructor(env, PRIMLIB_BYTE); + JCL_RETHROW_EXCEPTION(env); + return (*env)->NewObject(env, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_BYTE), construct, b); +} + +JNIEXPORT jobject JNICALL PRIMLIB_WrapChar (JNIEnv * env, jchar c) { + jmethodID construct = PRIMLIB_GetNativeWrapClassConstructor(env, PRIMLIB_CHAR); + JCL_RETHROW_EXCEPTION(env); + return (*env)->NewObject(env, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_CHAR), construct, c); +} + +JNIEXPORT jobject JNICALL PRIMLIB_WrapShort (JNIEnv * env, jshort s) { + jmethodID construct = PRIMLIB_GetNativeWrapClassConstructor(env, PRIMLIB_SHORT); + JCL_RETHROW_EXCEPTION(env); + return (*env)->NewObject(env, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_SHORT), construct, s); +} + +JNIEXPORT jobject JNICALL PRIMLIB_WrapInt (JNIEnv * env, jint i) { + jmethodID construct = PRIMLIB_GetNativeWrapClassConstructor(env, PRIMLIB_INT); + JCL_RETHROW_EXCEPTION(env); + return (*env)->NewObject(env, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_INT), construct, i); +} + +JNIEXPORT jobject JNICALL PRIMLIB_WrapLong (JNIEnv * env, jlong l) { + jmethodID construct = PRIMLIB_GetNativeWrapClassConstructor(env, PRIMLIB_LONG); + JCL_RETHROW_EXCEPTION(env); + return (*env)->NewObject(env, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_LONG), construct, l); +} + +JNIEXPORT jobject JNICALL PRIMLIB_WrapFloat (JNIEnv * env, jfloat f) { + jmethodID construct = PRIMLIB_GetNativeWrapClassConstructor(env, PRIMLIB_FLOAT); + JCL_RETHROW_EXCEPTION(env); + return (*env)->NewObject(env, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_FLOAT), construct, f); +} + +JNIEXPORT jobject JNICALL PRIMLIB_WrapDouble (JNIEnv * env, jdouble d) { + jmethodID construct = PRIMLIB_GetNativeWrapClassConstructor(env, PRIMLIB_DOUBLE); + JCL_RETHROW_EXCEPTION(env); + return (*env)->NewObject(env, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_DOUBLE), construct, d); +} + + +JNIEXPORT jboolean JNICALL PRIMLIB_UnwrapBoolean(JNIEnv * env, jobject obj) { + if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_BOOLEAN))) { + return PRIMLIB_GetBooleanObjectValue(env, obj); + } else { + JCL_ThrowException(env, "java/lang/IllegalArgumentException", "Argument not of correct type."); + } +} + +JNIEXPORT jbyte JNICALL PRIMLIB_UnwrapByte(JNIEnv * env, jobject obj) { + if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_BYTE))) { + return PRIMLIB_GetByteObjectValue(env, obj); + } else { + JCL_ThrowException(env, "java/lang/IllegalArgumentException", "Argument not of correct type."); + } +} + +JNIEXPORT jshort JNICALL PRIMLIB_UnwrapShort(JNIEnv * env, jobject obj) { + if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_SHORT))) { + return PRIMLIB_GetShortObjectValue(env, obj); + } else if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_BYTE))) { + return (jshort)PRIMLIB_GetByteObjectValue(env, obj); + } else { + JCL_ThrowException(env, "java/lang/IllegalArgumentException", "Argument not of correct type."); + } +} + +JNIEXPORT jchar JNICALL PRIMLIB_UnwrapChar(JNIEnv * env, jobject obj) { + if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_CHAR))) { + return PRIMLIB_GetCharObjectValue(env, obj); + } else { + JCL_ThrowException(env, "java/lang/IllegalArgumentException", "Argument not of correct type."); + } +} + +JNIEXPORT jint JNICALL PRIMLIB_UnwrapInt(JNIEnv * env, jobject obj) { + if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_INT))) { + return PRIMLIB_GetIntObjectValue(env, obj); + } else if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_SHORT))) { + return (jint)PRIMLIB_GetShortObjectValue(env, obj); + } else if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_CHAR))) { + return (jint)PRIMLIB_GetCharObjectValue(env, obj); + } else if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_BYTE))) { + return (jint)PRIMLIB_GetByteObjectValue(env, obj); + } else { + JCL_ThrowException(env, "java/lang/IllegalArgumentException", "Argument not of correct type."); + } +} + +JNIEXPORT jlong JNICALL PRIMLIB_UnwrapLong(JNIEnv * env, jobject obj) { + if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_LONG))) { + return PRIMLIB_GetLongObjectValue(env, obj); + } else if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_INT))) { + return (jlong)PRIMLIB_GetIntObjectValue(env, obj); + } else if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_SHORT))) { + return (jlong)PRIMLIB_GetShortObjectValue(env, obj); + } else if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_CHAR))) { + return (jlong)PRIMLIB_GetCharObjectValue(env, obj); + } else if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_BYTE))) { + return (jlong)PRIMLIB_GetByteObjectValue(env, obj); + } else { + JCL_ThrowException(env, "java/lang/IllegalArgumentException", "Argument not of correct type."); + } +} + +JNIEXPORT jfloat JNICALL PRIMLIB_UnwrapFloat(JNIEnv * env, jobject obj) { + if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_FLOAT))) { + return PRIMLIB_GetFloatObjectValue(env, obj); + } else if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_LONG))) { + return (jfloat)PRIMLIB_GetLongObjectValue(env, obj); + } else if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_INT))) { + return (jfloat)PRIMLIB_GetIntObjectValue(env, obj); + } else if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_SHORT))) { + return (jfloat)PRIMLIB_GetShortObjectValue(env, obj); + } else if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_CHAR))) { + return (jfloat)PRIMLIB_GetCharObjectValue(env, obj); + } else if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_BYTE))) { + return (jfloat)PRIMLIB_GetByteObjectValue(env, obj); + } else { + JCL_ThrowException(env, "java/lang/IllegalArgumentException", "Argument not of correct type."); + } +} + +JNIEXPORT jdouble JNICALL PRIMLIB_UnwrapDouble(JNIEnv * env, jobject obj) { + if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_DOUBLE))) { + return PRIMLIB_GetDoubleObjectValue(env, obj); + } else if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_FLOAT))) { + return (jdouble)PRIMLIB_GetFloatObjectValue(env, obj); + } else if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_LONG))) { + return (jdouble)PRIMLIB_GetLongObjectValue(env, obj); + } else if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_INT))) { + return (jdouble)PRIMLIB_GetIntObjectValue(env, obj); + } else if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_SHORT))) { + return (jdouble)PRIMLIB_GetShortObjectValue(env, obj); + } else if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_CHAR))) { + return (jdouble)PRIMLIB_GetCharObjectValue(env, obj); + } else if((*env)->IsInstanceOf(env, obj, PRIMLIB_GetNativeWrapClass(env, PRIMLIB_BYTE))) { + return (jdouble)PRIMLIB_GetByteObjectValue(env, obj); + } else { + JCL_ThrowException(env, "java/lang/IllegalArgumentException", "Argument not of correct type."); + } +} + +JNIEXPORT jint JNICALL PRIMLIB_GetReflectiveWrapperType(JNIEnv * env, jobject obj) { + jclass typeClass; + if(obj == NULL) { + return PRIMLIB_NULL; + } + + typeClass = PRIMLIB_GetNativeWrapClass(env, PRIMLIB_DOUBLE); + if((*env)->IsInstanceOf(env, obj, typeClass)) { + return PRIMLIB_DOUBLE; + } + typeClass = PRIMLIB_GetNativeWrapClass(env, PRIMLIB_FLOAT); + if((*env)->IsInstanceOf(env, obj, typeClass)) { + return PRIMLIB_FLOAT; + } + typeClass = PRIMLIB_GetNativeWrapClass(env, PRIMLIB_LONG); + if((*env)->IsInstanceOf(env, obj, typeClass)) { + return PRIMLIB_LONG; + } + typeClass = PRIMLIB_GetNativeWrapClass(env, PRIMLIB_INT); + if((*env)->IsInstanceOf(env, obj, typeClass)) { + return PRIMLIB_INT; + } + typeClass = PRIMLIB_GetNativeWrapClass(env, PRIMLIB_CHAR); + if((*env)->IsInstanceOf(env, obj, typeClass)) { + return PRIMLIB_CHAR; + } + typeClass = PRIMLIB_GetNativeWrapClass(env, PRIMLIB_SHORT); + if((*env)->IsInstanceOf(env, obj, typeClass)) { + return PRIMLIB_SHORT; + } + typeClass = PRIMLIB_GetNativeWrapClass(env, PRIMLIB_BYTE); + if((*env)->IsInstanceOf(env, obj, typeClass)) { + return PRIMLIB_BYTE; + } + typeClass = PRIMLIB_GetNativeWrapClass(env, PRIMLIB_BOOLEAN); + if((*env)->IsInstanceOf(env, obj, typeClass)) { + return PRIMLIB_BOOLEAN; + } + typeClass = PRIMLIB_GetNativeWrapClass(env, PRIMLIB_VOID); + if((*env)->IsInstanceOf(env, obj, typeClass)) { + return PRIMLIB_VOID; + } + return PRIMLIB_OBJECT; +} + +JNIEXPORT jint JNICALL PRIMLIB_GetReflectiveType(JNIEnv * env, jclass returnType) { + jclass typeClass = PRIMLIB_GetNativeTypeClass(env, PRIMLIB_DOUBLE); + if((*env)->IsAssignableFrom(env, returnType, typeClass)) { + return PRIMLIB_DOUBLE; + } + typeClass = PRIMLIB_GetNativeTypeClass(env, PRIMLIB_FLOAT); + if((*env)->IsAssignableFrom(env, returnType, typeClass)) { + return PRIMLIB_FLOAT; + } + typeClass = PRIMLIB_GetNativeTypeClass(env, PRIMLIB_LONG); + if((*env)->IsAssignableFrom(env, returnType, typeClass)) { + return PRIMLIB_LONG; + } + typeClass = PRIMLIB_GetNativeTypeClass(env, PRIMLIB_INT); + if((*env)->IsAssignableFrom(env, returnType, typeClass)) { + return PRIMLIB_INT; + } + typeClass = PRIMLIB_GetNativeTypeClass(env, PRIMLIB_CHAR); + if((*env)->IsAssignableFrom(env, returnType, typeClass)) { + return PRIMLIB_CHAR; + } + typeClass = PRIMLIB_GetNativeTypeClass(env, PRIMLIB_SHORT); + if((*env)->IsAssignableFrom(env, returnType, typeClass)) { + return PRIMLIB_SHORT; + } + typeClass = PRIMLIB_GetNativeTypeClass(env, PRIMLIB_BYTE); + if((*env)->IsAssignableFrom(env, returnType, typeClass)) { + return PRIMLIB_BYTE; + } + typeClass = PRIMLIB_GetNativeTypeClass(env, PRIMLIB_BOOLEAN); + if((*env)->IsAssignableFrom(env, returnType, typeClass)) { + return PRIMLIB_BOOLEAN; + } + typeClass = PRIMLIB_GetNativeTypeClass(env, PRIMLIB_VOID); + if((*env)->IsAssignableFrom(env, returnType, typeClass)) { + return PRIMLIB_VOID; + } + return PRIMLIB_OBJECT; +} + + +JNIEXPORT jboolean JNICALL PRIMLIB_GetBooleanObjectValue(JNIEnv * env, jobject obj) { + jmethodID acc = PRIMLIB_GetNativeWrapClassAccessor(env, PRIMLIB_BOOLEAN); + return (*env)->CallBooleanMethod(env, obj, acc); +} + +JNIEXPORT jbyte JNICALL PRIMLIB_GetByteObjectValue(JNIEnv * env, jobject obj) { + jmethodID acc = PRIMLIB_GetNativeWrapClassAccessor(env, PRIMLIB_BYTE); + return (*env)->CallByteMethod(env, obj, acc); +} + +JNIEXPORT jshort JNICALL PRIMLIB_GetShortObjectValue(JNIEnv * env, jobject obj) { + jmethodID acc = PRIMLIB_GetNativeWrapClassAccessor(env, PRIMLIB_SHORT); + return (*env)->CallShortMethod(env, obj, acc); +} + +JNIEXPORT jchar JNICALL PRIMLIB_GetCharObjectValue(JNIEnv * env, jobject obj) { + jmethodID acc = PRIMLIB_GetNativeWrapClassAccessor(env, PRIMLIB_CHAR); + return (*env)->CallCharMethod(env, obj, acc); +} + +JNIEXPORT jint JNICALL PRIMLIB_GetIntObjectValue(JNIEnv * env, jobject obj) { + jmethodID acc = PRIMLIB_GetNativeWrapClassAccessor(env, PRIMLIB_INT); + return (*env)->CallIntMethod(env, obj, acc); +} + +JNIEXPORT jlong JNICALL PRIMLIB_GetLongObjectValue(JNIEnv * env, jobject obj) { + jmethodID acc = PRIMLIB_GetNativeWrapClassAccessor(env, PRIMLIB_LONG); + return (*env)->CallLongMethod(env, obj, acc); +} + +JNIEXPORT jfloat JNICALL PRIMLIB_GetFloatObjectValue(JNIEnv * env, jobject obj) { + jmethodID acc = PRIMLIB_GetNativeWrapClassAccessor(env, PRIMLIB_FLOAT); + return (*env)->CallFloatMethod(env, obj, acc); +} + +JNIEXPORT jdouble JNICALL PRIMLIB_GetDoubleObjectValue(JNIEnv * env, jobject obj) { + jmethodID acc = PRIMLIB_GetNativeWrapClassAccessor(env, PRIMLIB_DOUBLE); + return (*env)->CallDoubleMethod(env, obj, acc); +} + + + +JNIEXPORT jvalue JNICALL PRIMLIB_UnwrapJValue(JNIEnv* env, jobject obj, jclass classType) { + jvalue retval; + jint objType = PRIMLIB_GetReflectiveType(env, classType); + if(objType == PRIMLIB_BOOLEAN) { + retval.z = PRIMLIB_UnwrapBoolean(env,obj); + } else if(objType == PRIMLIB_BYTE) { + retval.b = PRIMLIB_UnwrapByte(env,obj); + } else if(objType == PRIMLIB_CHAR) { + retval.c = PRIMLIB_UnwrapChar(env,obj); + } else if(objType == PRIMLIB_SHORT) { + retval.s = PRIMLIB_UnwrapShort(env,obj); + } else if(objType == PRIMLIB_INT) { + retval.i = PRIMLIB_UnwrapInt(env,obj); + } else if(objType == PRIMLIB_LONG) { + retval.j = PRIMLIB_UnwrapLong(env,obj); + } else if(objType == PRIMLIB_FLOAT) { + retval.f = PRIMLIB_UnwrapFloat(env,obj); + } else if(objType == PRIMLIB_DOUBLE) { + retval.d = PRIMLIB_UnwrapDouble(env,obj); + } else { + if(obj != NULL && !(*env)->IsInstanceOf(env, obj, classType)) { + JCL_ThrowException(env, "java/lang/IllegalArgumentException", "Argument not of correct object type."); + return retval; + } + retval.l = obj; + } + return retval; +} + diff --git a/native/lib/primlib.h b/native/lib/primlib.h new file mode 100644 index 000000000..1c1e3dbe4 --- /dev/null +++ b/native/lib/primlib.h @@ -0,0 +1,65 @@ +#ifndef __PRIMLIB_H__ +#define __PRIMLIB_H__ + +#include <jni.h> + +#define PRIMLIB_UNKNOWN 0 +#define PRIMLIB_OBJECT 1 +#define PRIMLIB_BOOLEAN 2 +#define PRIMLIB_BYTE 3 +#define PRIMLIB_CHAR 4 +#define PRIMLIB_SHORT 5 +#define PRIMLIB_INT 6 +#define PRIMLIB_LONG 7 +#define PRIMLIB_FLOAT 8 +#define PRIMLIB_DOUBLE 9 +#define PRIMLIB_VOID 10 +#define PRIMLIB_NULL 11 +#define PRIMLIB_NUMTYPES 12 + +/* Low-level primitive class accessor functions. */ +JNIEXPORT jclass JNICALL PRIMLIB_GetNativeWrapClass(JNIEnv * env, int reflectType); +JNIEXPORT jclass JNICALL PRIMLIB_GetNativeTypeClass(JNIEnv * env, int reflectType); +JNIEXPORT jmethodID JNICALL PRIMLIB_GetNativeWrapClassConstructor(JNIEnv * env, int reflectType); +JNIEXPORT jmethodID JNICALL PRIMLIB_GetNativeWrapClassAccessor(JNIEnv * env, int reflectType); + +/* Type discovery functions: WrapperType finds out j.l.Boolean/Byte/etc., and + Type finds out j.l.Boolean.TYPE, etc. +*/ +JNIEXPORT jint JNICALL PRIMLIB_GetReflectiveWrapperType(JNIEnv * env, jobject obj); +JNIEXPORT jint JNICALL PRIMLIB_GetReflectiveType(JNIEnv * env, jclass returnType); + +/* Constructor functions. */ +JNIEXPORT jobject JNICALL PRIMLIB_WrapBoolean(JNIEnv * env, jboolean b); +JNIEXPORT jobject JNICALL PRIMLIB_WrapByte (JNIEnv * env, jbyte b); +JNIEXPORT jobject JNICALL PRIMLIB_WrapChar (JNIEnv * env, jchar c); +JNIEXPORT jobject JNICALL PRIMLIB_WrapShort (JNIEnv * env, jshort s); +JNIEXPORT jobject JNICALL PRIMLIB_WrapInt (JNIEnv * env, jint i); +JNIEXPORT jobject JNICALL PRIMLIB_WrapLong (JNIEnv * env, jlong l); +JNIEXPORT jobject JNICALL PRIMLIB_WrapFloat (JNIEnv * env, jfloat f); +JNIEXPORT jobject JNICALL PRIMLIB_WrapDouble (JNIEnv * env, jdouble d); + +/* Widening conversion unwrapping functions. */ +JNIEXPORT jboolean JNICALL PRIMLIB_UnwrapBoolean(JNIEnv * env, jobject obj); +JNIEXPORT jbyte JNICALL PRIMLIB_UnwrapByte (JNIEnv * env, jobject obj); +JNIEXPORT jshort JNICALL PRIMLIB_UnwrapShort (JNIEnv * env, jobject obj); +JNIEXPORT jchar JNICALL PRIMLIB_UnwrapChar (JNIEnv * env, jobject obj); +JNIEXPORT jint JNICALL PRIMLIB_UnwrapInt (JNIEnv * env, jobject obj); +JNIEXPORT jlong JNICALL PRIMLIB_UnwrapLong (JNIEnv * env, jobject obj); +JNIEXPORT jfloat JNICALL PRIMLIB_UnwrapFloat (JNIEnv * env, jobject obj); +JNIEXPORT jdouble JNICALL PRIMLIB_UnwrapDouble (JNIEnv * env, jobject obj); + +/* Simple unwrapping functions. Objects *must* be of correct type. */ +JNIEXPORT jboolean JNICALL PRIMLIB_GetBooleanObjectValue(JNIEnv * env, jobject obj); +JNIEXPORT jbyte JNICALL PRIMLIB_GetByteObjectValue (JNIEnv * env, jobject obj); +JNIEXPORT jshort JNICALL PRIMLIB_GetShortObjectValue (JNIEnv * env, jobject obj); +JNIEXPORT jchar JNICALL PRIMLIB_GetCharObjectValue (JNIEnv * env, jobject obj); +JNIEXPORT jint JNICALL PRIMLIB_GetIntObjectValue (JNIEnv * env, jobject obj); +JNIEXPORT jlong JNICALL PRIMLIB_GetLongObjectValue (JNIEnv * env, jobject obj); +JNIEXPORT jfloat JNICALL PRIMLIB_GetFloatObjectValue (JNIEnv * env, jobject obj); +JNIEXPORT jdouble JNICALL PRIMLIB_GetDoubleObjectValue (JNIEnv * env, jobject obj); + +/* jvalue conversion: Unwrap obj to the type of classType, with widening conversion. */ +JNIEXPORT jvalue JNICALL PRIMLIB_UnwrapJValue(JNIEnv* env, jobject obj, jclass classType); + +#endif diff --git a/native/vmi/DEPENDENCIES b/native/vmi/DEPENDENCIES new file mode 100755 index 000000000..a4c3d51b8 --- /dev/null +++ b/native/vmi/DEPENDENCIES @@ -0,0 +1,14 @@ +DEPENDENCIES for JCL VMI library: + +Japhar 1.1: +- Most functions depend on Japhar JVMDI. +- However, JNI and JCL functions are called by some of the + non-JVMDI functions. +- Additionally: + - VMI_GetFrameObject() depends on the StackFrame + structure in Japhar's interp.h. + - VMI_GetThisFrame() and VMI_GetThisThreadObject() depend + on the JThreadInfo structure and the + THREAD_getJavaInfo() function in Japhar's + native-threads.h. + diff --git a/native/vmi/README b/native/vmi/README new file mode 100755 index 000000000..4f5d1a9a2 --- /dev/null +++ b/native/vmi/README @@ -0,0 +1,9 @@ +README for JCL VMI library: + +20 June 1998: John Keiser +Initial Revision + +This is the catchall library that does all the VM-specific +interface stuff. It needs to be implemented on a per-VM +basis. Currently the only JVM supported is Japhar. + diff --git a/native/vmi/STATUS b/native/vmi/STATUS new file mode 100755 index 000000000..97365ca80 --- /dev/null +++ b/native/vmi/STATUS @@ -0,0 +1,3 @@ +STATUS for JCL VMI library: + +Japhar 1.1: all current VMI functions implemented. Compiled, untested. diff --git a/native/vmi/TODO b/native/vmi/TODO new file mode 100644 index 000000000..8107ad444 --- /dev/null +++ b/native/vmi/TODO @@ -0,0 +1,28 @@ +TODO for JCL VMI library: + +API: +- More functions will almost certainly be required. I am + adding them in only as needs arise to keep the job as + easy as possible in the short term. The full JVMDI + will presumably need to be mimicked. + +Japhar 1.1: +- Using the JVMDI for many functions, since Japhar + implements JVMDI. Several JVMDI functions are not + implemented yet, though, so it becomes a question of + waiting til they are or implementing them ourselves. +- Specifically, the JVMDI functions not yet implemented in + Japhar that the VMI calls are: + - JVMDI_GetClassModifiers() + - JVMDI_GetClassName() + - JVMDI_GetClassMethods() + - JVMDI_GetClassFields() + - JVMDI_GetImplementedInterfaces() + - JVMDI_IsInterface() + - JVMDI_IsArray() + - JVMDI_ClassLoader() + - JVMDI_GetMethodModifiers() + - JVMDI_GetThrownExceptions() + - JVMDI_GetFieldName() + - JVMDI_GetFieldDeclaringClass() + - JVMDI_GetFieldModifiers() diff --git a/native/vmi/vmi.c b/native/vmi/vmi.c new file mode 100755 index 000000000..75d5bd5de --- /dev/null +++ b/native/vmi/vmi.c @@ -0,0 +1,206 @@ +/* Japhar implementation of VMI. */ + +#include <jcl.h> +#include <vmi.h> +#include <jvmdi.h> +#include <interp.h> +#include <native-threads.h> + +JNIEXPORT vmiError JNICALL +VMI_GetFrameObject(JNIEnv *env, + jframeID frame, + jobject *obj) { + StackFrame *sframe = (StackFrame*)frame; + if(env == NULL || obj == NULL) + return VMI_ERROR_NULL_POINTER; + if(frame == NULL) + return VMI_ERROR_INVALID_FRAMEID; + + *obj = THISPTR(sframe); + return VMI_ERROR_NONE; +} + +JNIEXPORT vmiError JNICALL +VMI_GetThisFrame(JNIEnv *env, jframeID *frame) { + JThreadInfo *thread_info; + + if(env == NULL || frame == NULL) + return VMI_ERROR_NULL_POINTER; + + thread_info = THREAD_getJavaInfo(); + *frame = (jframeID)TOPFRAME(thread_info); + return VMI_ERROR_NONE; +} + +JNIEXPORT vmiError JNICALL +VMI_GetThisThreadObject(JNIEnv* env, jthread *thread) { + JThreadInfo *thread_info; + if(env == NULL || thread == NULL) + return VMI_ERROR_NULL_POINTER; + thread_info = THREAD_getJavaInfo(); + *thread = (jthread)thread_info->java_thread; + return VMI_ERROR_NONE; +} + +JNIEXPORT void JNICALL +VMI_ThrowAppropriateException(JNIEnv *env, vmiError err) { + switch(err) { + case VMI_ERROR_NONE: + JCL_ThrowException(env, "java/lang/InternalError", "ERROR_NONE passed to VMI exception thrower."); + break; + case VMI_ERROR_NULL_POINTER: + JCL_ThrowException(env, "java/lang/NullPointerException", "null pointer in VMI detected."); + break; + case VMI_ERROR_OUT_OF_MEMORY: + JCL_ThrowException(env, "java/lang/OutOfMemoryError", "Out of memory! (in VMI)."); + break; + case VMI_ERROR_INVALID_METHODID: + JCL_ThrowException(env, "java/lang/InternalError", "VMI error: INVALID_METHODID"); + break; + case VMI_ERROR_INVALID_CLASS: + JCL_ThrowException(env, "java/lang/InternalError", "VMI error: INVALID_CLASS"); + break; + case VMI_ERROR_INVALID_BCI: + JCL_ThrowException(env, "java/lang/InternalError", "VMI error: INVALID_BCI"); + break; + case VMI_ERROR_NO_SUCH_BREAKPOINT: + JCL_ThrowException(env, "java/lang/InternalError", "VMI error: NO_SUCH_BREAKPOINT"); + break; + case VMI_ERROR_VM_DEAD: + JCL_ThrowException(env, "java/lang/InternalError", "VMI error: VM Dead! Kinda makes ya wonder how this exception got thrown, huh?"); + break; + case VMI_ERROR_INVALID_FRAMEID: + JCL_ThrowException(env, "java/lang/IllegalThreadStateException", "NULL Frame ID detected in VMI."); + break; + case VMI_ERROR_INVALID_SLOT: + JCL_ThrowException(env, "java/lang/InternalError", "VMI error: INVALID_SLOT"); + break; + case VMI_ERROR_TYPE_MISMATCH: + JCL_ThrowException(env, "java/lang/InternalError", "VMI error: INVALID_SLOT"); + break; + case VMI_ERROR_NATIVE_FRAME: + JCL_ThrowException(env, "java/lang/InternalError", "VMI error: NATIVE_FRAME"); + break; + case VMI_ERROR_NO_MORE_FRAMES: + JCL_ThrowException(env, "java/lang/InternalError", "VMI error: NO_MORE_FRAMES"); + break; + case VMI_ERROR_INVALID_THREAD: + JCL_ThrowException(env, "java/lang/IllegalThreadStateException", "Invalid thread in VMI."); + break; + case VMI_ERROR_THREAD_NOT_SUSPENDED: + JCL_ThrowException(env, "java/lang/IllegalThreadStateException", "Attempt to introspect unsuspended thread in VMI."); + break; + default: + JCL_ThrowException(env, "java/lang/UnknownError", "VMI returned erroneous error value ..."); + break; + } +} + + +/* 1.2 placeholders: can be implemented for Japhar using JNI */ + +/* Thread / Frame Stuff */ + +JNIEXPORT vmiError JNICALL +VMI_GetCallerFrame(JNIEnv *env, jframeID called, jframeID *framePtr) { + return JVMDI_GetCallerFrame(env, called, framePtr); +} + + +/* Class Introspection */ + +JNIEXPORT vmiError JNICALL +VMI_GetClassModifiers(JNIEnv *env, jclass clazz, jint *modifiers) { + return JVMDI_GetClassModifiers(env, clazz, modifiers); +} + +JNIEXPORT vmiError JNICALL +VMI_GetClassName(JNIEnv *env, jclass clazz, jstring *namePtr) { + return JVMDI_GetClassName(env, clazz, namePtr); +} + +JNIEXPORT vmiError JNICALL +VMI_GetClassMethods(JNIEnv *env, jclass clazz, + jint *methodCountPtr, jmethodID **methodsPtr) { + return JVMDI_GetClassMethods(env, clazz, methodCountPtr, methodsPtr); +} + +JNIEXPORT vmiError JNICALL +VMI_GetClassFields(JNIEnv *env, jclass clazz, + jint *fieldCountPtr, jfieldID **fieldsPtr) { + return JVMDI_GetClassFields(env, clazz, fieldCountPtr, fieldsPtr); +} + +JNIEXPORT vmiError JNICALL +VMI_GetImplementedInterfaces(JNIEnv *env, jclass clazz, + jint *interfaceCountPtr, + jclass **interfacesPtr) { + return JVMDI_GetImplementedInterfaces(env, clazz, interfaceCountPtr, interfacesPtr); +} + +JNIEXPORT vmiError JNICALL +VMI_IsInterface(JNIEnv *env, jclass clazz, jboolean *isInterfacePtr) { + return JVMDI_IsInterface(env, clazz, isInterfacePtr); +} + +JNIEXPORT vmiError JNICALL +VMI_IsArray(JNIEnv *env, jclass clazz, jboolean *isArrayPtr) { + return JVMDI_IsArray(env, clazz, isArrayPtr); +} + +JNIEXPORT vmiError JNICALL +VMI_ClassLoader(JNIEnv *env, jclass clazz, jobject *classloaderPtr) { + return JVMDI_ClassLoader(env, clazz, classloaderPtr); +} + +/* Method Introspection */ + +JNIEXPORT vmiError JNICALL +VMI_GetMethodModifiers(JNIEnv *env, jmethodID m, jint *modifiers) { + return JVMDI_GetMethodModifiers(env, m, modifiers); +} + +JNIEXPORT vmiError JNICALL +VMI_GetMethodName(JNIEnv *env, jclass clazz, jmethodID method, + jstring *namePtr, jstring *signaturePtr) { + return JVMDI_GetMethodName(env, clazz, method, namePtr, signaturePtr); +} + +JNIEXPORT vmiError JNICALL +VMI_GetMethodDefiningClass(JNIEnv *env, jclass clazz, jmethodID method, + jclass *definingClassPtr) { + return JVMDI_GetMethodDefiningClass(env, clazz, method, definingClassPtr); +} + +/* Field Introspection */ + +JNIEXPORT vmiError JNICALL +VMI_GetFieldName(JNIEnv *env, jclass clazz, jfieldID field, + char **namePtr, char **signaturePtr) { + return JVMDI_GetFieldName(env, clazz, field, namePtr, signaturePtr); +} + +JNIEXPORT vmiError JNICALL +VMI_GetFieldDeclaringClass(JNIEnv *env, jclass clazz, jfieldID field, + jclass *declaringClassPtr) { + return JVMDI_GetFieldDeclaringClass(env, clazz, field, declaringClassPtr); +} + +JNIEXPORT vmiError JNICALL +VMI_GetFieldModifiers(JNIEnv *env, jclass clazz, jfieldID field, + jint *modifiersPtr) { + return JVMDI_GetFieldModifiers(env, clazz, field, modifiersPtr); +} + +JNIEXPORT vmiError JNICALL +VMI_GetThrownExceptions(JNIEnv *env, jclass clazz, jmethodID method, + jint *exceptionCountPtr, jclass **exceptionsPtr) { + return JVMDI_GetThrownExceptions(env, clazz, method, exceptionCountPtr, exceptionsPtr); +} + +JNIEXPORT vmiError JNICALL +VMI_IsMethodNative(JNIEnv *env, jclass clazz, jmethodID method, + jboolean *isNativePtr) { + return JVMDI_IsMethodNative(env, clazz, method, isNativePtr); +} + diff --git a/native/vmi/vmi.h b/native/vmi/vmi.h new file mode 100755 index 000000000..70f343fa1 --- /dev/null +++ b/native/vmi/vmi.h @@ -0,0 +1,129 @@ +#ifndef __VMI_H__ +#define __VMI_H__ + +#include <jni.h> + +typedef void * jframeID; +typedef void * jthread; + +typedef enum { + VMI_ERROR_NONE, + VMI_ERROR_NULL_POINTER, + VMI_ERROR_OUT_OF_MEMORY, + VMI_ERROR_INVALID_METHODID, + VMI_ERROR_INVALID_CLASS, + VMI_ERROR_INVALID_BCI, + VMI_ERROR_NO_SUCH_BREAKPOINT, + VMI_ERROR_VM_DEAD, + VMI_ERROR_INVALID_FRAMEID, + VMI_ERROR_INVALID_SLOT, + VMI_ERROR_TYPE_MISMATCH, + VMI_ERROR_NATIVE_FRAME, + VMI_ERROR_NO_MORE_FRAMES, + VMI_ERROR_INVALID_THREAD, + VMI_ERROR_THREAD_NOT_SUSPENDED +} vmiError; + + +#define VMI_MOD_PUBLIC 0x0001 +#define VMI_MOD_PRIVATE 0x0002 +#define VMI_MOD_PROTECTED 0x0004 +#define VMI_MOD_STATIC 0x0008 +#define VMI_MOD_FINAL 0x0010 +#define VMI_MOD_SYNCHRONIZED 0x0020 +#define VMI_MOD_VOLATILE 0x0040 +#define VMI_MOD_TRANSIENT 0x0080 +#define VMI_MOD_NATIVE 0x0100 +#define VMI_MOD_INTERFACE 0x0200 +#define VMI_MOD_ABSTRACT 0x0400 + + +JNIEXPORT vmiError JNICALL +VMI_GetFrameObject(JNIEnv *env, jframeID frame, jobject *obj); + +JNIEXPORT vmiError JNICALL +VMI_GetThisFrame(JNIEnv *env, jframeID *frame); + +JNIEXPORT vmiError JNICALL +VMI_GetThisThreadObject(JNIEnv *env, jthread *thread); + +JNIEXPORT void JNICALL +VMI_ThrowAppropriateException(JNIEnv *env, vmiError err); + + +/* + * 1.2 placeholders: stuff that will be in JVMDI but has to be in VMI for now. + */ + +/* Thread / Frame Stuff */ + +JNIEXPORT vmiError JNICALL +VMI_GetCallerFrame(JNIEnv *env, jframeID called, jframeID *framePtr); + + +/* Class Introspection */ + +JNIEXPORT vmiError JNICALL +VMI_GetClassModifiers(JNIEnv *env, jclass clazz, jint *modifiers); + +JNIEXPORT vmiError JNICALL +VMI_GetClassName(JNIEnv *env, jclass clazz, jstring *namePtr); + +JNIEXPORT vmiError JNICALL +VMI_GetClassMethods(JNIEnv *env, jclass clazz, + jint *methodCountPtr, jmethodID **methodsPtr); + +JNIEXPORT vmiError JNICALL +VMI_GetClassFields(JNIEnv *env, jclass clazz, + jint *fieldCountPtr, jfieldID **fieldsPtr); + +JNIEXPORT vmiError JNICALL +VMI_GetImplementedInterfaces(JNIEnv *env, jclass clazz, + jint *interfaceCountPtr, + jclass **interfacesPtr); + +JNIEXPORT vmiError JNICALL +VMI_IsInterface(JNIEnv *env, jclass clazz, jboolean *isInterfacePtr); + +JNIEXPORT vmiError JNICALL +VMI_IsArray(JNIEnv *env, jclass clazz, jboolean *isArrayPtr); + +JNIEXPORT vmiError JNICALL +VMI_ClassLoader(JNIEnv *env, jclass clazz, jobject *classloaderPtr); + +/* Method Introspection */ + +JNIEXPORT vmiError JNICALL +VMI_GetMethodModifiers(JNIEnv *env, jmethodID m, jint *modifiers); + +JNIEXPORT vmiError JNICALL +VMI_GetMethodName(JNIEnv *env, jclass clazz, jmethodID method, + jstring *namePtr, jstring *signaturePtr); + +JNIEXPORT vmiError JNICALL +VMI_GetMethodDefiningClass(JNIEnv *env, jclass clazz, jmethodID method, + jclass *definingClassPtr); + +/* Field Introspection */ + +JNIEXPORT vmiError JNICALL +VMI_GetFieldName(JNIEnv *env, jclass clazz, jfieldID field, + char **namePtr, char **signaturePtr); + +JNIEXPORT vmiError JNICALL +VMI_GetFieldDeclaringClass(JNIEnv *env, jclass clazz, jfieldID field, + jclass *declaringClassPtr); + +JNIEXPORT vmiError JNICALL +VMI_GetFieldModifiers(JNIEnv *env, jclass clazz, jfieldID field, + jint *modifiersPtr); + +JNIEXPORT vmiError JNICALL +VMI_GetThrownExceptions(JNIEnv *env, jclass clazz, jmethodID method, + jint *exceptionCountPtr, jclass **exceptionsPtr); + +JNIEXPORT vmiError JNICALL +VMI_IsMethodNative(JNIEnv *env, jclass clazz, jmethodID method, + jboolean *isNativePtr); + +#endif |