Changed JNI reflection to be based on Java reflection (where possible).

This commit is contained in:
jfrijters 2008-08-21 06:40:22 +00:00
Родитель 316dd359eb
Коммит 6bce58f1bc
5 изменённых файлов: 202 добавлений и 74 удалений

Просмотреть файл

@ -1405,7 +1405,8 @@ namespace IKVM.Runtime
try
{
wrapper.Finish();
exception = (Exception)mw.InvokeJNI(null, new object[] { StringFromOEM(msg) }, false, null);
java.lang.reflect.Constructor cons = (java.lang.reflect.Constructor)mw.ToMethodOrConstructor(false);
exception = (Exception)cons.newInstance(new object[] { StringFromOEM(msg) }, (ikvm.@internal.CallerID)JVM.CreateCallerID(pEnv->currentMethod));
rc = JNI_OK;
}
catch(RetargetableJavaException x)
@ -1635,28 +1636,28 @@ namespace IKVM.Runtime
switch(sig[i])
{
case 'Z':
argarray[i] = args[i].z != JNI_FALSE;
argarray[i] = java.lang.Boolean.valueOf(args[i].z != JNI_FALSE);
break;
case 'B':
argarray[i] = args[i].b;
argarray[i] = java.lang.Byte.valueOf((byte)args[i].b);
break;
case 'C':
argarray[i] = (char)args[i].c;
argarray[i] = java.lang.Character.valueOf((char)args[i].c);
break;
case 'S':
argarray[i] = args[i].s;
argarray[i] = java.lang.Short.valueOf(args[i].s);
break;
case 'I':
argarray[i] = args[i].i;
argarray[i] = java.lang.Integer.valueOf(args[i].i);
break;
case 'J':
argarray[i] = args[i].j;
argarray[i] = java.lang.Long.valueOf(args[i].j);
break;
case 'F':
argarray[i] = args[i].f;
argarray[i] = java.lang.Float.valueOf(args[i].f);
break;
case 'D':
argarray[i] = args[i].d;
argarray[i] = java.lang.Double.valueOf(args[i].d);
break;
case 'L':
argarray[i] = pEnv->UnwrapRef(args[i].l);
@ -2003,120 +2004,99 @@ namespace IKVM.Runtime
return FindFieldID(pEnv, clazz, name, sig, false);
}
private static void SetFieldValue(jfieldID cookie, object obj, object val)
private static sun.reflect.FieldAccessor GetFieldAccessor(jfieldID cookie)
{
try
{
FieldWrapper.FromCookie(cookie).SetValue(obj, val);
}
catch
{
Debug.Assert(false);
throw;
}
}
private static object GetFieldValue(jfieldID cookie, object obj)
{
try
{
return FieldWrapper.FromCookie(cookie).GetValue(obj);
}
catch
{
Debug.Assert(false);
throw;
}
return (sun.reflect.FieldAccessor)FieldWrapper.FromCookie(cookie).GetFieldAccessorJNI();
}
internal static jobject GetObjectField(JNIEnv* pEnv, jobject obj, jfieldID fieldID)
{
return pEnv->MakeLocalRef(GetFieldValue(fieldID, pEnv->UnwrapRef(obj)));
return pEnv->MakeLocalRef(GetFieldAccessor(fieldID).get(pEnv->UnwrapRef(obj)));
}
internal static jboolean GetBooleanField(JNIEnv* pEnv, jobject obj, jfieldID fieldID)
{
return ((bool)GetFieldValue(fieldID, pEnv->UnwrapRef(obj))) ? JNI_TRUE : JNI_FALSE;
return GetFieldAccessor(fieldID).getBoolean(pEnv->UnwrapRef(obj)) ? JNI_TRUE : JNI_FALSE;
}
internal static jbyte GetByteField(JNIEnv* pEnv, jobject obj, jfieldID fieldID)
{
return (jbyte)(byte)GetFieldValue(fieldID, pEnv->UnwrapRef(obj));
return (jbyte)GetFieldAccessor(fieldID).getByte(pEnv->UnwrapRef(obj));
}
internal static jchar GetCharField(JNIEnv* pEnv, jobject obj, jfieldID fieldID)
{
return (jchar)(char)GetFieldValue(fieldID, pEnv->UnwrapRef(obj));
return (jchar)GetFieldAccessor(fieldID).getChar(pEnv->UnwrapRef(obj));
}
internal static jshort GetShortField(JNIEnv* pEnv, jobject obj, jfieldID fieldID)
{
return (jshort)(short)GetFieldValue(fieldID, pEnv->UnwrapRef(obj));
return (jshort)GetFieldAccessor(fieldID).getShort(pEnv->UnwrapRef(obj));
}
internal static jint GetIntField(JNIEnv* pEnv, jobject obj, jfieldID fieldID)
{
return (jint)(int)GetFieldValue(fieldID, pEnv->UnwrapRef(obj));
return (jint)GetFieldAccessor(fieldID).getInt(pEnv->UnwrapRef(obj));
}
internal static jlong GetLongField(JNIEnv* pEnv, jobject obj, jfieldID fieldID)
{
return (jlong)(long)GetFieldValue(fieldID, pEnv->UnwrapRef(obj));
return (jlong)GetFieldAccessor(fieldID).getLong(pEnv->UnwrapRef(obj));
}
internal static jfloat GetFloatField(JNIEnv* pEnv, jobject obj, jfieldID fieldID)
{
return (jfloat)(float)GetFieldValue(fieldID, pEnv->UnwrapRef(obj));
return (jfloat)GetFieldAccessor(fieldID).getFloat(pEnv->UnwrapRef(obj));
}
internal static jdouble GetDoubleField(JNIEnv* pEnv, jobject obj, jfieldID fieldID)
{
return (jdouble)(double)GetFieldValue(fieldID, pEnv->UnwrapRef(obj));
return (jdouble)GetFieldAccessor(fieldID).getDouble(pEnv->UnwrapRef(obj));
}
internal static void SetObjectField(JNIEnv* pEnv, jobject obj, jfieldID fieldID, jobject val)
{
SetFieldValue(fieldID, pEnv->UnwrapRef(obj), pEnv->UnwrapRef(val));
GetFieldAccessor(fieldID).set(pEnv->UnwrapRef(obj), pEnv->UnwrapRef(val));
}
internal static void SetBooleanField(JNIEnv* pEnv, jobject obj, jfieldID fieldID, jboolean val)
{
SetFieldValue(fieldID, pEnv->UnwrapRef(obj), val != JNI_FALSE);
GetFieldAccessor(fieldID).setBoolean(pEnv->UnwrapRef(obj), val != JNI_FALSE);
}
internal static void SetByteField(JNIEnv* pEnv, jobject obj, jfieldID fieldID, jbyte val)
{
SetFieldValue(fieldID, pEnv->UnwrapRef(obj), (byte)val);
GetFieldAccessor(fieldID).setByte(pEnv->UnwrapRef(obj), (byte)val);
}
internal static void SetCharField(JNIEnv* pEnv, jobject obj, jfieldID fieldID, jchar val)
{
SetFieldValue(fieldID, pEnv->UnwrapRef(obj), (char)val);
GetFieldAccessor(fieldID).setChar(pEnv->UnwrapRef(obj), (char)val);
}
internal static void SetShortField(JNIEnv* pEnv, jobject obj, jfieldID fieldID, jshort val)
{
SetFieldValue(fieldID, pEnv->UnwrapRef(obj), (short)val);
GetFieldAccessor(fieldID).setShort(pEnv->UnwrapRef(obj), (short)val);
}
internal static void SetIntField(JNIEnv* pEnv, jobject obj, jfieldID fieldID, jint val)
{
SetFieldValue(fieldID, pEnv->UnwrapRef(obj), (int)val);
GetFieldAccessor(fieldID).setInt(pEnv->UnwrapRef(obj), (int)val);
}
internal static void SetLongField(JNIEnv* pEnv, jobject obj, jfieldID fieldID, jlong val)
{
SetFieldValue(fieldID, pEnv->UnwrapRef(obj), (long)val);
GetFieldAccessor(fieldID).setLong(pEnv->UnwrapRef(obj), (long)val);
}
internal static void SetFloatField(JNIEnv* pEnv, jobject obj, jfieldID fieldID, jfloat val)
{
SetFieldValue(fieldID, pEnv->UnwrapRef(obj), (float)val);
GetFieldAccessor(fieldID).setFloat(pEnv->UnwrapRef(obj), (float)val);
}
internal static void SetDoubleField(JNIEnv* pEnv, jobject obj, jfieldID fieldID, jdouble val)
{
SetFieldValue(fieldID, pEnv->UnwrapRef(obj), (double)val);
GetFieldAccessor(fieldID).setDouble(pEnv->UnwrapRef(obj), (double)val);
}
internal static jmethodID GetStaticMethodID(JNIEnv* pEnv, jclass clazz, byte* name, byte* sig)
@ -2221,92 +2201,92 @@ namespace IKVM.Runtime
internal static jobject GetStaticObjectField(JNIEnv* pEnv, jclass clazz, jfieldID fieldID)
{
return pEnv->MakeLocalRef(GetFieldValue(fieldID, null));
return pEnv->MakeLocalRef(GetFieldAccessor(fieldID).get(null));
}
internal static jboolean GetStaticBooleanField(JNIEnv* pEnv, jclass clazz, jfieldID fieldID)
{
return ((bool)GetFieldValue(fieldID, null)) ? JNI_TRUE : JNI_FALSE;
return GetFieldAccessor(fieldID).getBoolean(null) ? JNI_TRUE : JNI_FALSE;
}
internal static jbyte GetStaticByteField(JNIEnv* pEnv, jclass clazz, jfieldID fieldID)
{
return (jbyte)(byte)GetFieldValue(fieldID, null);
return (jbyte)GetFieldAccessor(fieldID).getByte(null);
}
internal static jchar GetStaticCharField(JNIEnv* pEnv, jclass clazz, jfieldID fieldID)
{
return (jchar)(char)GetFieldValue(fieldID, null);
return (jchar)GetFieldAccessor(fieldID).getChar(null);
}
internal static jshort GetStaticShortField(JNIEnv* pEnv, jclass clazz, jfieldID fieldID)
{
return (jshort)(short)GetFieldValue(fieldID, null);
return (jshort)GetFieldAccessor(fieldID).getShort(null);
}
internal static jint GetStaticIntField(JNIEnv* pEnv, jclass clazz, jfieldID fieldID)
{
return (jint)(int)GetFieldValue(fieldID, null);
return (jint)GetFieldAccessor(fieldID).getInt(null);
}
internal static jlong GetStaticLongField(JNIEnv* pEnv, jclass clazz, jfieldID fieldID)
{
return (jlong)(long)GetFieldValue(fieldID, null);
return (jlong)GetFieldAccessor(fieldID).getLong(null);
}
internal static jfloat GetStaticFloatField(JNIEnv* pEnv, jclass clazz, jfieldID fieldID)
{
return (jfloat)(float)GetFieldValue(fieldID, null);
return (jfloat)GetFieldAccessor(fieldID).getFloat(null);
}
internal static jdouble GetStaticDoubleField(JNIEnv* pEnv, jclass clazz, jfieldID fieldID)
{
return (jdouble)(double)GetFieldValue(fieldID, null);
return (jdouble)GetFieldAccessor(fieldID).getDouble(null);
}
internal static void SetStaticObjectField(JNIEnv* pEnv, jclass clazz, jfieldID fieldID, jobject val)
{
SetFieldValue(fieldID, null, pEnv->UnwrapRef(val));
GetFieldAccessor(fieldID).set(null, pEnv->UnwrapRef(val));
}
internal static void SetStaticBooleanField(JNIEnv* pEnv, jclass clazz, jfieldID fieldID, jboolean val)
{
SetFieldValue(fieldID, null, val != JNI_FALSE);
GetFieldAccessor(fieldID).setBoolean(null, val != JNI_FALSE);
}
internal static void SetStaticByteField(JNIEnv* pEnv, jclass clazz, jfieldID fieldID, jbyte val)
{
SetFieldValue(fieldID, null, (byte)val);
GetFieldAccessor(fieldID).setByte(null, (byte)val);
}
internal static void SetStaticCharField(JNIEnv* pEnv, jclass clazz, jfieldID fieldID, jchar val)
{
SetFieldValue(fieldID, null, (char)val);
GetFieldAccessor(fieldID).setChar(null, (char)val);
}
internal static void SetStaticShortField(JNIEnv* pEnv, jclass clazz, jfieldID fieldID, jshort val)
{
SetFieldValue(fieldID, null, (short)val);
GetFieldAccessor(fieldID).setShort(null, (short)val);
}
internal static void SetStaticIntField(JNIEnv* pEnv, jclass clazz, jfieldID fieldID, jint val)
{
SetFieldValue(fieldID, null, (int)val);
GetFieldAccessor(fieldID).setInt(null, (int)val);
}
internal static void SetStaticLongField(JNIEnv* pEnv, jclass clazz, jfieldID fieldID, jlong val)
{
SetFieldValue(fieldID, null, (long)val);
GetFieldAccessor(fieldID).setLong(null, (long)val);
}
internal static void SetStaticFloatField(JNIEnv* pEnv, jclass clazz, jfieldID fieldID, jfloat val)
{
SetFieldValue(fieldID, null, (float)val);
GetFieldAccessor(fieldID).setFloat(null, (float)val);
}
internal static void SetStaticDoubleField(JNIEnv* pEnv, jclass clazz, jfieldID fieldID, jdouble val)
{
SetFieldValue(fieldID, null, (double)val);
GetFieldAccessor(fieldID).setDouble(null, (double)val);
}
internal static jstring NewString(JNIEnv* pEnv, jchar* unicode, int len)

