internal static void SetObjectArrayElement(JNIEnv* pEnv, jarray array, jsize index, jobject val) { try { // we want to support (non-primitive) value types so we can't cast to object[] ((Array)pEnv->UnwrapRef(array)).SetValue(pEnv->UnwrapRef(val), index); } catch(IndexOutOfRangeException) { SetPendingException(pEnv, new java.lang.ArrayIndexOutOfBoundsException()); } }
internal static jobject NewDirectByteBuffer(JNIEnv* pEnv, IntPtr address, jlong capacity) { try { if(capacity < 0 || capacity > int.MaxValue) { SetPendingException(pEnv, new java.lang.IllegalArgumentException("capacity")); return IntPtr.Zero; } return pEnv->MakeLocalRef(JVM.NewDirectByteBuffer(address.ToInt64(), (int)capacity)); } catch(Exception x) { SetPendingException(pEnv, ikvm.runtime.Util.mapException(x)); return IntPtr.Zero; } }
internal static jlong GetDirectBufferCapacity(JNIEnv* pEnv, jobject buf) { try { return (jlong)(long)((java.nio.Buffer)pEnv->UnwrapRef(buf)).capacity(); } catch(Exception x) { SetPendingException(pEnv, ikvm.runtime.Util.mapException(x)); return 0; } }
internal static void ReleaseStringCritical(JNIEnv* pEnv, jstring str, jchar* cstring) { Marshal.FreeHGlobal((IntPtr)(void*)cstring); }
internal static void DeleteWeakGlobalRef(JNIEnv* pEnv, jweak obj) { int i = obj.ToInt32(); if(i < 0) { i = -i; i -= (1 << 30); lock(GlobalRefs.weakRefLock) { GlobalRefs.weakRefs[i].Free(); } } if(i > 0) { Debug.Assert(false, "local ref passed to DeleteWeakGlobalRef"); } }
internal static void GetStringUTFRegion(JNIEnv* pEnv, IntPtr str, int start, int len, IntPtr buf) { string s = (string)pEnv->UnwrapRef(str); if(s != null) { if(start < 0 || start > s.Length || s.Length - start < len) { SetPendingException(pEnv, new java.lang.StringIndexOutOfBoundsException()); return; } else { byte* p = (byte*)(void*)buf; for(int i = 0; i < len; i++) { char ch = s[start + i]; if((ch != 0) && (ch <= 0x7F)) { *p++ = (byte)ch; } else if(ch <= 0x7FF) { *p++ = (byte)((ch >> 6) | 0xC0); *p++ = (byte)((ch & 0x3F) | 0x80); } else { *p++ = (byte)((ch >> 12) | 0xE0); *p++ = (byte)(((ch >> 6) & 0x3F) | 0x80); *p++ = (byte)((ch & 0x3F) | 0x80); } } return; } } else { SetPendingException(pEnv, new java.lang.NullPointerException()); } }
internal static void ReleasePrimitiveArrayCritical(JNIEnv* pEnv, jarray array, void* carray, jint mode) { Array ar = (Array)pEnv->UnwrapRef(array); if(pEnv->criticalArrayHandle1.Target == ar && (void*)pEnv->criticalArrayHandle1.AddrOfPinnedObject() == carray) { if(mode == 0 || mode == JNI_ABORT) { pEnv->criticalArrayHandle1.Target = null; } return; } if(pEnv->criticalArrayHandle2.Target == ar && (void*)pEnv->criticalArrayHandle2.AddrOfPinnedObject() == carray) { if(mode == 0 || mode == JNI_ABORT) { pEnv->criticalArrayHandle2.Target = null; } return; } if(mode == 0 || mode == JNI_COMMIT) { // TODO not 64-bit safe (len can overflow) int len = ar.Length * GetPrimitiveArrayElementSize(ar); GCHandle h = GCHandle.Alloc(ar, GCHandleType.Pinned); try { byte* pdst = (byte*)(void*)h.AddrOfPinnedObject(); byte* psrc = (byte*)(void*)carray; // TODO isn't there a managed memcpy? for(int i = 0; i < len; i++) { *pdst++ = *psrc++; } } finally { h.Free(); } } if(mode == 0 || mode == JNI_ABORT) { JniMem.Free((IntPtr)carray); } }
internal static void ReleaseByteArrayElements(JNIEnv* pEnv, jbyteArray array, jbyte* elems, jint mode) { if(mode == 0 || mode == JNI_COMMIT) { byte[] b = (byte[])pEnv->UnwrapRef(array); for(int i = 0; i < b.Length; i++) { b[i] = (byte)elems[i]; } } if(mode == 0 || mode == JNI_ABORT) { JniMem.Free((IntPtr)(void*)elems); } }
internal static void ReleaseDoubleArrayElements(JNIEnv* pEnv, jdoubleArray array, jdouble* elems, jint mode) { if(mode == 0 || mode == JNI_COMMIT) { double[] b = (double[])pEnv->UnwrapRef(array); Marshal.Copy((IntPtr)(void*)elems, b, 0, b.Length); } if(mode == 0 || mode == JNI_ABORT) { JniMem.Free((IntPtr)(void*)elems); } }
internal static jfloat* GetFloatArrayElements(JNIEnv* pEnv, jfloatArray array, jboolean* isCopy) { float[] b = (float[])pEnv->UnwrapRef(array); IntPtr buf = JniMem.Alloc(b.Length * 4); Marshal.Copy(b, 0, buf, b.Length); if(isCopy != null) { *isCopy = JNI_TRUE; } return (jfloat*)(void*)buf; }
internal static jdouble* GetDoubleArrayElements(JNIEnv* pEnv, jdoubleArray array, jboolean* isCopy) { double[] b = (double[])pEnv->UnwrapRef(array); IntPtr buf = JniMem.Alloc(b.Length * 8); Marshal.Copy(b, 0, buf, b.Length); if(isCopy != null) { *isCopy = JNI_TRUE; } return (jdouble*)(void*)buf; }
internal static jchar* GetCharArrayElements(JNIEnv* pEnv, jcharArray array, jboolean* isCopy) { char[] b = (char[])pEnv->UnwrapRef(array); IntPtr buf = JniMem.Alloc(b.Length * 2); Marshal.Copy(b, 0, buf, b.Length); if(isCopy != null) { *isCopy = JNI_TRUE; } return (jchar*)(void*)buf; }
internal static jbyte* GetByteArrayElements(JNIEnv* pEnv, jbyteArray array, jboolean* isCopy) { byte[] b = (byte[])pEnv->UnwrapRef(array); jbyte* p = (jbyte*)(void*)JniMem.Alloc(b.Length * 1); for(int i = 0; i < b.Length; i++) { p[i] = (jbyte)b[i]; } if(isCopy != null) { *isCopy = JNI_TRUE; } return p; }
internal static jdoubleArray NewDoubleArray(JNIEnv* pEnv, jsize len) { try { return pEnv->MakeLocalRef(new double[len]); } catch(Exception x) { SetPendingException(pEnv, x); return IntPtr.Zero; } }
internal static int GetJavaVM(JNIEnv* pEnv, JavaVM **ppJavaVM) { *ppJavaVM = JavaVM.pJavaVM; return JNI_OK; }
internal static void GetBooleanArrayRegion(JNIEnv* pEnv, IntPtr array, int start, int len, IntPtr buf) { try { bool[] b = (bool[])pEnv->UnwrapRef(array); sbyte* p = (sbyte*)(void*)buf; for(int i = 0; i < len; i++) { *p++ = b[start + i] ? JNI_TRUE : JNI_FALSE; } } catch(IndexOutOfRangeException) { SetPendingException(pEnv, new java.lang.ArrayIndexOutOfBoundsException()); } }
internal static void GetStringRegion(JNIEnv* pEnv, IntPtr str, int start, int len, IntPtr buf) { string s = (string)pEnv->UnwrapRef(str); if(s != null) { if(start < 0 || start > s.Length || s.Length - start < len) { SetPendingException(pEnv, new java.lang.StringIndexOutOfBoundsException()); return; } else { char* p = (char*)(void*)buf; // TODO isn't there a managed memcpy? for(int i = 0; i < len; i++) { *p++ = s[start + i]; } return; } } else { SetPendingException(pEnv, new java.lang.NullPointerException()); } }
internal static void SetByteArrayRegion(JNIEnv* pEnv, IntPtr array, int start, int len, IntPtr buf) { try { byte[] b = (byte[])pEnv->UnwrapRef(array); byte* p = (byte*)(void*)buf; for(int i = 0; i < len; i++) { b[start + i] = *p++; } } catch(IndexOutOfRangeException) { SetPendingException(pEnv, new java.lang.ArrayIndexOutOfBoundsException()); } }
internal static void* GetPrimitiveArrayCritical(JNIEnv* pEnv, jarray array, jboolean* isCopy) { Array ar = (Array)pEnv->UnwrapRef(array); if(pEnv->criticalArrayHandle1.Target == null) { pEnv->criticalArrayHandle1.Target = ar; if(isCopy != null) { *isCopy = JNI_FALSE; } return (void*)pEnv->criticalArrayHandle1.AddrOfPinnedObject(); } if(pEnv->criticalArrayHandle2.Target == null) { pEnv->criticalArrayHandle2.Target = ar; if(isCopy != null) { *isCopy = JNI_FALSE; } return (void*)pEnv->criticalArrayHandle2.AddrOfPinnedObject(); } // TODO not 64-bit safe (len can overflow) int len = ar.Length * GetPrimitiveArrayElementSize(ar); GCHandle h = GCHandle.Alloc(ar, GCHandleType.Pinned); try { IntPtr hglobal = JniMem.Alloc(len); byte* pdst = (byte*)(void*)hglobal; byte* psrc = (byte*)(void*)h.AddrOfPinnedObject(); // TODO isn't there a managed memcpy? for(int i = 0; i < len; i++) { *pdst++ = *psrc++; } if(isCopy != null) { *isCopy = JNI_TRUE; } return (void*)hglobal; } finally { h.Free(); } }
internal static void SetDoubleArrayRegion(JNIEnv* pEnv, IntPtr array, int start, int len, IntPtr buf) { try { double[] b = (double[])pEnv->UnwrapRef(array); Marshal.Copy(buf, b, start, len); } catch(ArgumentOutOfRangeException) { SetPendingException(pEnv, new java.lang.ArrayIndexOutOfBoundsException()); } }
internal static jchar* GetStringCritical(JNIEnv* pEnv, jstring str, jboolean* isCopy) { string s = (string)pEnv->UnwrapRef(str); if(s != null) { if(isCopy != null) { *isCopy = JNI_TRUE; } return (jchar*)(void*)Marshal.StringToHGlobalUni(s); } SetPendingException(pEnv, new java.lang.NullPointerException()); return null; }
internal static int RegisterNatives(JNIEnv* pEnv, IntPtr clazz, JNINativeMethod* methods, int nMethods) { try { TypeWrapper wrapper = TypeWrapper.FromClass((java.lang.Class)pEnv->UnwrapRef(clazz)); wrapper.Finish(); for(int i = 0; i < nMethods; i++) { string methodName = StringFromUTF8(methods[i].name); string methodSig = StringFromUTF8(methods[i].signature); Tracer.Info(Tracer.Jni, "Registering native method: {0}.{1}{2}, fnPtr = 0x{3:X}", wrapper.Name, methodName, methodSig, ((IntPtr)methods[i].fnPtr).ToInt64()); FieldInfo fi = null; // don't allow dotted names! if(methodSig.IndexOf('.') < 0) { // TODO this won't work when we're putting the JNI methods in jniproxy.dll fi = wrapper.TypeAsTBD.GetField(JNI.METHOD_PTR_FIELD_PREFIX + methodName + methodSig, BindingFlags.Static | BindingFlags.NonPublic); } if(fi == null) { Tracer.Error(Tracer.Jni, "Failed to register native method: {0}.{1}{2}", wrapper.Name, methodName, methodSig); SetPendingException(pEnv, new java.lang.NoSuchMethodError(methodName)); return JNI_ERR; } fi.SetValue(null, (IntPtr)methods[i].fnPtr); } return JNI_OK; } catch(RetargetableJavaException x) { SetPendingException(pEnv, x.ToJava()); return JNI_ERR; } catch(Exception x) { SetPendingException(pEnv, x); return JNI_ERR; } }
internal static jweak NewWeakGlobalRef(JNIEnv* pEnv, jobject obj) { object o = pEnv->UnwrapRef(obj); if(o == null) { return IntPtr.Zero; } lock(GlobalRefs.weakRefLock) { for(int i = 0; i < GlobalRefs.weakRefs.Length; i++) { if(!GlobalRefs.weakRefs[i].IsAllocated) { GlobalRefs.weakRefs[i] = GCHandle.Alloc(o, GCHandleType.WeakTrackResurrection); return (IntPtr)(- (i | (1 << 30))); } } int len = GlobalRefs.weakRefs.Length; GCHandle[] tmp = new GCHandle[len * 2]; Array.Copy(GlobalRefs.weakRefs, 0, tmp, 0, len); tmp[len] = GCHandle.Alloc(o, GCHandleType.WeakTrackResurrection); GlobalRefs.weakRefs = tmp; return (IntPtr)(- (len | (1 << 30))); } }
internal static int UnregisterNatives(JNIEnv* pEnv, IntPtr clazz) { try { TypeWrapper wrapper = TypeWrapper.FromClass((java.lang.Class)pEnv->UnwrapRef(clazz)); wrapper.Finish(); // TODO this won't work when we're putting the JNI methods in jniproxy.dll foreach(FieldInfo fi in wrapper.TypeAsTBD.GetFields(BindingFlags.Static | BindingFlags.NonPublic)) { string name = fi.Name; if(name.StartsWith(JNI.METHOD_PTR_FIELD_PREFIX)) { Tracer.Info(Tracer.Jni, "Unregistering native method: {0}.{1}", wrapper.Name, name.Substring(JNI.METHOD_PTR_FIELD_PREFIX.Length)); fi.SetValue(null, IntPtr.Zero); } } return JNI_OK; } catch(RetargetableJavaException x) { SetPendingException(pEnv, x.ToJava()); return JNI_ERR; } catch(Exception x) { SetPendingException(pEnv, x); return JNI_ERR; } }
internal static jboolean ExceptionCheck(JNIEnv* pEnv) { ManagedJNIEnv env = pEnv->GetManagedJNIEnv(); return env.pendingException != null ? JNI_TRUE : JNI_FALSE; }
internal static int MonitorEnter(JNIEnv* pEnv, IntPtr obj) { try { // on .NET 4.0 Monitor.Enter has been marked obsolete, // but in this case the alternative adds no value #pragma warning disable 618 System.Threading.Monitor.Enter(pEnv->UnwrapRef(obj)); #pragma warning restore 618 return JNI_OK; } catch(Exception x) { SetPendingException(pEnv, x); return JNI_ERR; } }
internal static IntPtr GetDirectBufferAddress(JNIEnv* pEnv, jobject buf) { try { return (IntPtr)((sun.nio.ch.DirectBuffer)pEnv->UnwrapRef(buf)).address(); } catch(Exception x) { SetPendingException(pEnv, ikvm.runtime.Util.mapException(x)); return IntPtr.Zero; } }
internal static int MonitorExit(JNIEnv* pEnv, IntPtr obj) { try { System.Threading.Monitor.Exit(pEnv->UnwrapRef(obj)); return JNI_OK; } catch(Exception x) { SetPendingException(pEnv, x); return JNI_ERR; } }
internal static int GetObjectRefType(JNIEnv* pEnv, jobject obj) { int i = obj.ToInt32(); if(i >= 0) { return JNILocalRefType; } i = -i; if((i & (1 << 30)) != 0) { return JNIWeakGlobalRefType; } else { return JNIGlobalRefType; } }
internal static jobject GetObjectArrayElement(JNIEnv* pEnv, jarray array, jsize index) { try { // we want to support (non-primitive) value types so we can't cast to object[] return pEnv->MakeLocalRef(((Array)pEnv->UnwrapRef(array)).GetValue(index)); } catch(IndexOutOfRangeException) { SetPendingException(pEnv, new java.lang.ArrayIndexOutOfBoundsException()); return IntPtr.Zero; } }