diff options
Diffstat (limited to 'external/ikvm/runtime/JniInterface.cs')
-rw-r--r-- | external/ikvm/runtime/JniInterface.cs | 127 |
1 files changed, 95 insertions, 32 deletions
diff --git a/external/ikvm/runtime/JniInterface.cs b/external/ikvm/runtime/JniInterface.cs index aee0a4769f..d81576d056 100644 --- a/external/ikvm/runtime/JniInterface.cs +++ b/external/ikvm/runtime/JniInterface.cs @@ -1,5 +1,5 @@ /* - Copyright (C) 2002-2009 Jeroen Frijters + Copyright (C) 2002-2013 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 @@ -350,7 +350,7 @@ namespace IKVM.Runtime { private const string library = "ikvm-native-win32-x86"; - [DllImport(library)] + [DllImport(library, SetLastError = true)] private static extern IntPtr ikvm_LoadLibrary(string filename); [DllImport(library)] private static extern void ikvm_FreeLibrary(IntPtr handle); @@ -398,7 +398,7 @@ namespace IKVM.Runtime { private const string library = "ikvm-native-win32-x64"; - [DllImport(library)] + [DllImport(library, SetLastError = true)] private static extern IntPtr ikvm_LoadLibrary(string filename); [DllImport(library)] private static extern void ikvm_FreeLibrary(IntPtr handle); @@ -446,7 +446,7 @@ namespace IKVM.Runtime { private const string library = "ikvm-native"; - [DllImport(library)] + [DllImport(library, SetLastError = true)] private static extern IntPtr ikvm_LoadLibrary(string filename); [DllImport(library)] private static extern void ikvm_FreeLibrary(IntPtr handle); @@ -553,7 +553,8 @@ namespace IKVM.Runtime IntPtr p = NativeLibrary.LoadLibrary(filename); if(p == IntPtr.Zero) { - Tracer.Info(Tracer.Jni, "Library not found: {0}", filename); + Tracer.Info(Tracer.Jni, "Failed to load library: path = '{0}', error = {1}, message = {2}", filename, + Marshal.GetLastWin32Error(), new System.ComponentModel.Win32Exception().Message); return 0; } try @@ -1127,7 +1128,7 @@ namespace IKVM.Runtime return JNIEnv.JNI_ERR; } JNI.jvmDestroyed = true; - IKVM.NativeCode.java.lang.Thread.WaitUntilLastJniThread(); + Java_java_lang_Thread.WaitUntilLastJniThread(); return JNIEnv.JNI_OK; } @@ -1172,7 +1173,7 @@ namespace IKVM.Runtime object threadGroup = GlobalRefs.Unwrap(pAttachArgs->group.ToInt32()); if(threadGroup != null) { - IKVM.NativeCode.java.lang.Thread.AttachThreadFromJni(threadGroup); + Java_java_lang_Thread.AttachThreadFromJni(threadGroup); } } *penv = JNIEnv.CreateJNIEnv(); @@ -1188,7 +1189,7 @@ namespace IKVM.Runtime } // TODO if we set Thread.IsBackground to false when we attached, now might be a good time to set it back to true. JNIEnv.FreeJNIEnv(); - IKVM.NativeCode.ikvm.runtime.Startup.jniDetach(); + Java_ikvm_runtime_Startup.jniDetach(); return JNIEnv.JNI_OK; } @@ -1243,7 +1244,7 @@ namespace IKVM.Runtime static JNIEnv() { // we set the field here so that IKVM.Runtime.dll doesn't have to load us if we're not otherwise needed - IKVM.NativeCode.java.lang.SecurityManager.jniAssembly = typeof(JNIEnv).Assembly; + Java_java_lang_SecurityManager.jniAssembly = typeof(JNIEnv).Assembly; } internal ManagedJNIEnv GetManagedJNIEnv() @@ -1622,7 +1623,7 @@ namespace IKVM.Runtime // TODO what should the protection domain be? // NOTE I'm assuming name is platform encoded (as opposed to UTF-8), but the Sun JVM only seems to work for ASCII. global::java.lang.ClassLoader classLoader = (global::java.lang.ClassLoader)pEnv->UnwrapRef(loader); - return pEnv->MakeLocalRef(IKVM.NativeCode.java.lang.ClassLoader.defineClass0(classLoader, name != null ? StringFromOEM(name) : null, buf, 0, buf.Length, null)); + return pEnv->MakeLocalRef(Java_java_lang_ClassLoader.defineClass0(classLoader, name != null ? StringFromOEM(name) : null, buf, 0, buf.Length, null)); } catch(Exception x) { @@ -1690,7 +1691,7 @@ namespace IKVM.Runtime internal static jfieldID FromReflectedField(JNIEnv* pEnv, jobject field) { - return FieldWrapper.FromField(pEnv->UnwrapRef(field)).Cookie; + return FieldWrapper.FromField((java.lang.reflect.Field)pEnv->UnwrapRef(field)).Cookie; } internal static jobject ToReflectedMethod(JNIEnv* pEnv, jclass clazz_ignored, jmethodID method, jboolean isStatic) @@ -1725,7 +1726,10 @@ namespace IKVM.Runtime { ManagedJNIEnv env = pEnv->GetManagedJNIEnv(); Exception x = UnwrapRef(env, throwable) as Exception; - env.pendingException = x; + if (x != null) + { + env.pendingException = x; + } return JNI_OK; } @@ -1733,7 +1737,7 @@ namespace IKVM.Runtime { ManagedJNIEnv env = pEnv->GetManagedJNIEnv(); TypeWrapper wrapper = TypeWrapper.FromClass((java.lang.Class)UnwrapRef(env, clazz)); - MethodWrapper mw = wrapper.GetMethodWrapper("<init>", "(Ljava.lang.String;)V", false); + MethodWrapper mw = wrapper.GetMethodWrapper("<init>", msg == null ? "()V" : "(Ljava.lang.String;)V", false); if(mw != null) { jint rc; @@ -1742,7 +1746,7 @@ namespace IKVM.Runtime { wrapper.Finish(); java.lang.reflect.Constructor cons = (java.lang.reflect.Constructor)mw.ToMethodOrConstructor(false); - exception = (Exception)cons.newInstance(new object[] { StringFromOEM(msg) }, env.callerID); + exception = (Exception)cons.newInstance(msg == null ? new object[0] : new object[] { StringFromOEM(msg) }, env.callerID); rc = JNI_OK; } catch(RetargetableJavaException x) @@ -1925,50 +1929,104 @@ namespace IKVM.Runtime public jobject l; } - private static object InvokeHelper(JNIEnv* pEnv, jobject obj, jmethodID methodID, jvalue *args, bool nonVirtual) + private static object InvokeHelper(JNIEnv* pEnv, jobject objHandle, jmethodID methodID, jvalue* pArgs, bool nonVirtual) { ManagedJNIEnv env = pEnv->GetManagedJNIEnv(); + object obj = UnwrapRef(env, objHandle); MethodWrapper mw = MethodWrapper.FromCookie(methodID); + mw.Link(); + mw.ResolveMethod(); TypeWrapper[] argTypes = mw.GetParameters(); - object[] argarray = new object[argTypes.Length]; - for (int i = 0; i < argarray.Length; i++) + object[] args = new object[argTypes.Length + (mw.HasCallerID ? 1 : 0)]; + for (int i = 0; i < argTypes.Length; i++) { TypeWrapper type = argTypes[i]; if (type == PrimitiveTypeWrapper.BOOLEAN) - argarray[i] = java.lang.Boolean.valueOf(args[i].z != JNI_FALSE); + args[i] = pArgs[i].z != JNI_FALSE; else if (type == PrimitiveTypeWrapper.BYTE) - argarray[i] = java.lang.Byte.valueOf((byte)args[i].b); + args[i] = (byte)pArgs[i].b; else if (type == PrimitiveTypeWrapper.CHAR) - argarray[i] = java.lang.Character.valueOf((char)args[i].c); + args[i] = (char)pArgs[i].c; else if (type == PrimitiveTypeWrapper.SHORT) - argarray[i] = java.lang.Short.valueOf(args[i].s); + args[i] = pArgs[i].s; else if (type == PrimitiveTypeWrapper.INT) - argarray[i] = java.lang.Integer.valueOf(args[i].i); + args[i] = pArgs[i].i; else if (type == PrimitiveTypeWrapper.LONG) - argarray[i] = java.lang.Long.valueOf(args[i].j); + args[i] = pArgs[i].j; else if (type == PrimitiveTypeWrapper.FLOAT) - argarray[i] = java.lang.Float.valueOf(args[i].f); + args[i] = pArgs[i].f; else if (type == PrimitiveTypeWrapper.DOUBLE) - argarray[i] = java.lang.Double.valueOf(args[i].d); + args[i] = pArgs[i].d; else - argarray[i] = UnwrapRef(env, args[i].l); + args[i] = argTypes[i].GhostWrap(UnwrapRef(env, pArgs[i].l)); } - try + if (mw.HasCallerID) { - return mw.InvokeJNI(UnwrapRef(env, obj), argarray, nonVirtual, env.callerID); + args[args.Length - 1] = env.callerID; } - catch(java.lang.reflect.InvocationTargetException x) + try { - SetPendingException(pEnv, ikvm.runtime.Util.mapException(x.getCause())); - return null; + if (nonVirtual && mw.RequiresNonVirtualDispatcher) + { + return InvokeNonVirtual(env, mw, obj, args); + } + if (mw.IsConstructor) + { + if (obj == null) + { + return mw.CreateInstance(args); + } + else + { + MethodBase mb = mw.GetMethod(); + if (mb.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 + throw new NotSupportedException(string.Format("Remapped type {0} doesn't support constructor invocation on an existing instance", mw.DeclaringType.Name)); + } + else if (!mb.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 " + mb.DeclaringType.FullName); + } + } + } + return mw.Invoke(obj, args); } - catch(Exception x) + catch (Exception x) { SetPendingException(pEnv, ikvm.runtime.Util.mapException(x)); return null; } } + private static object InvokeNonVirtual(ManagedJNIEnv env, MethodWrapper mw, object obj, object[] argarray) + { + if (mw.HasCallerID || mw.IsDynamicOnly) + { + throw new NotSupportedException(); + } + if (mw.DeclaringType.IsRemapped && !mw.DeclaringType.TypeAsBaseType.IsInstanceOfType(obj)) + { + return mw.InvokeNonvirtualRemapped(obj, argarray); + } + else + { + Delegate del = (Delegate)Activator.CreateInstance(mw.GetDelegateType(), + new object[] { obj, mw.GetMethod().MethodHandle.GetFunctionPointer() }); + try + { + return del.DynamicInvoke(argarray); + } + catch (TargetInvocationException x) + { + throw ikvm.runtime.Util.mapException(x.InnerException); + } + } + } + internal static jobject NewObjectA(JNIEnv* pEnv, jclass clazz, jmethodID methodID, jvalue *args) { TypeWrapper wrapper = TypeWrapper.FromClass((java.lang.Class)pEnv->UnwrapRef(clazz)); @@ -2657,6 +2715,11 @@ namespace IKVM.Runtime internal static jobject NewStringUTF(JNIEnv* pEnv, byte* psz) { + if (psz == null) + { + // The JNI spec does not explicitly allow a null pointer, but the JDK accepts it + return IntPtr.Zero; + } return pEnv->MakeLocalRef(StringFromUTF8(psz)); } |