diff --git a/classpath/allsources.lst b/classpath/allsources.lst index a1839332..6505b9e4 100644 --- a/classpath/allsources.lst +++ b/classpath/allsources.lst @@ -3129,6 +3129,7 @@ gnu/classpath/Configuration.java gnu/classpath/RawData.java gnu/classpath/VMStackWalker.java gnu/classpath/VMSystemProperties.java +gnu/java/lang/reflect/VMField.java gnu/java/net/PlainDatagramSocketImpl.java gnu/java/net/PlainSocketImpl.java gnu/java/net/protocol/ikvmres/Handler.java @@ -3142,6 +3143,7 @@ java/lang/ref/Reference.java java/lang/reflect/Constructor.java java/lang/reflect/Field.java java/lang/reflect/Method.java +java/lang/reflect/VMFieldImpl.java java/lang/StringHelper.java java/lang/VMClass.java java/lang/VMClassLoader.java diff --git a/classpath/gnu/java/lang/reflect/VMField.java b/classpath/gnu/java/lang/reflect/VMField.java new file mode 100644 index 00000000..b8b3f5b8 --- /dev/null +++ b/classpath/gnu/java/lang/reflect/VMField.java @@ -0,0 +1,75 @@ +/* + Copyright (C) 2005 Jeroen Frijters + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jeroen Frijters + jeroen@frijters.net + +*/ +package gnu.java.lang.reflect; + +import java.lang.reflect.Field; + +public abstract class VMField +{ + // fieldCookie must be package accessible (actually "assembly") to allow map.xml + // implementation of LibraryVMInterfaceImpl.getWrapperFromField() to access it. + protected Object fieldCookie; + protected Class declaringClass; + protected boolean isPublic; + protected int modifiers; + + public final boolean needsAccessCheck(boolean accessible) + { + return !accessible & !isPublic; + } + + public final Class getDeclaringClass() + { + return declaringClass; + } + + public final int getModifiers() + { + return modifiers; + } + + public abstract Field newField(); + public abstract void checkAccess(Object o, Class caller) throws IllegalAccessException; + public abstract String getName(); + public abstract Class getType(); + + public abstract Object get(Object obj); + public abstract boolean getBoolean(Object obj); + public abstract byte getByte(Object obj); + public abstract char getChar(Object obj); + public abstract short getShort(Object obj); + public abstract int getInt(Object obj); + public abstract float getFloat(Object obj); + public abstract long getLong(Object obj); + public abstract double getDouble(Object obj); + public abstract void set(Object obj, Object val, boolean accessible) throws IllegalAccessException; + public abstract void setBoolean(Object obj, boolean val, boolean accessible) throws IllegalAccessException; + public abstract void setByte(Object obj, byte val, boolean accessible) throws IllegalAccessException; + public abstract void setChar(Object obj, char val, boolean accessible) throws IllegalAccessException; + public abstract void setShort(Object obj, short val, boolean accessible) throws IllegalAccessException; + public abstract void setInt(Object obj, int val, boolean accessible) throws IllegalAccessException; + public abstract void setFloat(Object obj, float val, boolean accessible) throws IllegalAccessException; + public abstract void setLong(Object obj, long val, boolean accessible) throws IllegalAccessException; + public abstract void setDouble(Object obj, double val, boolean accessible) throws IllegalAccessException; +} diff --git a/classpath/java/lang/reflect/Constructor.java b/classpath/java/lang/reflect/Constructor.java index ab306648..128dde61 100644 --- a/classpath/java/lang/reflect/Constructor.java +++ b/classpath/java/lang/reflect/Constructor.java @@ -260,7 +260,7 @@ public final class Constructor InvocationTargetException { if(!isAccessible() && (!Modifier.isPublic(modifiers) || !classIsPublic)) - Field.checkAccess(modifiers, null, declaringClass, VMStackWalker.getCallingClass()); + VMFieldImpl.checkAccess(modifiers, null, declaringClass, VMStackWalker.getCallingClass()); int mods = declaringClass.getModifiers() | Method.GetRealModifiers(declaringClass); if(Modifier.isAbstract(mods) || Modifier.isInterface(mods)) { diff --git a/classpath/java/lang/reflect/Field.java b/classpath/java/lang/reflect/Field.java index 7da407a6..33624fb5 100644 --- a/classpath/java/lang/reflect/Field.java +++ b/classpath/java/lang/reflect/Field.java @@ -1,5 +1,5 @@ /* java.lang.reflect.Field - reflection of Java fields - Copyright (C) 1998, 2001 Free Software Foundation, Inc. + Copyright (C) 1998, 2001, 2005 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,9 +38,8 @@ exception statement from your version. */ package java.lang.reflect; -import cli.System.Diagnostics.StackFrame; import gnu.classpath.VMStackWalker; -import ikvm.lang.CIL; +import gnu.java.lang.reflect.VMField; /** * The Field class represents a member variable of a class. It also allows @@ -66,6 +65,7 @@ import ikvm.lang.CIL; * * @author John Keiser * @author Eric Blake + * @author Jeroen Frijters * @see Member * @see Class * @see Class#getField(String) @@ -77,612 +77,16 @@ import ikvm.lang.CIL; */ public final class Field extends AccessibleObject implements Member { - private Class declaringClass; - // package accessible (actually "assembly") to allow map.xml implementation - // of LibraryVMInterfaceImpl.getWrapperFromField() to access it. - Object fieldCookie; - private int modifiers; - private boolean classIsPublic; - private FieldImpl impl; - - private static native Object GetValue(Object fieldCookie, Object o); - private static native void SetValue(Object fieldCookie, Object o, Object value, boolean accessible); - - abstract static class FieldImpl - { - private Object fieldCookie; - - FieldImpl(Object fieldCookie) - { - this.fieldCookie = fieldCookie; - } - - final Object getImpl(Object obj) - { - return Field.GetValue(fieldCookie, obj); - } - - final void setImpl(Object obj, Object val, boolean accessible) - { - Field.SetValue(fieldCookie, obj, val, accessible); - } - - abstract Object get(Object obj); - - boolean getBoolean(Object obj) - { - throw new IllegalArgumentException(); - } - byte getByte(Object obj) - { - throw new IllegalArgumentException(); - } - char getChar(Object obj) - { - throw new IllegalArgumentException(); - } - short getShort(Object obj) - { - throw new IllegalArgumentException(); - } - int getInt(Object obj) - { - throw new IllegalArgumentException(); - } - float getFloat(Object obj) - { - throw new IllegalArgumentException(); - } - long getLong(Object obj) - { - throw new IllegalArgumentException(); - } - double getDouble(Object obj) - { - throw new IllegalArgumentException(); - } - - abstract void set(Object obj, Object val, boolean accessible); - - void setBoolean(Object obj, boolean val, boolean accessible) - { - throw new IllegalArgumentException(); - } - void setByte(Object obj, byte val, boolean accessible) - { - throw new IllegalArgumentException(); - } - void setChar(Object obj, char val, boolean accessible) - { - throw new IllegalArgumentException(); - } - void setShort(Object obj, short val, boolean accessible) - { - throw new IllegalArgumentException(); - } - void setInt(Object obj, int val, boolean accessible) - { - throw new IllegalArgumentException(); - } - void setFloat(Object obj, float val, boolean accessible) - { - throw new IllegalArgumentException(); - } - void setLong(Object obj, long val, boolean accessible) - { - throw new IllegalArgumentException(); - } - void setDouble(Object obj, double val, boolean accessible) - { - throw new IllegalArgumentException(); - } - } - - final static class ObjectFieldImpl extends FieldImpl - { - ObjectFieldImpl(Object fieldCookie) - { - super(fieldCookie); - } - - Object get(Object obj) - { - return getImpl(obj); - } - - void set(Object obj, Object val, boolean accessible) - { - setImpl(obj, val, accessible); - } - } - - final static class BooleanFieldImpl extends FieldImpl - { - BooleanFieldImpl(Object fieldCookie) - { - super(fieldCookie); - } - - Object get(Object obj) - { - return getBoolean(obj) ? Boolean.TRUE : Boolean.FALSE; - } - - boolean getBoolean(Object obj) - { - return CIL.unbox_boolean(getImpl(obj)); - } - - void set(Object obj, Object val, boolean accessible) - { - if(! (val instanceof Boolean)) - throw new IllegalArgumentException(); - setBoolean(obj, ((Boolean)val).booleanValue(), accessible); - } - - void setBoolean(Object obj, boolean val, boolean accessible) - { - setImpl(obj, CIL.box_boolean(val), accessible); - } - } - - final static class ByteFieldImpl extends FieldImpl - { - ByteFieldImpl(Object fieldCookie) - { - super(fieldCookie); - } - - Object get(Object obj) - { - return new Byte(getByte(obj)); - } - - byte getByte(Object obj) - { - return CIL.unbox_byte(getImpl(obj)); - } - - short getShort(Object obj) - { - return getByte(obj); - } - - int getInt(Object obj) - { - return getByte(obj); - } - - float getFloat(Object obj) - { - return getByte(obj); - } - - long getLong(Object obj) - { - return getByte(obj); - } - - double getDouble(Object obj) - { - return getByte(obj); - } - - void set(Object obj, Object val, boolean accessible) - { - if(! (val instanceof Byte)) - throw new IllegalArgumentException(); - setByte(obj, ((Byte)val).byteValue(), accessible); - } - - void setByte(Object obj, byte val, boolean accessible) - { - setImpl(obj, CIL.box_byte(val), accessible); - } - } - - final static class CharFieldImpl extends FieldImpl - { - CharFieldImpl(Object fieldCookie) - { - super(fieldCookie); - } - - Object get(Object obj) - { - return new Character(getChar(obj)); - } - - char getChar(Object obj) - { - return CIL.unbox_char(getImpl(obj)); - } - - int getInt(Object obj) - { - return getChar(obj); - } - - float getFloat(Object obj) - { - return getChar(obj); - } - - long getLong(Object obj) - { - return getChar(obj); - } - - double getDouble(Object obj) - { - return getChar(obj); - } - - void set(Object obj, Object val, boolean accessible) - { - if(! (val instanceof Character)) - throw new IllegalArgumentException(); - setChar(obj, ((Character)val).charValue(), accessible); - } - - void setChar(Object obj, char val, boolean accessible) - { - setImpl(obj, CIL.box_char(val), accessible); - } - } - - final static class ShortFieldImpl extends FieldImpl - { - ShortFieldImpl(Object fieldCookie) - { - super(fieldCookie); - } - - Object get(Object obj) - { - return new Short(getShort(obj)); - } - - short getShort(Object obj) - { - return CIL.unbox_short(getImpl(obj)); - } - - int getInt(Object obj) - { - return getShort(obj); - } - - float getFloat(Object obj) - { - return getShort(obj); - } - - long getLong(Object obj) - { - return getShort(obj); - } - - double getDouble(Object obj) - { - return getShort(obj); - } - - void set(Object obj, Object val, boolean accessible) - { - if(! (val instanceof Short - || val instanceof Byte)) - throw new IllegalArgumentException(); - setShort(obj, ((Number)val).shortValue(), accessible); - } - - void setShort(Object obj, short val, boolean accessible) - { - setImpl(obj, CIL.box_short(val), accessible); - } - - void setByte(Object obj, byte val, boolean accessible) - { - setShort(obj, val, accessible); - } - } - - final static class IntFieldImpl extends FieldImpl - { - IntFieldImpl(Object fieldCookie) - { - super(fieldCookie); - } - - Object get(Object obj) - { - return new Integer(getInt(obj)); - } - - int getInt(Object obj) - { - return CIL.unbox_int(getImpl(obj)); - } - - float getFloat(Object obj) - { - return getInt(obj); - } - - long getLong(Object obj) - { - return getInt(obj); - } - - double getDouble(Object obj) - { - return getInt(obj); - } - - void set(Object obj, Object val, boolean accessible) - { - if (val instanceof Integer - || val instanceof Byte - || val instanceof Short) - setInt(obj, ((Number)val).intValue(), accessible); - else if (val instanceof Character) - setInt(obj, ((Character)val).charValue(), accessible); - else - throw new IllegalArgumentException(); - } - - void setInt(Object obj, int val, boolean accessible) - { - setImpl(obj, CIL.box_int(val), accessible); - } - - void setByte(Object obj, byte val, boolean accessible) - { - setInt(obj, val, accessible); - } - - void setChar(Object obj, char val, boolean accessible) - { - setInt(obj, val, accessible); - } - - void setShort(Object obj, short val, boolean accessible) - { - setInt(obj, val, accessible); - } - } - - final static class FloatFieldImpl extends FieldImpl - { - FloatFieldImpl(Object fieldCookie) - { - super(fieldCookie); - } - - Object get(Object obj) - { - return new Float(getFloat(obj)); - } - - float getFloat(Object obj) - { - return CIL.unbox_float(getImpl(obj)); - } - - double getDouble(Object obj) - { - return getFloat(obj); - } - - void set(Object obj, Object val, boolean accessible) - { - if (val instanceof Float - || val instanceof Byte - || val instanceof Short - || val instanceof Integer - || val instanceof Long) - setFloat(obj, ((Number)val).floatValue(), accessible); - else if (val instanceof Character) - setFloat(obj, ((Character)val).charValue(), accessible); - else - throw new IllegalArgumentException(); - } - - void setFloat(Object obj, float val, boolean accessible) - { - setImpl(obj, CIL.box_float(val), accessible); - } - - void setByte(Object obj, byte val, boolean accessible) - { - setFloat(obj, val, accessible); - } - - void setChar(Object obj, char val, boolean accessible) - { - setFloat(obj, val, accessible); - } - - void setShort(Object obj, short val, boolean accessible) - { - setFloat(obj, val, accessible); - } - - void setInt(Object obj, int val, boolean accessible) - { - setFloat(obj, val, accessible); - } - - void setLong(Object obj, long val, boolean accessible) - { - setFloat(obj, val, accessible); - } - } - - final static class LongFieldImpl extends FieldImpl - { - LongFieldImpl(Object fieldCookie) - { - super(fieldCookie); - } - - Object get(Object obj) - { - return new Long(getLong(obj)); - } - - long getLong(Object obj) - { - return CIL.unbox_long(getImpl(obj)); - } - - float getFloat(Object obj) - { - return getLong(obj); - } - - double getDouble(Object obj) - { - return getLong(obj); - } - - void set(Object obj, Object val, boolean accessible) - { - if (val instanceof Long - || val instanceof Byte - || val instanceof Short - || val instanceof Integer) - setLong(obj, ((Number)val).longValue(), accessible); - else if (val instanceof Character) - setLong(obj, ((Character)val).charValue(), accessible); - else - throw new IllegalArgumentException(); - } - - void setLong(Object obj, long val, boolean accessible) - { - setImpl(obj, CIL.box_long(val), accessible); - } - - void setByte(Object obj, byte val, boolean accessible) - { - setLong(obj, val, accessible); - } - - void setChar(Object obj, char val, boolean accessible) - { - setLong(obj, val, accessible); - } - - void setShort(Object obj, short val, boolean accessible) - { - setLong(obj, val, accessible); - } - - void setInt(Object obj, int val, boolean accessible) - { - setLong(obj, val, accessible); - } - } - - final static class DoubleFieldImpl extends FieldImpl - { - DoubleFieldImpl(Object fieldCookie) - { - super(fieldCookie); - } - - Object get(Object obj) - { - return new Double(getDouble(obj)); - } - - double getDouble(Object obj) - { - return CIL.unbox_double(getImpl(obj)); - } - - void set(Object obj, Object val, boolean accessible) - { - if (val instanceof Double - || val instanceof Byte - || val instanceof Short - || val instanceof Integer - || val instanceof Float - || val instanceof Long) - setDouble(obj, ((Number)val).doubleValue(), accessible); - else if (val instanceof Character) - setDouble(obj, ((Character)val).charValue(), accessible); - else - throw new IllegalArgumentException(); - } - - void setDouble(Object obj, double val, boolean accessible) - { - setImpl(obj, CIL.box_double(val), accessible); - } - - void setByte(Object obj, byte val, boolean accessible) - { - setDouble(obj, val, accessible); - } - - void setChar(Object obj, char val, boolean accessible) - { - setDouble(obj, val, accessible); - } - - void setShort(Object obj, short val, boolean accessible) - { - setDouble(obj, val, accessible); - } - - void setInt(Object obj, int val, boolean accessible) - { - setDouble(obj, val, accessible); - } - - void setFloat(Object obj, float val, boolean accessible) - { - setDouble(obj, val, accessible); - } - - void setLong(Object obj, long val, boolean accessible) - { - setDouble(obj, val, accessible); - } - } + // package accessible to allow VM to access it + VMField impl; /** * This class is uninstantiable except natively. */ - Field(Class declaringClass, Object fieldCookie) + Field(VMField impl) { - this.declaringClass = declaringClass; - this.fieldCookie = fieldCookie; - modifiers = GetModifiers(fieldCookie); - classIsPublic = (Method.GetRealModifiers(declaringClass) & Modifier.PUBLIC) != 0; - Class type = getType(); - if (type == Boolean.TYPE) - impl = new BooleanFieldImpl(fieldCookie); - else if (type == Byte.TYPE) - impl = new ByteFieldImpl(fieldCookie); - else if (type == Character.TYPE) - impl = new CharFieldImpl(fieldCookie); - else if (type == Short.TYPE) - impl = new ShortFieldImpl(fieldCookie); - else if (type == Integer.TYPE) - impl = new IntFieldImpl(fieldCookie); - else if (type == Float.TYPE) - impl = new FloatFieldImpl(fieldCookie); - else if (type == Long.TYPE) - impl = new LongFieldImpl(fieldCookie); - else if (type == Double.TYPE) - impl = new DoubleFieldImpl(fieldCookie); - else - impl = new ObjectFieldImpl(fieldCookie); + this.impl = impl; } - private static native int GetModifiers(Object fieldCookie); /** * Gets the class that declared this field, or the class where this field @@ -691,7 +95,7 @@ public final class Field extends AccessibleObject implements Member */ public Class getDeclaringClass() { - return declaringClass; + return impl.getDeclaringClass(); } /** @@ -700,10 +104,8 @@ public final class Field extends AccessibleObject implements Member */ public String getName() { - return GetName(fieldCookie); + return impl.getName(); } - private static native String GetName(Object fieldCookie); - /** * Gets the modifiers this field uses. Use the Modifier @@ -716,7 +118,7 @@ public final class Field extends AccessibleObject implements Member */ public int getModifiers() { - return modifiers; + return impl.getModifiers(); } /** @@ -725,9 +127,8 @@ public final class Field extends AccessibleObject implements Member */ public Class getType() { - return (Class)GetFieldType(fieldCookie); + return impl.getType(); } - private static native Object GetFieldType(Object fieldCookie); /** * Compare two objects to see if they are semantically equivalent. @@ -746,7 +147,7 @@ public final class Field extends AccessibleObject implements Member if(!getName().equals(f.getName())) return false; - if(declaringClass != f.declaringClass) + if(getDeclaringClass() != f.getDeclaringClass()) return false; if(getType() != f.getType()) @@ -827,10 +228,8 @@ public final class Field extends AccessibleObject implements Member public Object get(Object o) throws IllegalAccessException { - if(!isAccessible() && (!Modifier.isPublic(modifiers) || !classIsPublic)) - checkAccess(modifiers, o, declaringClass, VMStackWalker.getCallingClass()); - if(o != null && !declaringClass.isInstance(o)) - throw new IllegalArgumentException(); + if(impl.needsAccessCheck(isAccessible())) + impl.checkAccess(o, VMStackWalker.getCallingClass()); return impl.get(o); } @@ -854,10 +253,8 @@ public final class Field extends AccessibleObject implements Member public boolean getBoolean(Object o) throws IllegalAccessException { - if(!isAccessible() && (!Modifier.isPublic(modifiers) || !classIsPublic)) - checkAccess(modifiers, o, declaringClass, VMStackWalker.getCallingClass()); - if(o != null && !declaringClass.isInstance(o)) - throw new IllegalArgumentException(); + if(impl.needsAccessCheck(isAccessible())) + impl.checkAccess(o, VMStackWalker.getCallingClass()); return impl.getBoolean(o); } @@ -881,10 +278,8 @@ public final class Field extends AccessibleObject implements Member public byte getByte(Object o) throws IllegalAccessException { - if(!isAccessible() && (!Modifier.isPublic(modifiers) || !classIsPublic)) - checkAccess(modifiers, o, declaringClass, VMStackWalker.getCallingClass()); - if(o != null && !declaringClass.isInstance(o)) - throw new IllegalArgumentException(); + if(impl.needsAccessCheck(isAccessible())) + impl.checkAccess(o, VMStackWalker.getCallingClass()); return impl.getByte(o); } @@ -906,10 +301,8 @@ public final class Field extends AccessibleObject implements Member public char getChar(Object o) throws IllegalAccessException { - if(!isAccessible() && (!Modifier.isPublic(modifiers) || !classIsPublic)) - checkAccess(modifiers, o, declaringClass, VMStackWalker.getCallingClass()); - if(o != null && !declaringClass.isInstance(o)) - throw new IllegalArgumentException(); + if(impl.needsAccessCheck(isAccessible())) + impl.checkAccess(o, VMStackWalker.getCallingClass()); return impl.getChar(o); } @@ -933,10 +326,8 @@ public final class Field extends AccessibleObject implements Member public short getShort(Object o) throws IllegalAccessException { - if(!isAccessible() && (!Modifier.isPublic(modifiers) || !classIsPublic)) - checkAccess(modifiers, o, declaringClass, VMStackWalker.getCallingClass()); - if(o != null && !declaringClass.isInstance(o)) - throw new IllegalArgumentException(); + if(impl.needsAccessCheck(isAccessible())) + impl.checkAccess(o, VMStackWalker.getCallingClass()); return impl.getShort(o); } @@ -960,10 +351,8 @@ public final class Field extends AccessibleObject implements Member public int getInt(Object o) throws IllegalAccessException { - if(!isAccessible() && (!Modifier.isPublic(modifiers) || !classIsPublic)) - checkAccess(modifiers, o, declaringClass, VMStackWalker.getCallingClass()); - if(o != null && !declaringClass.isInstance(o)) - throw new IllegalArgumentException(); + if(impl.needsAccessCheck(isAccessible())) + impl.checkAccess(o, VMStackWalker.getCallingClass()); return impl.getInt(o); } @@ -987,10 +376,8 @@ public final class Field extends AccessibleObject implements Member public long getLong(Object o) throws IllegalAccessException { - if(!isAccessible() && (!Modifier.isPublic(modifiers) || !classIsPublic)) - checkAccess(modifiers, o, declaringClass, VMStackWalker.getCallingClass()); - if(o != null && !declaringClass.isInstance(o)) - throw new IllegalArgumentException(); + if(impl.needsAccessCheck(isAccessible())) + impl.checkAccess(o, VMStackWalker.getCallingClass()); return impl.getLong(o); } @@ -1014,10 +401,8 @@ public final class Field extends AccessibleObject implements Member public float getFloat(Object o) throws IllegalAccessException { - if(!isAccessible() && (!Modifier.isPublic(modifiers) || !classIsPublic)) - checkAccess(modifiers, o, declaringClass, VMStackWalker.getCallingClass()); - if(o != null && !declaringClass.isInstance(o)) - throw new IllegalArgumentException(); + if(impl.needsAccessCheck(isAccessible())) + impl.checkAccess(o, VMStackWalker.getCallingClass()); return impl.getFloat(o); } @@ -1042,10 +427,8 @@ public final class Field extends AccessibleObject implements Member public double getDouble(Object o) throws IllegalAccessException { - if(!isAccessible() && (!Modifier.isPublic(modifiers) || !classIsPublic)) - checkAccess(modifiers, o, declaringClass, VMStackWalker.getCallingClass()); - if(o != null && !declaringClass.isInstance(o)) - throw new IllegalArgumentException(); + if(impl.needsAccessCheck(isAccessible())) + impl.checkAccess(o, VMStackWalker.getCallingClass()); return impl.getDouble(o); } @@ -1097,38 +480,11 @@ public final class Field extends AccessibleObject implements Member public void set(Object o, Object value) throws IllegalAccessException { - if(!isAccessible() && (!Modifier.isPublic(modifiers) || !classIsPublic)) - checkAccess(modifiers, o, declaringClass, VMStackWalker.getCallingClass()); - if(o != null && !declaringClass.isInstance(o)) - throw new IllegalArgumentException(); + if(impl.needsAccessCheck(isAccessible())) + impl.checkAccess(o, VMStackWalker.getCallingClass()); impl.set(o, value, isAccessible()); } - static void checkAccess(int modifiers, Object o, Class declaringClass, Class caller) throws IllegalAccessException - { - // when we're invoking a constructor, modifiers will not be static, but o will be null. - Class actualClass = Modifier.isStatic(modifiers) || o == null ? declaringClass : o.getClass(); - boolean declaringClassIsPublic = (Method.GetRealModifiers(declaringClass) & Modifier.PUBLIC) != 0; - if((!Modifier.isPublic(modifiers) || !declaringClassIsPublic) && declaringClass != caller) - { - // if the caller is a global method, the class returned will be null - if(caller == null) - { - throw new IllegalAccessException(); - } - if(Modifier.isProtected(modifiers) && actualClass.isAssignableFrom(caller)) - { - } - else if(!isSamePackage(declaringClass, caller) || Modifier.isPrivate(modifiers)) - { - throw new IllegalAccessException("Class " + caller.getName() + - " can not access a member of class " + declaringClass.getName() + - " with modifiers \"" + Modifier.toString(modifiers & (Modifier.PRIVATE | Modifier.PROTECTED)) + "\""); - } - } - } - private static native boolean isSamePackage(Class a, Class b); - /** * Set this boolean Field. If the field is static, o will be * ignored. @@ -1149,10 +505,8 @@ public final class Field extends AccessibleObject implements Member public void setBoolean(Object o, boolean value) throws IllegalAccessException { - if(!isAccessible() && (!Modifier.isPublic(modifiers) || !classIsPublic)) - checkAccess(modifiers, o, declaringClass, VMStackWalker.getCallingClass()); - if(o != null && !declaringClass.isInstance(o)) - throw new IllegalArgumentException(); + if(impl.needsAccessCheck(isAccessible())) + impl.checkAccess(o, VMStackWalker.getCallingClass()); impl.setBoolean(o, value, isAccessible()); } @@ -1176,10 +530,8 @@ public final class Field extends AccessibleObject implements Member public void setByte(Object o, byte value) throws IllegalAccessException { - if(!isAccessible() && (!Modifier.isPublic(modifiers) || !classIsPublic)) - checkAccess(modifiers, o, declaringClass, VMStackWalker.getCallingClass()); - if(o != null && !declaringClass.isInstance(o)) - throw new IllegalArgumentException(); + if(impl.needsAccessCheck(isAccessible())) + impl.checkAccess(o, VMStackWalker.getCallingClass()); impl.setByte(o, value, isAccessible()); } @@ -1203,10 +555,8 @@ public final class Field extends AccessibleObject implements Member public void setChar(Object o, char value) throws IllegalAccessException { - if(!isAccessible() && (!Modifier.isPublic(modifiers) || !classIsPublic)) - checkAccess(modifiers, o, declaringClass, VMStackWalker.getCallingClass()); - if(o != null && !declaringClass.isInstance(o)) - throw new IllegalArgumentException(); + if(impl.needsAccessCheck(isAccessible())) + impl.checkAccess(o, VMStackWalker.getCallingClass()); impl.setChar(o, value, isAccessible()); } @@ -1230,10 +580,8 @@ public final class Field extends AccessibleObject implements Member public void setShort(Object o, short value) throws IllegalAccessException { - if(!isAccessible() && (!Modifier.isPublic(modifiers) || !classIsPublic)) - checkAccess(modifiers, o, declaringClass, VMStackWalker.getCallingClass()); - if(o != null && !declaringClass.isInstance(o)) - throw new IllegalArgumentException(); + if(impl.needsAccessCheck(isAccessible())) + impl.checkAccess(o, VMStackWalker.getCallingClass()); impl.setShort(o, value, isAccessible()); } @@ -1257,10 +605,8 @@ public final class Field extends AccessibleObject implements Member public void setInt(Object o, int value) throws IllegalAccessException { - if(!isAccessible() && (!Modifier.isPublic(modifiers) || !classIsPublic)) - checkAccess(modifiers, o, declaringClass, VMStackWalker.getCallingClass()); - if(o != null && !declaringClass.isInstance(o)) - throw new IllegalArgumentException(); + if(impl.needsAccessCheck(isAccessible())) + impl.checkAccess(o, VMStackWalker.getCallingClass()); impl.setInt(o, value, isAccessible()); } @@ -1284,10 +630,8 @@ public final class Field extends AccessibleObject implements Member public void setLong(Object o, long value) throws IllegalAccessException { - if(!isAccessible() && (!Modifier.isPublic(modifiers) || !classIsPublic)) - checkAccess(modifiers, o, declaringClass, VMStackWalker.getCallingClass()); - if(o != null && !declaringClass.isInstance(o)) - throw new IllegalArgumentException(); + if(impl.needsAccessCheck(isAccessible())) + impl.checkAccess(o, VMStackWalker.getCallingClass()); impl.setLong(o, value, isAccessible()); } @@ -1311,10 +655,8 @@ public final class Field extends AccessibleObject implements Member public void setFloat(Object o, float value) throws IllegalAccessException { - if(!isAccessible() && (!Modifier.isPublic(modifiers) || !classIsPublic)) - checkAccess(modifiers, o, declaringClass, VMStackWalker.getCallingClass()); - if(o != null && !declaringClass.isInstance(o)) - throw new IllegalArgumentException(); + if(impl.needsAccessCheck(isAccessible())) + impl.checkAccess(o, VMStackWalker.getCallingClass()); impl.setFloat(o, value, isAccessible()); } @@ -1338,10 +680,8 @@ public final class Field extends AccessibleObject implements Member public void setDouble(Object o, double value) throws IllegalAccessException { - if(!isAccessible() && (!Modifier.isPublic(modifiers) || !classIsPublic)) - checkAccess(modifiers, o, declaringClass, VMStackWalker.getCallingClass()); - if(o != null && !declaringClass.isInstance(o)) - throw new IllegalArgumentException(); + if(impl.needsAccessCheck(isAccessible())) + impl.checkAccess(o, VMStackWalker.getCallingClass()); impl.setDouble(o, value, isAccessible()); } } diff --git a/classpath/java/lang/reflect/Method.java b/classpath/java/lang/reflect/Method.java index 09b8233d..aa0a496b 100644 --- a/classpath/java/lang/reflect/Method.java +++ b/classpath/java/lang/reflect/Method.java @@ -337,7 +337,7 @@ public final class Method extends AccessibleObject implements Member throws IllegalAccessException, InvocationTargetException { if(!isAccessible() && (!Modifier.isPublic(modifiers) || !classIsPublic)) - Field.checkAccess(modifiers, o, declaringClass, VMStackWalker.getCallingClass()); + VMFieldImpl.checkAccess(modifiers, o, declaringClass, VMStackWalker.getCallingClass()); if(!Modifier.isStatic(modifiers)) { if(o == null) diff --git a/classpath/java/lang/reflect/VMFieldImpl.java b/classpath/java/lang/reflect/VMFieldImpl.java new file mode 100644 index 00000000..005382b5 --- /dev/null +++ b/classpath/java/lang/reflect/VMFieldImpl.java @@ -0,0 +1,696 @@ +/* + Copyright (C) 2005 Jeroen Frijters + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jeroen Frijters + jeroen@frijters.net + +*/ +package java.lang.reflect; + +import cli.System.Diagnostics.StackFrame; +import gnu.java.lang.reflect.VMField; +import ikvm.lang.CIL; + +abstract class VMFieldImpl extends VMField +{ + private static native Object GetValue(Object fieldCookie, Object o); + private static native void SetValue(Object fieldCookie, Object o, Object value); + private static native int GetModifiers(Object fieldCookie); + private static native String GetName(Object fieldCookie); + private static native Object GetFieldType(Object fieldCookie); + private static native boolean isSamePackage(Class a, Class b); + private static native void RunClassInit(Class clazz); + + static void checkAccess(int modifiers, Object o, Class declaringClass, Class caller) throws IllegalAccessException + { + // when we're invoking a constructor, modifiers will not be static, but o will be null. + Class actualClass = Modifier.isStatic(modifiers) || o == null ? declaringClass : o.getClass(); + boolean declaringClassIsPublic = (Method.GetRealModifiers(declaringClass) & Modifier.PUBLIC) != 0; + if((!Modifier.isPublic(modifiers) || !declaringClassIsPublic) && declaringClass != caller) + { + // if the caller is a global method, the class returned will be null + if(caller == null) + { + throw new IllegalAccessException(); + } + if(Modifier.isProtected(modifiers) && actualClass.isAssignableFrom(caller)) + { + } + else if(!isSamePackage(declaringClass, caller) || Modifier.isPrivate(modifiers)) + { + throw new IllegalAccessException("Class " + caller.getName() + + " can not access a member of class " + declaringClass.getName() + + " with modifiers \"" + Modifier.toString(modifiers & (Modifier.PRIVATE | Modifier.PROTECTED)) + "\""); + } + } + } + + static Field newField(Class declaringClass, Object fieldCookie) + { + Class type = (Class)GetFieldType(fieldCookie); + if (type == Boolean.TYPE) + return new BooleanFieldImpl(declaringClass, fieldCookie).newField(); + else if (type == Byte.TYPE) + return new ByteFieldImpl(declaringClass, fieldCookie).newField(); + else if (type == Character.TYPE) + return new CharFieldImpl(declaringClass, fieldCookie).newField(); + else if (type == Short.TYPE) + return new ShortFieldImpl(declaringClass, fieldCookie).newField(); + else if (type == Integer.TYPE) + return new IntFieldImpl(declaringClass, fieldCookie).newField(); + else if (type == Float.TYPE) + return new FloatFieldImpl(declaringClass, fieldCookie).newField(); + else if (type == Long.TYPE) + return new LongFieldImpl(declaringClass, fieldCookie).newField(); + else if (type == Double.TYPE) + return new DoubleFieldImpl(declaringClass, fieldCookie).newField(); + else + return new ObjectFieldImpl(declaringClass, fieldCookie).newField(); + } + + VMFieldImpl(Class declaringClass, Object fieldCookie) + { + this.declaringClass = declaringClass; + this.fieldCookie = fieldCookie; + this.modifiers = GetModifiers(fieldCookie); + isPublic = Modifier.isPublic(modifiers) + && Modifier.isPublic(Method.GetRealModifiers(declaringClass)); + } + + public final Field newField() + { + return new Field(this); + } + + public final void checkAccess(Object o, Class caller) throws IllegalAccessException + { + checkAccess(modifiers, o, declaringClass, caller); + } + + public final String getName() + { + return GetName(fieldCookie); + } + + public final Class getType() + { + return (Class)GetFieldType(fieldCookie); + } + + final void checkObject(Object obj) + { + if(!Modifier.isStatic(modifiers)) + { + if(!declaringClass.isAssignableFrom(obj.getClass())) + { + throw new IllegalArgumentException(); + } + } + } + + final void checkWrite(boolean accessible) throws IllegalAccessException + { + if(Modifier.isFinal(modifiers)) + { + // Starting with JDK 1.5, it is legal to change final instance fields + // (see JSR-133), but they have to be made "accessible". + if(Modifier.isStatic(modifiers) || !accessible) + { + // even though the field access will fail with an IllegalAccessException, + // we run the for declaringClass for compatibility with the JDK. + RunClassInit(declaringClass); + throw new IllegalAccessException("Field is final"); + } + } + } + + final Object getImpl(Object obj) + { + checkObject(obj); + return GetValue(fieldCookie, obj); + } + + final void setImpl(Object obj, Object val, boolean accessible) throws IllegalAccessException + { + checkWrite(accessible); + checkObject(obj); + SetValue(fieldCookie, obj, val); + } + + public boolean getBoolean(Object obj) + { + throw new IllegalArgumentException(); + } + public byte getByte(Object obj) + { + throw new IllegalArgumentException(); + } + public char getChar(Object obj) + { + throw new IllegalArgumentException(); + } + public short getShort(Object obj) + { + throw new IllegalArgumentException(); + } + public int getInt(Object obj) + { + throw new IllegalArgumentException(); + } + public float getFloat(Object obj) + { + throw new IllegalArgumentException(); + } + public long getLong(Object obj) + { + throw new IllegalArgumentException(); + } + public double getDouble(Object obj) + { + throw new IllegalArgumentException(); + } + + public void setBoolean(Object obj, boolean val, boolean accessible) throws IllegalAccessException + { + throw new IllegalArgumentException(); + } + public void setByte(Object obj, byte val, boolean accessible) throws IllegalAccessException + { + throw new IllegalArgumentException(); + } + public void setChar(Object obj, char val, boolean accessible) throws IllegalAccessException + { + throw new IllegalArgumentException(); + } + public void setShort(Object obj, short val, boolean accessible) throws IllegalAccessException + { + throw new IllegalArgumentException(); + } + public void setInt(Object obj, int val, boolean accessible) throws IllegalAccessException + { + throw new IllegalArgumentException(); + } + public void setFloat(Object obj, float val, boolean accessible) throws IllegalAccessException + { + throw new IllegalArgumentException(); + } + public void setLong(Object obj, long val, boolean accessible) throws IllegalAccessException + { + throw new IllegalArgumentException(); + } + public void setDouble(Object obj, double val, boolean accessible) throws IllegalAccessException + { + throw new IllegalArgumentException(); + } +} + +final class ObjectFieldImpl extends VMFieldImpl +{ + ObjectFieldImpl(Class declaringClass, Object fieldCookie) + { + super(declaringClass, fieldCookie); + } + + public Object get(Object obj) + { + return getImpl(obj); + } + + public void set(Object obj, Object val, boolean accessible) throws IllegalAccessException + { + setImpl(obj, val, accessible); + } +} + +final class BooleanFieldImpl extends VMFieldImpl +{ + BooleanFieldImpl(Class declaringClass, Object fieldCookie) + { + super(declaringClass, fieldCookie); + } + + public Object get(Object obj) + { + return getBoolean(obj) ? Boolean.TRUE : Boolean.FALSE; + } + + public boolean getBoolean(Object obj) + { + return CIL.unbox_boolean(getImpl(obj)); + } + + public void set(Object obj, Object val, boolean accessible) throws IllegalAccessException + { + if(! (val instanceof Boolean)) + throw new IllegalArgumentException(); + setBoolean(obj, ((Boolean)val).booleanValue(), accessible); + } + + public void setBoolean(Object obj, boolean val, boolean accessible) throws IllegalAccessException + { + setImpl(obj, CIL.box_boolean(val), accessible); + } +} + +final class ByteFieldImpl extends VMFieldImpl +{ + ByteFieldImpl(Class declaringClass, Object fieldCookie) + { + super(declaringClass, fieldCookie); + } + + public Object get(Object obj) + { + return new Byte(getByte(obj)); + } + + public byte getByte(Object obj) + { + return CIL.unbox_byte(getImpl(obj)); + } + + public short getShort(Object obj) + { + return getByte(obj); + } + + public int getInt(Object obj) + { + return getByte(obj); + } + + public float getFloat(Object obj) + { + return getByte(obj); + } + + public long getLong(Object obj) + { + return getByte(obj); + } + + public double getDouble(Object obj) + { + return getByte(obj); + } + + public void set(Object obj, Object val, boolean accessible) throws IllegalAccessException + { + if(! (val instanceof Byte)) + throw new IllegalArgumentException(); + setByte(obj, ((Byte)val).byteValue(), accessible); + } + + public void setByte(Object obj, byte val, boolean accessible) throws IllegalAccessException + { + setImpl(obj, CIL.box_byte(val), accessible); + } +} + +final class CharFieldImpl extends VMFieldImpl +{ + CharFieldImpl(Class declaringClass, Object fieldCookie) + { + super(declaringClass, fieldCookie); + } + + public Object get(Object obj) + { + return new Character(getChar(obj)); + } + + public char getChar(Object obj) + { + return CIL.unbox_char(getImpl(obj)); + } + + public int getInt(Object obj) + { + return getChar(obj); + } + + public float getFloat(Object obj) + { + return getChar(obj); + } + + public long getLong(Object obj) + { + return getChar(obj); + } + + public double getDouble(Object obj) + { + return getChar(obj); + } + + public void set(Object obj, Object val, boolean accessible) throws IllegalAccessException + { + if(! (val instanceof Character)) + throw new IllegalArgumentException(); + setChar(obj, ((Character)val).charValue(), accessible); + } + + public void setChar(Object obj, char val, boolean accessible) throws IllegalAccessException + { + setImpl(obj, CIL.box_char(val), accessible); + } +} + +final class ShortFieldImpl extends VMFieldImpl +{ + ShortFieldImpl(Class declaringClass, Object fieldCookie) + { + super(declaringClass, fieldCookie); + } + + public Object get(Object obj) + { + return new Short(getShort(obj)); + } + + public short getShort(Object obj) + { + return CIL.unbox_short(getImpl(obj)); + } + + public int getInt(Object obj) + { + return getShort(obj); + } + + public float getFloat(Object obj) + { + return getShort(obj); + } + + public long getLong(Object obj) + { + return getShort(obj); + } + + public double getDouble(Object obj) + { + return getShort(obj); + } + + public void set(Object obj, Object val, boolean accessible) throws IllegalAccessException + { + if(! (val instanceof Short + || val instanceof Byte)) + throw new IllegalArgumentException(); + setShort(obj, ((Number)val).shortValue(), accessible); + } + + public void setShort(Object obj, short val, boolean accessible) throws IllegalAccessException + { + setImpl(obj, CIL.box_short(val), accessible); + } + + public void setByte(Object obj, byte val, boolean accessible) throws IllegalAccessException + { + setShort(obj, val, accessible); + } +} + +final class IntFieldImpl extends VMFieldImpl +{ + IntFieldImpl(Class declaringClass, Object fieldCookie) + { + super(declaringClass, fieldCookie); + } + + public Object get(Object obj) + { + return new Integer(getInt(obj)); + } + + public int getInt(Object obj) + { + return CIL.unbox_int(getImpl(obj)); + } + + public float getFloat(Object obj) + { + return getInt(obj); + } + + public long getLong(Object obj) + { + return getInt(obj); + } + + public double getDouble(Object obj) + { + return getInt(obj); + } + + public void set(Object obj, Object val, boolean accessible) throws IllegalAccessException + { + if (val instanceof Integer + || val instanceof Byte + || val instanceof Short) + setInt(obj, ((Number)val).intValue(), accessible); + else if (val instanceof Character) + setInt(obj, ((Character)val).charValue(), accessible); + else + throw new IllegalArgumentException(); + } + + public void setInt(Object obj, int val, boolean accessible) throws IllegalAccessException + { + setImpl(obj, CIL.box_int(val), accessible); + } + + public void setByte(Object obj, byte val, boolean accessible) throws IllegalAccessException + { + setInt(obj, val, accessible); + } + + public void setChar(Object obj, char val, boolean accessible) throws IllegalAccessException + { + setInt(obj, val, accessible); + } + + public void setShort(Object obj, short val, boolean accessible) throws IllegalAccessException + { + setInt(obj, val, accessible); + } +} + +final class FloatFieldImpl extends VMFieldImpl +{ + FloatFieldImpl(Class declaringClass, Object fieldCookie) + { + super(declaringClass, fieldCookie); + } + + public Object get(Object obj) + { + return new Float(getFloat(obj)); + } + + public float getFloat(Object obj) + { + return CIL.unbox_float(getImpl(obj)); + } + + public double getDouble(Object obj) + { + return getFloat(obj); + } + + public void set(Object obj, Object val, boolean accessible) throws IllegalAccessException + { + if (val instanceof Float + || val instanceof Byte + || val instanceof Short + || val instanceof Integer + || val instanceof Long) + setFloat(obj, ((Number)val).floatValue(), accessible); + else if (val instanceof Character) + setFloat(obj, ((Character)val).charValue(), accessible); + else + throw new IllegalArgumentException(); + } + + public void setFloat(Object obj, float val, boolean accessible) throws IllegalAccessException + { + setImpl(obj, CIL.box_float(val), accessible); + } + + public void setByte(Object obj, byte val, boolean accessible) throws IllegalAccessException + { + setFloat(obj, val, accessible); + } + + public void setChar(Object obj, char val, boolean accessible) throws IllegalAccessException + { + setFloat(obj, val, accessible); + } + + public void setShort(Object obj, short val, boolean accessible) throws IllegalAccessException + { + setFloat(obj, val, accessible); + } + + public void setInt(Object obj, int val, boolean accessible) throws IllegalAccessException + { + setFloat(obj, val, accessible); + } + + public void setLong(Object obj, long val, boolean accessible) throws IllegalAccessException + { + setFloat(obj, val, accessible); + } +} + +final class LongFieldImpl extends VMFieldImpl +{ + LongFieldImpl(Class declaringClass, Object fieldCookie) + { + super(declaringClass, fieldCookie); + } + + public Object get(Object obj) + { + return new Long(getLong(obj)); + } + + public long getLong(Object obj) + { + return CIL.unbox_long(getImpl(obj)); + } + + public float getFloat(Object obj) + { + return getLong(obj); + } + + public double getDouble(Object obj) + { + return getLong(obj); + } + + public void set(Object obj, Object val, boolean accessible) throws IllegalAccessException + { + if (val instanceof Long + || val instanceof Byte + || val instanceof Short + || val instanceof Integer) + setLong(obj, ((Number)val).longValue(), accessible); + else if (val instanceof Character) + setLong(obj, ((Character)val).charValue(), accessible); + else + throw new IllegalArgumentException(); + } + + public void setLong(Object obj, long val, boolean accessible) throws IllegalAccessException + { + setImpl(obj, CIL.box_long(val), accessible); + } + + public void setByte(Object obj, byte val, boolean accessible) throws IllegalAccessException + { + setLong(obj, val, accessible); + } + + public void setChar(Object obj, char val, boolean accessible) throws IllegalAccessException + { + setLong(obj, val, accessible); + } + + public void setShort(Object obj, short val, boolean accessible) throws IllegalAccessException + { + setLong(obj, val, accessible); + } + + public void setInt(Object obj, int val, boolean accessible) throws IllegalAccessException + { + setLong(obj, val, accessible); + } +} + +final class DoubleFieldImpl extends VMFieldImpl +{ + DoubleFieldImpl(Class declaringClass, Object fieldCookie) + { + super(declaringClass, fieldCookie); + } + + public Object get(Object obj) + { + return new Double(getDouble(obj)); + } + + public double getDouble(Object obj) + { + return CIL.unbox_double(getImpl(obj)); + } + + public void set(Object obj, Object val, boolean accessible) throws IllegalAccessException + { + if (val instanceof Double + || val instanceof Byte + || val instanceof Short + || val instanceof Integer + || val instanceof Float + || val instanceof Long) + setDouble(obj, ((Number)val).doubleValue(), accessible); + else if (val instanceof Character) + setDouble(obj, ((Character)val).charValue(), accessible); + else + throw new IllegalArgumentException(); + } + + public void setDouble(Object obj, double val, boolean accessible) throws IllegalAccessException + { + setImpl(obj, CIL.box_double(val), accessible); + } + + public void setByte(Object obj, byte val, boolean accessible) throws IllegalAccessException + { + setDouble(obj, val, accessible); + } + + public void setChar(Object obj, char val, boolean accessible) throws IllegalAccessException + { + setDouble(obj, val, accessible); + } + + public void setShort(Object obj, short val, boolean accessible) throws IllegalAccessException + { + setDouble(obj, val, accessible); + } + + public void setInt(Object obj, int val, boolean accessible) throws IllegalAccessException + { + setDouble(obj, val, accessible); + } + + public void setFloat(Object obj, float val, boolean accessible) throws IllegalAccessException + { + setDouble(obj, val, accessible); + } + + public void setLong(Object obj, long val, boolean accessible) throws IllegalAccessException + { + setDouble(obj, val, accessible); + } +} diff --git a/classpath/map.xml b/classpath/map.xml index 06c5c20f..4a6ab580 100644 --- a/classpath/map.xml +++ b/classpath/map.xml @@ -841,7 +841,7 @@ - + @@ -876,7 +876,8 @@ - + + diff --git a/runtime/ClassLoaderWrapper.cs b/runtime/ClassLoaderWrapper.cs index 9b67c154..0ec8bc73 100644 --- a/runtime/ClassLoaderWrapper.cs +++ b/runtime/ClassLoaderWrapper.cs @@ -433,7 +433,7 @@ class ClassLoaderWrapper { // since this type was compiled from Java source, we have to look for our // attributes - wrapper = new CompiledTypeWrapper(name, type); + wrapper = CompiledTypeWrapper.newInstance(name, type); } else { @@ -1012,7 +1012,7 @@ class ClassLoaderWrapper internal static void PublishLibraryImplementationHelperType(Type type) { - CompiledTypeWrapper typeWrapper = new CompiledTypeWrapper(type.FullName, type); + CompiledTypeWrapper typeWrapper = CompiledTypeWrapper.newInstance(type.FullName, type); SetWrapperForType(type, typeWrapper); GetBootstrapClassLoader().types[type.FullName] = typeWrapper; } diff --git a/runtime/MemberWrapper.cs b/runtime/MemberWrapper.cs index 80dd76af..da42f36e 100644 --- a/runtime/MemberWrapper.cs +++ b/runtime/MemberWrapper.cs @@ -37,7 +37,8 @@ enum MemberFlags : short { None = 0, HideFromReflection = 1, - ExplicitOverride = 2 + ExplicitOverride = 2, + LiteralField = 4 } class MemberWrapper @@ -47,11 +48,6 @@ class MemberWrapper private Modifiers modifiers; private MemberFlags flags; - protected MemberWrapper(TypeWrapper declaringType, Modifiers modifiers, bool hideFromReflection) - : this(declaringType, modifiers, hideFromReflection ? MemberFlags.HideFromReflection : MemberFlags.None) - { - } - protected MemberWrapper(TypeWrapper declaringType, Modifiers modifiers, MemberFlags flags) { Debug.Assert(declaringType != null); @@ -121,6 +117,19 @@ class MemberWrapper } } + internal bool IsLiteralField + { + get + { + return (flags & MemberFlags.LiteralField) != 0; + } + set + { + flags &= ~MemberFlags.LiteralField; + flags |= value ? MemberFlags.LiteralField : MemberFlags.None; + } + } + internal Modifiers Modifiers { get @@ -1049,7 +1058,7 @@ abstract class FieldWrapper : MemberWrapper private TypeWrapper fieldType; internal FieldWrapper(TypeWrapper declaringType, TypeWrapper fieldType, string name, string sig, Modifiers modifiers, FieldInfo field) - : base(declaringType, modifiers, false) + : base(declaringType, modifiers, field != null && field.IsLiteral ? MemberFlags.LiteralField : MemberFlags.None) { Debug.Assert(name != null); Debug.Assert(sig != null); @@ -1214,6 +1223,7 @@ abstract class FieldWrapper : MemberWrapper } // TODO instead of looking up the field by name, we should use the Token to find it. field = DeclaringType.TypeAsTBD.GetField(name, bindings); + this.IsLiteralField = field.IsLiteral; Debug.Assert(field != null); } @@ -1249,10 +1259,13 @@ abstract class FieldWrapper : MemberWrapper { LookupField(); } - if(field.IsLiteral) + // FieldInfo.IsLiteral is expensive, so we have our own flag + // TODO we might be able to ensure that we always use ConstantFieldWrapper for literal fields, + // in that case the we could simply remove the check altogether. + if(IsLiteralField) { // on a non-broken CLR GetValue on a literal will not trigger type initialization, but on Java it should - System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(field.DeclaringType.TypeHandle); + DeclaringType.RunClassInit(); } object val = field.GetValue(obj); if(fieldType.IsGhost) diff --git a/runtime/TypeWrapper.cs b/runtime/TypeWrapper.cs index b71fb229..30032819 100644 --- a/runtime/TypeWrapper.cs +++ b/runtime/TypeWrapper.cs @@ -3503,7 +3503,7 @@ sealed class DynamicTypeWrapper : TypeWrapper // because the ClassLoaderWrapper assumes that all dynamic types are in its hashtable, // but note that this only registers it for reverse lookup (from Type -> TypeWrapper), this // is necessary to make stack walking work. - ClassLoaderWrapper.SetWrapperForType(type, new CompiledTypeWrapper(type.FullName, type)); + ClassLoaderWrapper.SetWrapperForType(type, CompiledTypeWrapper.newInstance(type.FullName, type)); } } @@ -4477,14 +4477,188 @@ sealed class DynamicTypeWrapper : TypeWrapper } } -sealed class CompiledTypeWrapper : TypeWrapper +class CompiledTypeWrapper : TypeWrapper { private readonly Type type; private TypeWrapper[] interfaces; private TypeWrapper[] innerclasses; - private FieldInfo ghostRefField; - private Type typeAsBaseType; - private Type remappedType; + + internal static CompiledTypeWrapper newInstance(string name, Type type) + { + // TODO since ghost and remapped types can only exist in the core library assembly, we probably + // should be able to remove the Type.IsDefined() tests in most cases + if(type.IsValueType && type.IsDefined(typeof(GhostInterfaceAttribute), false)) + { + return new CompiledGhostTypeWrapper(name, type); + } + else if(type.IsDefined(typeof(RemappedTypeAttribute), false)) + { + return new CompiledRemappedTypeWrapper(name, type); + } + else + { + return new CompiledTypeWrapper(name, type); + } + } + + private sealed class CompiledRemappedTypeWrapper : CompiledTypeWrapper + { + private readonly Type remappedType; + + internal CompiledRemappedTypeWrapper(string name, Type type) + : base(name, type) + { + object[] attribs = type.GetCustomAttributes(typeof(RemappedTypeAttribute), false); + if(attribs.Length != 1) + { + throw new InvalidOperationException(); + } + remappedType = ((RemappedTypeAttribute)attribs[0]).Type; + } + + internal override Type TypeAsTBD + { + get + { + return remappedType; + } + } + + internal override bool IsRemapped + { + get + { + return true; + } + } + + protected override void LazyPublishMembers() + { + ArrayList methods = new ArrayList(); + ArrayList fields = new ArrayList(); + MemberInfo[] members = type.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance); + foreach(MemberInfo m in members) + { + if(!AttributeHelper.IsHideFromJava(m)) + { + MethodBase method = m as MethodBase; + if(method != null && + (remappedType.IsSealed || !m.Name.StartsWith("instancehelper_")) && + (!remappedType.IsSealed || method.IsStatic)) + { + methods.Add(CreateRemappedMethodWrapper(method)); + } + else + { + FieldInfo field = m as FieldInfo; + if(field != null) + { + fields.Add(CreateFieldWrapper(field)); + } + } + } + } + // if we're a remapped interface, we need to get the methods from the real interface + if(remappedType.IsInterface) + { + Type nestedHelper = type.GetNestedType("__Helper", BindingFlags.Public | BindingFlags.Static); + foreach(RemappedInterfaceMethodAttribute m in type.GetCustomAttributes(typeof(RemappedInterfaceMethodAttribute), false)) + { + MethodInfo method = remappedType.GetMethod(m.MappedTo); + MethodInfo mbHelper = method; + Modifiers modifiers = AttributeHelper.GetModifiers(method, false); + string name; + string sig; + TypeWrapper retType; + TypeWrapper[] paramTypes; + GetNameSigFromMethodBase(method, out name, out sig, out retType, out paramTypes); + if(nestedHelper != null) + { + mbHelper = nestedHelper.GetMethod(m.Name); + if(mbHelper == null) + { + mbHelper = method; + } + } + methods.Add(new CompiledRemappedMethodWrapper(this, m.Name, sig, method, retType, paramTypes, modifiers, false, mbHelper, null)); + } + } + SetMethods((MethodWrapper[])methods.ToArray(typeof(MethodWrapper))); + SetFields((FieldWrapper[])fields.ToArray(typeof(FieldWrapper))); + } + + private MethodWrapper CreateRemappedMethodWrapper(MethodBase mb) + { + Modifiers modifiers = AttributeHelper.GetModifiers(mb, false); + string name; + string sig; + TypeWrapper retType; + TypeWrapper[] paramTypes; + GetNameSigFromMethodBase(mb, out name, out sig, out retType, out paramTypes); + MethodInfo mbHelper = mb as MethodInfo; + MethodInfo mbNonvirtualHelper = null; + if(!mb.IsStatic && !mb.IsConstructor) + { + ParameterInfo[] parameters = mb.GetParameters(); + Type[] argTypes = new Type[parameters.Length + 1]; + argTypes[0] = remappedType; + for(int i = 0; i < parameters.Length; i++) + { + argTypes[i + 1] = parameters[i].ParameterType; + } + MethodInfo helper = type.GetMethod("instancehelper_" + mb.Name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, argTypes, null); + if(helper != null) + { + mbHelper = helper; + } + mbNonvirtualHelper = type.GetMethod("nonvirtualhelper/" + mb.Name, BindingFlags.NonPublic | BindingFlags.Static, null, argTypes, null); + } + return new CompiledRemappedMethodWrapper(this, name, sig, mb, retType, paramTypes, modifiers, false, mbHelper, mbNonvirtualHelper); + } + } + + private sealed class CompiledGhostTypeWrapper : CompiledTypeWrapper + { + private FieldInfo ghostRefField; + private Type typeAsBaseType; + + internal CompiledGhostTypeWrapper(string name, Type type) + : base(name, type) + { + } + + internal override Type TypeAsBaseType + { + get + { + if(typeAsBaseType == null) + { + typeAsBaseType = type.GetNestedType("__Interface"); + } + return typeAsBaseType; + } + } + + internal override FieldInfo GhostRefField + { + get + { + if(ghostRefField == null) + { + ghostRefField = type.GetField("__"); + } + return ghostRefField; + } + } + + internal override bool IsGhost + { + get + { + return true; + } + } + } internal static string GetName(Type type) { @@ -4534,19 +4708,12 @@ sealed class CompiledTypeWrapper : TypeWrapper return ClassLoaderWrapper.IsCoreAssemblyType(type) ? ClassLoaderWrapper.GetBootstrapClassLoader() : ClassLoaderWrapper.GetSystemClassLoader(); } - internal CompiledTypeWrapper(string name, Type type) + private CompiledTypeWrapper(string name, Type type) : base(GetModifiers(type), name, GetBaseTypeWrapper(type), GetClassLoader(type), null) { Debug.Assert(!(type is TypeBuilder)); Debug.Assert(!type.IsArray); - object[] attribs = type.GetCustomAttributes(typeof(RemappedTypeAttribute), false); - if(attribs.Length == 1) - { - this.typeAsBaseType = type; - this.remappedType = ((RemappedTypeAttribute)attribs[0]).Type; - } - this.type = type; } @@ -4647,6 +4814,7 @@ sealed class CompiledTypeWrapper : TypeWrapper { get { + // TODO why are we caching this? if(innerclasses == null) { Type[] nestedTypes = type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly); @@ -4694,30 +4862,7 @@ sealed class CompiledTypeWrapper : TypeWrapper { get { - if(typeAsBaseType == null) - { - if(IsGhost) - { - typeAsBaseType = type.GetNestedType("__Interface"); - } - else - { - typeAsBaseType = type; - } - } - return typeAsBaseType; - } - } - - internal override FieldInfo GhostRefField - { - get - { - if(ghostRefField == null) - { - ghostRefField = type.GetField("__"); - } - return ghostRefField; + return type; } } @@ -4850,81 +4995,29 @@ sealed class CompiledTypeWrapper : TypeWrapper ArrayList methods = new ArrayList(); ArrayList fields = new ArrayList(); MemberInfo[] members = type.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance); - if(remappedType == null) + foreach(MemberInfo m in members) { - foreach(MemberInfo m in members) + if(!AttributeHelper.IsHideFromJava(m)) { - if(!AttributeHelper.IsHideFromJava(m)) + MethodBase method = m as MethodBase; + if(method != null) { - MethodBase method = m as MethodBase; - if(method != null) - { - string name; - string sig; - TypeWrapper retType; - TypeWrapper[] paramTypes; - GetNameSigFromMethodBase(method, out name, out sig, out retType, out paramTypes); - MethodInfo mi = method as MethodInfo; - bool miranda = mi != null ? AttributeHelper.IsMirandaMethod(mi) : false; - methods.Add(MethodWrapper.Create(this, name, sig, method, retType, paramTypes, AttributeHelper.GetModifiers(method, false), miranda)); - } - else - { - FieldInfo field = m as FieldInfo; - if(field != null) - { - fields.Add(CreateFieldWrapper(field)); - } - } - } - } - } - else - { - foreach(MemberInfo m in members) - { - if(!AttributeHelper.IsHideFromJava(m)) - { - MethodBase method = m as MethodBase; - if(method != null && - (remappedType.IsSealed || !m.Name.StartsWith("instancehelper_")) && - (!remappedType.IsSealed || method.IsStatic)) - { - methods.Add(CreateRemappedMethodWrapper(method)); - } - else - { - FieldInfo field = m as FieldInfo; - if(field != null) - { - fields.Add(CreateFieldWrapper(field)); - } - } - } - } - // if we're a remapped interface, we need to get the methods from the real interface - if(remappedType.IsInterface) - { - Type nestedHelper = type.GetNestedType("__Helper", BindingFlags.Public | BindingFlags.Static); - foreach(RemappedInterfaceMethodAttribute m in type.GetCustomAttributes(typeof(RemappedInterfaceMethodAttribute), false)) - { - MethodInfo method = remappedType.GetMethod(m.MappedTo); - MethodInfo mbHelper = method; - Modifiers modifiers = AttributeHelper.GetModifiers(method, false); string name; string sig; TypeWrapper retType; TypeWrapper[] paramTypes; GetNameSigFromMethodBase(method, out name, out sig, out retType, out paramTypes); - if(nestedHelper != null) + MethodInfo mi = method as MethodInfo; + bool miranda = mi != null ? AttributeHelper.IsMirandaMethod(mi) : false; + methods.Add(MethodWrapper.Create(this, name, sig, method, retType, paramTypes, AttributeHelper.GetModifiers(method, false), miranda)); + } + else + { + FieldInfo field = m as FieldInfo; + if(field != null) { - mbHelper = nestedHelper.GetMethod(m.Name); - if(mbHelper == null) - { - mbHelper = method; - } + fields.Add(CreateFieldWrapper(field)); } - methods.Add(new CompiledRemappedMethodWrapper(this, m.Name, sig, method, retType, paramTypes, modifiers, false, mbHelper, null)); } } } @@ -5010,35 +5103,6 @@ sealed class CompiledTypeWrapper : TypeWrapper } } - private MethodWrapper CreateRemappedMethodWrapper(MethodBase mb) - { - Modifiers modifiers = AttributeHelper.GetModifiers(mb, false); - string name; - string sig; - TypeWrapper retType; - TypeWrapper[] paramTypes; - GetNameSigFromMethodBase(mb, out name, out sig, out retType, out paramTypes); - MethodInfo mbHelper = mb as MethodInfo; - MethodInfo mbNonvirtualHelper = null; - if(!mb.IsStatic && !mb.IsConstructor) - { - ParameterInfo[] parameters = mb.GetParameters(); - Type[] argTypes = new Type[parameters.Length + 1]; - argTypes[0] = remappedType; - for(int i = 0; i < parameters.Length; i++) - { - argTypes[i + 1] = parameters[i].ParameterType; - } - MethodInfo helper = type.GetMethod("instancehelper_" + mb.Name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, argTypes, null); - if(helper != null) - { - mbHelper = helper; - } - mbNonvirtualHelper = type.GetMethod("nonvirtualhelper/" + mb.Name, BindingFlags.NonPublic | BindingFlags.Static, null, argTypes, null); - } - return new CompiledRemappedMethodWrapper(this, name, sig, mb, retType, paramTypes, modifiers, false, mbHelper, mbNonvirtualHelper); - } - private FieldWrapper CreateFieldWrapper(FieldInfo field) { Modifiers modifiers = AttributeHelper.GetModifiers(field, false); @@ -5071,27 +5135,11 @@ sealed class CompiledTypeWrapper : TypeWrapper } } - internal override bool IsGhost - { - get - { - return type.IsDefined(typeof(GhostInterfaceAttribute), false); - } - } - - internal override bool IsRemapped - { - get - { - return remappedType != null; - } - } - internal override Type TypeAsTBD { get { - return remappedType != null ? remappedType : type; + return type; } } @@ -5250,7 +5298,7 @@ sealed class DotNetTypeWrapper : TypeWrapper TypeBuilder typeBuilder = moduleBuilder.DefineType(NamePrefix + name, TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract); AttributeHelper.SetInnerClass(typeBuilder, NamePrefix + name, NamePrefix + delegateType.FullName, "Method", Modifiers.Public | Modifiers.Interface | Modifiers.Static | Modifiers.Abstract); typeBuilder.DefineMethod("Invoke", MethodAttributes.Public | MethodAttributes.Abstract | MethodAttributes.Virtual, CallingConventions.Standard, invoke.ReturnType, args); - return new CompiledTypeWrapper(NamePrefix + name, typeBuilder.CreateType()); + return CompiledTypeWrapper.newInstance(NamePrefix + name, typeBuilder.CreateType()); } } return null; diff --git a/runtime/classpath.cs b/runtime/classpath.cs index 3ca3b70e..f712ad8e 100644 --- a/runtime/classpath.cs +++ b/runtime/classpath.cs @@ -188,7 +188,7 @@ namespace IKVM.NativeCode.java } } - public class Field + public class VMFieldImpl { public static string GetName(object fieldCookie) { @@ -215,6 +215,11 @@ namespace IKVM.NativeCode.java return VMClass.getWrapperFromClass(a).IsInSamePackageAs(VMClass.getWrapperFromClass(b)); } + public static void RunClassInit(object clazz) + { + VMClass.getWrapperFromClass(clazz).RunClassInit(); + } + public static object GetValue(object fieldCookie, object o) { Profiler.Enter("Field.GetValue"); @@ -235,24 +240,12 @@ namespace IKVM.NativeCode.java } } - public static void SetValue(object fieldCookie, object o, object v, bool accessible) + public static void SetValue(object fieldCookie, object o, object v) { Profiler.Enter("Field.SetValue"); try { FieldWrapper wrapper = (FieldWrapper)fieldCookie; - if(wrapper.IsFinal) - { - // NOTE Java runs the class initializer when trying to set a final field - wrapper.DeclaringType.RunClassInit(); - // Starting with JDK 1.5, it is legal to change final instance fields - // (see JSR-133) - if(wrapper.IsStatic || !accessible) - { - // NOTE even if the caller is the class itself, it still isn't legal - throw JavaException.IllegalAccessException("Field is final"); - } - } // if the field is an interface field, we must explicitly run , // because .NET reflection doesn't if(wrapper.DeclaringType.IsInterface)