Просмотреть файл

@ -29,6 +29,7 @@ using System.Reflection.Emit;
#endif
using System.Diagnostics;
using IKVM.Attributes;
using System.Threading;
namespace IKVM.Internal
{
@ -278,6 +279,7 @@ namespace IKVM.Internal
abstract class MethodWrapper : MemberWrapper
{
#if !STATIC_COMPILER && !FIRST_PASS
private static Dictionary<MethodWrapper, sun.reflect.MethodAccessor> invokenonvirtualCache;
private volatile object reflectionMethod;
#endif
internal static readonly MethodWrapper[] EmptyArray = new MethodWrapper[0];
@ -704,9 +706,122 @@ namespace IKVM.Internal
#if FIRST_PASS
return null;
#else
return Invoke(obj, args, nonVirtual, ikvm.@internal.CallerID.create(callerID));
if (ReferenceEquals(Name, StringConstants.INIT))
{
java.lang.reflect.Constructor cons = (java.lang.reflect.Constructor)ToMethodOrConstructor(false);
if (obj == null)
{
sun.reflect.ConstructorAccessor acc = cons.getConstructorAccessor();
if (acc == null)
{
acc = reflectionFactory.newConstructorAccessor(cons);
cons.setConstructorAccessor(acc);
}
return acc.newInstance(args);
}
else if (method is MethodInfo)
{
Debug.Assert(method.IsStatic);
// we're dealing with a constructor on a remapped type, if obj is supplied, it means
// that we should call the constructor on an already existing instance, but that isn't
// possible with remapped types
// the type of this exception is a bit random (note that this can only happen through JNI reflection)
throw new java.lang.IncompatibleClassChangeError(string.Format("Remapped type {0} doesn't support constructor invocation on an existing instance", DeclaringType.Name));
}
else if (!method.DeclaringType.IsInstanceOfType(obj))
{
// we're trying to initialize an existing instance of a remapped type
throw new NotSupportedException("Unable to partially construct object of type " + obj.GetType().FullName + " to type " + method.DeclaringType.FullName);
}
else
{
try
{
InvokeArgsProcessor proc = new InvokeArgsProcessor(this, method, obj, UnboxArgs(args), ikvm.@internal.CallerID.create(callerID));
object o = method.Invoke(proc.GetObj(), proc.GetArgs());
TypeWrapper retType = this.ReturnType;
if (!retType.IsUnloadable && retType.IsGhost)
{
o = retType.GhostRefField.GetValue(o);
}
return o;
}
catch (ArgumentException x1)
{
throw new java.lang.IllegalArgumentException(x1.Message);
}
catch (TargetInvocationException x)
{
throw new java.lang.reflect.InvocationTargetException(ikvm.runtime.Util.mapException(x.InnerException));
}
}
}
else if (nonVirtual
&& !this.IsStatic
&& !this.IsPrivate
&& !this.IsAbstract
&& !this.IsFinal
&& !this.DeclaringType.IsFinal)
{
if (this.DeclaringType.IsRemapped)
{
ResolveMethod();
return InvokeImpl(method, obj, UnboxArgs(args), true, ikvm.@internal.CallerID.create(callerID));
}
else
{
if (invokenonvirtualCache == null)
{
Interlocked.CompareExchange(ref invokenonvirtualCache, new Dictionary<MethodWrapper, sun.reflect.MethodAccessor>(), null);
}
sun.reflect.MethodAccessor acc;
lock (invokenonvirtualCache)
{
if (!invokenonvirtualCache.TryGetValue(this, out acc))
{
acc = new IKVM.NativeCode.sun.reflect.ReflectionFactory.FastMethodAccessorImpl((java.lang.reflect.Method)ToMethodOrConstructor(false), true);
invokenonvirtualCache.Add(this, acc);
}
}
object val = acc.invoke(obj, args, ikvm.@internal.CallerID.create(callerID));
if (this.ReturnType.IsPrimitive && this.ReturnType != PrimitiveTypeWrapper.VOID)
{
val = JVM.Unbox(val);
}
return val;
}
}
else
{
java.lang.reflect.Method method = (java.lang.reflect.Method)ToMethodOrConstructor(false);
sun.reflect.MethodAccessor acc = method.getMethodAccessor();
if (acc == null)
{
acc = reflectionFactory.newMethodAccessor(method);
method.setMethodAccessor(acc);
}
object val = acc.invoke(obj, args, ikvm.@internal.CallerID.create(callerID));
if (this.ReturnType.IsPrimitive && this.ReturnType != PrimitiveTypeWrapper.VOID)
{
val = JVM.Unbox(val);
}
return val;
}
#endif
}
private object[] UnboxArgs(object[] args)
{
TypeWrapper[] paramTypes = GetParameters();
for (int i = 0; i < paramTypes.Length; i++)
{
if (paramTypes[i].IsPrimitive)
{
args[i] = JVM.Unbox(args[i]);
}
}
return args;
}
#endif // !STATIC_COMPILER
#if !STATIC_COMPILER && !FIRST_PASS
@ -1183,6 +1298,7 @@ namespace IKVM.Internal
#if !STATIC_COMPILER && !FIRST_PASS
private static readonly FieldInfo slotField = typeof(java.lang.reflect.Field).GetField("slot", BindingFlags.Instance | BindingFlags.NonPublic);
private volatile object reflectionField;
private sun.reflect.FieldAccessor jniAccessor;
#endif
internal static readonly FieldWrapper[] EmptyArray = new FieldWrapper[0];
private FieldInfo field;
@ -1414,6 +1530,19 @@ namespace IKVM.Internal
#endif
}
}
internal object GetFieldAccessorJNI()
{
#if FIRST_PASS
return null;
#else
if (jniAccessor == null)
{
jniAccessor = reflectionFactory.newFieldAccessor((java.lang.reflect.Field)ToField(false), true);
}
return jniAccessor;
#endif
}
#endif // !STATIC_COMPILER
internal virtual object GetValue(object obj)

Просмотреть файл

@ -11315,7 +11315,13 @@ namespace IKVM.Internal
protected override void EmitSetImpl(CodeEmitter ilgen)
{
throw new InvalidOperationException();
// NOTE even though the field is final, JNI reflection can still be used to set its value!
LocalBuilder temp = ilgen.AllocTempLocal(underlyingType);
ilgen.Emit(OpCodes.Stloc, temp);
ilgen.Emit(OpCodes.Unbox, underlyingType);
ilgen.Emit(OpCodes.Ldloc, temp);
ilgen.Emit(OpCodes.Stobj, underlyingType);
ilgen.ReleaseTempLocal(temp);
}
#endif

Просмотреть файл

@ -5859,7 +5859,7 @@ namespace IKVM.NativeCode.sun.reflect
}
}
private sealed class FastMethodAccessorImpl : srMethodAccessor
internal sealed class FastMethodAccessorImpl : srMethodAccessor
{
private static readonly MethodInfo valueOfByte;
private static readonly MethodInfo valueOfBoolean;
@ -5927,7 +5927,7 @@ namespace IKVM.NativeCode.sun.reflect
}
}
internal FastMethodAccessorImpl(jlrMethod method)
internal FastMethodAccessorImpl(jlrMethod method, bool nonvirtual)
{
MethodWrapper mw = MethodWrapper.FromMethodOrConstructor(method);
mw.DeclaringType.Finish();
@ -6018,7 +6018,7 @@ namespace IKVM.NativeCode.sun.reflect
{
ilgen.Emit(OpCodes.Ldarg_2);
}
if (mw.IsStatic)
if (mw.IsStatic || nonvirtual)
{
mw.EmitCall(ilgen);
}
@ -7672,7 +7672,7 @@ namespace IKVM.NativeCode.sun.reflect
TypeWrapper tw = TypeWrapper.FromClass(m.getDeclaringClass());
if (!mw.IsDynamicOnly && !tw.IsRemapped)
{
return new FastMethodAccessorImpl(m);
return new FastMethodAccessorImpl(m, false);
}
}
return new MethodAccessorImpl(m);

Просмотреть файл

@ -379,6 +379,19 @@ namespace IKVM.Internal
}
#endif
#if !STATIC_COMPILER
// helper for JNI (which doesn't have access to core library internals)
internal static object CreateCallerID(RuntimeMethodHandle method)
{
#if FIRST_PASS
return null;
#else
return ikvm.@internal.CallerID.create(MethodBase.GetMethodFromHandle(method));
#endif
}
#endif
#if !STATIC_COMPILER
// helper for JNI (which doesn't have access to core library internals)
internal static object NewDirectByteBuffer(long address, int capacity)