diff --git a/dub.json b/dub.json index f7b4c6e..2070dab 100644 --- a/dub.json +++ b/dub.json @@ -231,16 +231,16 @@ "importPaths": ["."], "dflags": ["-mv=arsd.http2=http2.d"], "configurations": [ - { - "name": "with_openssl", - "versions": ["with_openssl"], - "libs": ["crypto", "ssl"] - }, - { - "name": "without_openssl", - "versions": ["without_openssl"] - } - ] + { + "name": "with_openssl", + "versions": ["with_openssl"], + "libs": ["crypto", "ssl"] + }, + { + "name": "without_openssl", + "versions": ["without_openssl"] + } + ] }, { "name": "jsvar", @@ -250,6 +250,14 @@ "dflags": ["-mv=arsd.jsvar=jsvar.d"], "sourceFiles": ["jsvar.d"] }, + { + "name": "jni", + "description": "Provides easy interop with Java via JNI.", + "targetType": "library", + "importPaths": ["."], + "dflags": ["-mv=arsd.jni=jni.d"], + "sourceFiles": ["jni.d"] + }, { "name": "script", "description": "Small Javascript-like script interpreter with easy D API", diff --git a/jni.d b/jni.d new file mode 100644 index 0000000..c9b548e --- /dev/null +++ b/jni.d @@ -0,0 +1,806 @@ +/++ + Provides easy interoperability with Java code through JNI. + + ```java + class Hello { + public native void hi(String s); + public native String stringFromJNI(); + public native String returnNull(); + public native void throwException(); + static { + System.loadLibrary("myjni"); + } + public static void main(String[] args) { + System.out.println("Hello from Java!"); + Hello h = new Hello(); + // we can pass data back and forth normally + h.hi("jni"); + System.out.println(h.stringFromJNI()); + System.out.println(h.returnNull()); // it can handle null too + // and even forward exceptions (sort of, it puts it in a RuntimeException right now) + h.throwException(); + } + } + ``` + + --- + import arsd.jni; + + // if it was in a Java package, you'd pass that + // in the string here instead of "". + final class Hello : JavaClass!("", Hello) { + + @Export string stringFromJNI() { + return "hey, D returned this"; + } + + @Export string returnNull() { + return null; + } + + @Export void throwException() { + throw new Exception("exception from D"); + } + + @Export void hi(string name) { + import std.stdio; + writefln("hello from D, %s", name); + } + } + --- + + $(CONSOLE + $ javac Hello.java + $ dmd -shared myjni.d jni.d # compile into a shared lib + $ LD_LIBRARY_PATH=. java Hello + Hello from Java! + hello from D, jni + hey, D returned this + null + Exception in thread "main" java.lang.RuntimeException: object.Exception@myjni.d(14): exception from D + ---------------- + ??:? void myjni.Hello.throwException() [0x7f51d86dc17b] + ??:? Java_Hello_throwException [0x7f51d86dd3e0] + ??:? [0x7f51dd018406] + ??:? [0x7f51dd007ffc] + ??:? [0x7f51dd0004e6] + ??:? [0x7f51f16b0709] + ??:? [0x7f51f16c1339] + ??:? [0x7f51f16d208d] + ??:? [0x7f51f1f97058] + ??:? [0x7f51f1fae06a] + at Hello.throwException(Native Method) + at Hello.main(Hello.java:17) + ) + + Exact details subject to change, especially of how I pass the exceptions over. + + Calling Java methods from D coming later. + + + $(WARNING + ALL references passed to you through Java, including + arrays, objects, and even the `this` pointer, MUST NOT + be stored outside the lifetime of the immediate function + they were passed to! + + You may be able to get the D compiler to help you with + this with the scope attribute, but regardless, don't + do it. + ) + + It is YOUR responsibility to make sure parameter and return types + match between D and Java. The library will `static assert` given + unrepresentable types, but it cannot see what Java actually expects. + Getting this wrong can lead to memory corruption and crashes. + + $(TIP + When possible, use `wstring` instead of `string` when + working with Java APIs. `wstring` matches the format + of Java's `String` so it avoids a conversion step. + ) + + All [JavaClass] sub-objects should be marked `final` on the D + side. Java may subclass them, but D can't (at least not now). + + Do not use default arguments on the exported methods. No promise + the wrapper will do what you want when called from Java. + + You may choose to only import JavaClass from here to minimize the + namespace pollution. + ++/ +module arsd.jni; + +// see: https://developer.android.com/training/articles/perf-jni.html + +// FIXME: do these work on Windows? +// FIXME: put this in a mixin instead of assuming it is needed/wanted? +pragma(crt_constructor) +extern(C) +void initializeDRuntime() { + import core.runtime; + //import core.stdc.stdio; printf("here\n"); + Runtime.initialize(); +} + +pragma(crt_destructor) +extern(C) +void uninitializeDRuntime() { + import core.runtime; + //import core.stdc.stdio; printf("gone\n"); + Runtime.terminate(); +} + +// FIXME make a start JVM function + +private mixin template JavaImportImpl(T, alias method) { + static assert(0, "@Import not yet implemented"); // FIXME + import std.traits; + pragma(mangle, method.mangleof) + private static ReturnType!method implementation(Parameters!method args, T this_) { + // FIXME. need to get the jni env to this somehow, remembering it gets invalidated easily + static if(is(typeof(return) == void)) + {} + else + return typeof(return); + } +} + +private template DTypesToJni(Types...) { + static if(Types.length == 0) + alias DTypesToJni = Types; + else static if(Types.length == 1) { + alias T = Types[0]; + + static if(is(T == void)) + alias DTypesToJni = void; + else static if(is(T == string)) + alias DTypesToJni = jstring; + else static if(is(T == wstring)) + alias DTypesToJni = jstring; + else static if(is(T == int)) + alias DTypesToJni = jint; + else static if(is(T == bool)) + alias DTypesToJni = jboolean; + else static if(is(T == byte)) + alias DTypesToJni = jbyte; + else static if(is(T == wchar)) + alias DTypesToJni = jchar; + else static if(is(T == short)) + alias DTypesToJni = jshort; + else static if(is(T == long)) + alias DTypesToJni = jlong; + else static if(is(T == float)) + alias DTypesToJni = jfloat; + else static if(is(T == double)) + alias DTypesToJni = jdouble; + else static if(is(T == size_t)) + alias DTypesToJni = jsize; + else static if(is(T == jobject)) + alias DTypesToJni = IJavaObject; + else static if(is(T == IJavaObject[])) + alias DTypesToJni = jobjectArray; + else static if(is(T == bool[])) + alias DTypesToJni = jbooleanArray; + else static if(is(T == byte[])) + alias DTypesToJni = jbyteArray; + else static if(is(T == wchar[])) + alias DTypesToJni = jcharArray; + else static if(is(T == short[])) + alias DTypesToJni = jshortArray; + else static if(is(T == int[])) + alias DTypesToJni = jintArray; + else static if(is(T == long[])) + alias DTypesToJni = jlongArray; + else static if(is(T == float[])) + alias DTypesToJni = jfloatArray; + else static if(is(T == double[])) + alias DTypesToJni = jdoubleArray; + else static assert(0, "Unsupported type for JNI " ~ T.stringof); + } else { + import std.typecons; + alias DTypesToJni = AliasSeq!(DTypesToJni!(Types[0]), DTypesToJni(Types[1 .. $])); + } +} + +auto DDataToJni(T)(JNIEnv* env, T data) { + static if(is(T == void)) + static assert(0); + else static if(is(T == string)) { + if(data is null) + return null; + wchar[1024] buffer; + const(wchar)[] translated; + if(data.length < 1024) { + size_t len; + foreach(wchar ch; data) + buffer[len++] = ch; + translated = buffer[0 .. len]; + } else { + import std.conv; + translated = to!wstring(data); + } + // Java copies the buffer so it is perfectly fine to return here now + return (*env).NewString(env, translated.ptr, cast(jsize) translated.length); + } else static if(is(T == wstring)) + return (*env).NewString(env, data.ptr, cast(jsize) data.length); + else static if(is(T == int)) return data; + else static if(is(T == bool)) return data; + else static if(is(T == byte)) return data; + else static if(is(T == wchar)) return data; + else static if(is(T == short)) return data; + else static if(is(T == long)) return data; + else static if(is(T == float)) return data; + else static if(is(T == double)) return data; + else static if(is(T == size_t)) return cast(int) data; + else static if(is(T : IJavaObject)) return data.getJavaHandle(); + else static assert(0, "Unsupported type " ~ T.stringof); + /* // FIXME: finish these + else static if(is(T == IJavaObject[])) + alias DTypesToJni = jobjectArray; + else static if(is(T == bool[])) + alias DTypesToJni = jbooleanArray; + else static if(is(T == byte[])) + alias DTypesToJni = jbyteArray; + else static if(is(T == wchar[])) + alias DTypesToJni = jcharArray; + else static if(is(T == short[])) + alias DTypesToJni = jshortArray; + else static if(is(T == int[])) + alias DTypesToJni = jintArray; + else static if(is(T == long[])) + alias DTypesToJni = jlongArray; + else static if(is(T == float[])) + alias DTypesToJni = jfloatArray; + else static if(is(T == double[])) + alias DTypesToJni = jdoubleArray; + */ + +} + +private struct JavaParamsToD(Spec...) { + import std.meta; + + Spec args; + AliasSeq!(DTypesToJni!Spec) jargs; + JNIEnv* env; + + ~this() { + // import core.stdc.stdio; printf("dtor\n"); + + // any time we sliced the Java object directly, we need to clean it up + // so this must stay in sync with the constructor's logic + foreach(idx, arg; args) { + static if(is(typeof(arg) == wstring)) { + // also need to check for null. not allowed to release null + if(arg.ptr !is null) { + auto jarg = jargs[idx]; + (*env).ReleaseStringChars(env, jarg, arg.ptr); + } + } + } + } + + this(JNIEnv* env, AliasSeq!(DTypesToJni!Spec) jargs) { + this.jargs = jargs; + this.env = env; + + foreach(idx, ref arg; args) { + auto jarg = jargs[idx]; + alias T = typeof(arg); + alias J = typeof(jarg); + + static if(__traits(compiles, arg = jarg)) + arg = jarg; + else static if(is(T == size_t)) { + static assert(is(J == jsize)); + arg = cast(size_t) jarg; + } else static if(is(T == string) || is(T == wstring)) { + static assert(is(J == jstring)); + auto len = (*env).GetStringLength(env, jarg); + auto ptr = (*env).GetStringChars(env, jarg, null); + // java strings are immutable so this should be fine + // just remember the lifetime limitation... which is also + // why i am ok + static if(is(T == wstring)) { + if(ptr !is null) + arg = ptr[0 .. len]; + } else { + /* + // I actually can't do this little buffer here + // because this helper function will return before + // it is used. yikes. + char[1024] buffer; + int blen; + if(len < buffer.length / 4) { + foreach(char c; ptr[0 .. len]) + buffer[blen++] = c; + arg = buffer[0 .. blen]; + } else { + arg = to!string(ptr[0 .. len]); + } + */ + import std.conv; + if(ptr !is null) { + arg = to!string(ptr[0 .. len]); + (*env).ReleaseStringChars(env, jarg, ptr); + } + } + } + // FIXME other types of arrays + //else static if(is(T : IJavaObject)) return data.getJavaHandle(); // create the D object, hook in the handle, do some kind of type check from the Java class name. + else static assert(0, "Unimplemented/unsupported type " ~ T.stringof); + + } + } +} + +void jniRethrow(JNIEnv* env, Throwable t) { + (*env).ThrowNew( + env, + (*env).FindClass(env, "java/lang/RuntimeException"), + (t.toString() ~ "\0").ptr + ); +} + +private mixin template JavaExportImpl(T, alias method) { + import std.traits; + import std.string; + + static private string JniMangle() { + static if(is(T : JavaClass!(JP, P), string JP, P)) + return "Java_" ~replace(JP, ".", "_") ~ (JP.length ? "_" : "") ~ P.stringof ~ "_" ~ __traits(identifier, method); + else static assert(0); + } + + extern(C) + pragma(mangle, JniMangle()) + // I need it in the DLL, but want it to be not accessible from outside... alas. + export /*private*/ static DTypesToJni!(ReturnType!method) privateJniImplementation(JNIEnv* env, jobject obj, DTypesToJni!(Parameters!method) args) { + // FIXME: efficiency and possibly pull the same object again if possible + auto dobj = new T(); + dobj.internalJavaHandle_ = obj; + + // getMember(identifer) is weird but i want to get the method on this + // particular instance and it feels less hacky than doing the delegate + + static if(is(typeof(return) == void)) { + try { + __traits(getMember, dobj, __traits(identifier, method))(JavaParamsToD!(Parameters!method)(env, args).args); + } catch(Throwable t) { + jniRethrow(env, t); + } + } else { + try { + return DDataToJni(env, __traits(getMember, dobj, __traits(identifier, method))(JavaParamsToD!(Parameters!method)(env, args).args)); + } catch(Throwable t) { + jniRethrow(env, t); + return typeof(return).init; // still required to return... + } + } + } +} + +/++ + This is really used by the [JavaClass] class below to give a base for all Java classes. + You can use it for that too, but you really shouldn't try to implement it yourself + (it doesn't do much anyway). ++/ +interface IJavaObject { + /// Remember the returned object is a TEMPORARY local reference! + protected jobject getJavaHandle(); +} + +/++ + This is the base class you inherit from in D classes that represent Java classes. + You can then mark your methods @Import if they are implemented in Java and you want + to call them from D, or @Export if they are implemented in D and want to be called + as a `native` method from Java. + + Methods marked without either of these signifiers are not associated with Java. + + You should not expect any instance data on these to survive function calls, since + associating it back with Java across calls may be impossible. ++/ +class JavaClass(string javaPackage, CRTP) : IJavaObject { + enum Import; /// UDA to indicate you are importing the method from Java. Do NOT put a body on these methods. + enum Export; /// UDA to indicate you are exporting the method to Java. Put a D implementation body on these. + + static foreach(memberName; __traits(derivedMembers, CRTP)) + static foreach(attr; __traits(getAttributes, __traits(getMember, CRTP, memberName))) { + static if(is(attr == Import)) + mixin JavaImportImpl!(CRTP, __traits(getMember, CRTP, memberName)); + else static if(is(attr == Export)) + mixin JavaExportImpl!(CRTP, __traits(getMember, CRTP, memberName)); + } + + protected jobject internalJavaHandle_; + protected jobject getJavaHandle() { return internalJavaHandle_; } +} + + + + + + + + + + + + + + + + + +// Mechanically translated header below. +// You can use it yourself if you need low level access to JNI. + + + +import core.stdc.stdarg; + +//version (Android): +extern (C): +@system: +nothrow: +@nogc: + +alias bool jboolean; +alias byte jbyte; +alias wchar jchar; +alias short jshort; +alias int jint; +alias long jlong; +alias float jfloat; +alias double jdouble; +alias jint jsize; +alias void* jobject; +alias jobject jclass; +alias jobject jstring; +alias jobject jarray; +alias jarray jobjectArray; +alias jarray jbooleanArray; +alias jarray jbyteArray; +alias jarray jcharArray; +alias jarray jshortArray; +alias jarray jintArray; +alias jarray jlongArray; +alias jarray jfloatArray; +alias jarray jdoubleArray; +alias jobject jthrowable; +alias jobject jweak; +alias _jfieldID* jfieldID; +alias _jmethodID* jmethodID; +alias const(JNINativeInterface)* C_JNIEnv; +alias const(JNINativeInterface)* JNIEnv; +alias const(JNIInvokeInterface)* JavaVM; + +enum jobjectRefType +{ + JNIInvalidRefType = 0, + JNILocalRefType = 1, + JNIGlobalRefType = 2, + JNIWeakGlobalRefType = 3 +} + +enum JNI_FALSE = 0; +enum JNI_TRUE = 1; +enum JNI_VERSION_1_1 = 0x00010001; +enum JNI_VERSION_1_2 = 0x00010002; +enum JNI_VERSION_1_4 = 0x00010004; +enum JNI_VERSION_1_6 = 0x00010006; +enum JNI_OK = 0; +enum JNI_ERR = -1; +enum JNI_EDETACHED = -2; +enum JNI_EVERSION = -3; +enum JNI_COMMIT = 1; +enum JNI_ABORT = 2; + +struct JNINativeMethod +{ + const(char)* name; + const(char)* signature; + void* fnPtr; +} + +struct JNINativeInterface +{ + void* reserved0; + void* reserved1; + void* reserved2; + void* reserved3; + jint function(JNIEnv*) GetVersion; + jclass function(JNIEnv*, const(char)*, jobject, const(jbyte)*, jsize) DefineClass; + jclass function(JNIEnv*, const(char)*) FindClass; + jmethodID function(JNIEnv*, jobject) FromReflectedMethod; + jfieldID function(JNIEnv*, jobject) FromReflectedField; + jobject function(JNIEnv*, jclass, jmethodID, jboolean) ToReflectedMethod; + jclass function(JNIEnv*, jclass) GetSuperclass; + jboolean function(JNIEnv*, jclass, jclass) IsAssignableFrom; + jobject function(JNIEnv*, jclass, jfieldID, jboolean) ToReflectedField; + jint function(JNIEnv*, jthrowable) Throw; + jint function(JNIEnv*, jclass, const(char)*) ThrowNew; + jthrowable function(JNIEnv*) ExceptionOccurred; + void function(JNIEnv*) ExceptionDescribe; + void function(JNIEnv*) ExceptionClear; + void function(JNIEnv*, const(char)*) FatalError; + jint function(JNIEnv*, jint) PushLocalFrame; + jobject function(JNIEnv*, jobject) PopLocalFrame; + jobject function(JNIEnv*, jobject) NewGlobalRef; + void function(JNIEnv*, jobject) DeleteGlobalRef; + void function(JNIEnv*, jobject) DeleteLocalRef; + jboolean function(JNIEnv*, jobject, jobject) IsSameObject; + jobject function(JNIEnv*, jobject) NewLocalRef; + jint function(JNIEnv*, jint) EnsureLocalCapacity; + jobject function(JNIEnv*, jclass) AllocObject; + jobject function(JNIEnv*, jclass, jmethodID, ...) NewObject; + jobject function(JNIEnv*, jclass, jmethodID, va_list) NewObjectV; + jobject function(JNIEnv*, jclass, jmethodID, jvalue*) NewObjectA; + jclass function(JNIEnv*, jobject) GetObjectClass; + jboolean function(JNIEnv*, jobject, jclass) IsInstanceOf; + jmethodID function(JNIEnv*, jclass, const(char)*, const(char)*) GetMethodID; + jobject function(JNIEnv*, jobject, jmethodID, ...) CallObjectMethod; + jobject function(JNIEnv*, jobject, jmethodID, va_list) CallObjectMethodV; + jobject function(JNIEnv*, jobject, jmethodID, jvalue*) CallObjectMethodA; + jboolean function(JNIEnv*, jobject, jmethodID, ...) CallBooleanMethod; + jboolean function(JNIEnv*, jobject, jmethodID, va_list) CallBooleanMethodV; + jboolean function(JNIEnv*, jobject, jmethodID, jvalue*) CallBooleanMethodA; + jbyte function(JNIEnv*, jobject, jmethodID, ...) CallByteMethod; + jbyte function(JNIEnv*, jobject, jmethodID, va_list) CallByteMethodV; + jbyte function(JNIEnv*, jobject, jmethodID, jvalue*) CallByteMethodA; + jchar function(JNIEnv*, jobject, jmethodID, ...) CallCharMethod; + jchar function(JNIEnv*, jobject, jmethodID, va_list) CallCharMethodV; + jchar function(JNIEnv*, jobject, jmethodID, jvalue*) CallCharMethodA; + jshort function(JNIEnv*, jobject, jmethodID, ...) CallShortMethod; + jshort function(JNIEnv*, jobject, jmethodID, va_list) CallShortMethodV; + jshort function(JNIEnv*, jobject, jmethodID, jvalue*) CallShortMethodA; + jint function(JNIEnv*, jobject, jmethodID, ...) CallIntMethod; + jint function(JNIEnv*, jobject, jmethodID, va_list) CallIntMethodV; + jint function(JNIEnv*, jobject, jmethodID, jvalue*) CallIntMethodA; + jlong function(JNIEnv*, jobject, jmethodID, ...) CallLongMethod; + jlong function(JNIEnv*, jobject, jmethodID, va_list) CallLongMethodV; + jlong function(JNIEnv*, jobject, jmethodID, jvalue*) CallLongMethodA; + jfloat function(JNIEnv*, jobject, jmethodID, ...) CallFloatMethod; + jfloat function(JNIEnv*, jobject, jmethodID, va_list) CallFloatMethodV; + jfloat function(JNIEnv*, jobject, jmethodID, jvalue*) CallFloatMethodA; + jdouble function(JNIEnv*, jobject, jmethodID, ...) CallDoubleMethod; + jdouble function(JNIEnv*, jobject, jmethodID, va_list) CallDoubleMethodV; + jdouble function(JNIEnv*, jobject, jmethodID, jvalue*) CallDoubleMethodA; + void function(JNIEnv*, jobject, jmethodID, ...) CallVoidMethod; + void function(JNIEnv*, jobject, jmethodID, va_list) CallVoidMethodV; + void function(JNIEnv*, jobject, jmethodID, jvalue*) CallVoidMethodA; + jobject function(JNIEnv*, jobject, jclass, jmethodID, ...) CallNonvirtualObjectMethod; + jobject function(JNIEnv*, jobject, jclass, jmethodID, va_list) CallNonvirtualObjectMethodV; + jobject function(JNIEnv*, jobject, jclass, jmethodID, jvalue*) CallNonvirtualObjectMethodA; + jboolean function(JNIEnv*, jobject, jclass, jmethodID, ...) CallNonvirtualBooleanMethod; + jboolean function(JNIEnv*, jobject, jclass, jmethodID, va_list) CallNonvirtualBooleanMethodV; + jboolean function(JNIEnv*, jobject, jclass, jmethodID, jvalue*) CallNonvirtualBooleanMethodA; + jbyte function(JNIEnv*, jobject, jclass, jmethodID, ...) CallNonvirtualByteMethod; + jbyte function(JNIEnv*, jobject, jclass, jmethodID, va_list) CallNonvirtualByteMethodV; + jbyte function(JNIEnv*, jobject, jclass, jmethodID, jvalue*) CallNonvirtualByteMethodA; + jchar function(JNIEnv*, jobject, jclass, jmethodID, ...) CallNonvirtualCharMethod; + jchar function(JNIEnv*, jobject, jclass, jmethodID, va_list) CallNonvirtualCharMethodV; + jchar function(JNIEnv*, jobject, jclass, jmethodID, jvalue*) CallNonvirtualCharMethodA; + jshort function(JNIEnv*, jobject, jclass, jmethodID, ...) CallNonvirtualShortMethod; + jshort function(JNIEnv*, jobject, jclass, jmethodID, va_list) CallNonvirtualShortMethodV; + jshort function(JNIEnv*, jobject, jclass, jmethodID, jvalue*) CallNonvirtualShortMethodA; + jint function(JNIEnv*, jobject, jclass, jmethodID, ...) CallNonvirtualIntMethod; + jint function(JNIEnv*, jobject, jclass, jmethodID, va_list) CallNonvirtualIntMethodV; + jint function(JNIEnv*, jobject, jclass, jmethodID, jvalue*) CallNonvirtualIntMethodA; + jlong function(JNIEnv*, jobject, jclass, jmethodID, ...) CallNonvirtualLongMethod; + jlong function(JNIEnv*, jobject, jclass, jmethodID, va_list) CallNonvirtualLongMethodV; + jlong function(JNIEnv*, jobject, jclass, jmethodID, jvalue*) CallNonvirtualLongMethodA; + jfloat function(JNIEnv*, jobject, jclass, jmethodID, ...) CallNonvirtualFloatMethod; + jfloat function(JNIEnv*, jobject, jclass, jmethodID, va_list) CallNonvirtualFloatMethodV; + jfloat function(JNIEnv*, jobject, jclass, jmethodID, jvalue*) CallNonvirtualFloatMethodA; + jdouble function(JNIEnv*, jobject, jclass, jmethodID, ...) CallNonvirtualDoubleMethod; + jdouble function(JNIEnv*, jobject, jclass, jmethodID, va_list) CallNonvirtualDoubleMethodV; + jdouble function(JNIEnv*, jobject, jclass, jmethodID, jvalue*) CallNonvirtualDoubleMethodA; + void function(JNIEnv*, jobject, jclass, jmethodID, ...) CallNonvirtualVoidMethod; + void function(JNIEnv*, jobject, jclass, jmethodID, va_list) CallNonvirtualVoidMethodV; + void function(JNIEnv*, jobject, jclass, jmethodID, jvalue*) CallNonvirtualVoidMethodA; + jfieldID function(JNIEnv*, jclass, const(char)*, const(char)*) GetFieldID; + jobject function(JNIEnv*, jobject, jfieldID) GetObjectField; + jboolean function(JNIEnv*, jobject, jfieldID) GetBooleanField; + jbyte function(JNIEnv*, jobject, jfieldID) GetByteField; + jchar function(JNIEnv*, jobject, jfieldID) GetCharField; + jshort function(JNIEnv*, jobject, jfieldID) GetShortField; + jint function(JNIEnv*, jobject, jfieldID) GetIntField; + jlong function(JNIEnv*, jobject, jfieldID) GetLongField; + jfloat function(JNIEnv*, jobject, jfieldID) GetFloatField; + jdouble function(JNIEnv*, jobject, jfieldID) GetDoubleField; + void function(JNIEnv*, jobject, jfieldID, jobject) SetObjectField; + void function(JNIEnv*, jobject, jfieldID, jboolean) SetBooleanField; + void function(JNIEnv*, jobject, jfieldID, jbyte) SetByteField; + void function(JNIEnv*, jobject, jfieldID, jchar) SetCharField; + void function(JNIEnv*, jobject, jfieldID, jshort) SetShortField; + void function(JNIEnv*, jobject, jfieldID, jint) SetIntField; + void function(JNIEnv*, jobject, jfieldID, jlong) SetLongField; + void function(JNIEnv*, jobject, jfieldID, jfloat) SetFloatField; + void function(JNIEnv*, jobject, jfieldID, jdouble) SetDoubleField; + jmethodID function(JNIEnv*, jclass, const(char)*, const(char)*) GetStaticMethodID; + jobject function(JNIEnv*, jclass, jmethodID, ...) CallStaticObjectMethod; + jobject function(JNIEnv*, jclass, jmethodID, va_list) CallStaticObjectMethodV; + jobject function(JNIEnv*, jclass, jmethodID, jvalue*) CallStaticObjectMethodA; + jboolean function(JNIEnv*, jclass, jmethodID, ...) CallStaticBooleanMethod; + jboolean function(JNIEnv*, jclass, jmethodID, va_list) CallStaticBooleanMethodV; + jboolean function(JNIEnv*, jclass, jmethodID, jvalue*) CallStaticBooleanMethodA; + jbyte function(JNIEnv*, jclass, jmethodID, ...) CallStaticByteMethod; + jbyte function(JNIEnv*, jclass, jmethodID, va_list) CallStaticByteMethodV; + jbyte function(JNIEnv*, jclass, jmethodID, jvalue*) CallStaticByteMethodA; + jchar function(JNIEnv*, jclass, jmethodID, ...) CallStaticCharMethod; + jchar function(JNIEnv*, jclass, jmethodID, va_list) CallStaticCharMethodV; + jchar function(JNIEnv*, jclass, jmethodID, jvalue*) CallStaticCharMethodA; + jshort function(JNIEnv*, jclass, jmethodID, ...) CallStaticShortMethod; + jshort function(JNIEnv*, jclass, jmethodID, va_list) CallStaticShortMethodV; + jshort function(JNIEnv*, jclass, jmethodID, jvalue*) CallStaticShortMethodA; + jint function(JNIEnv*, jclass, jmethodID, ...) CallStaticIntMethod; + jint function(JNIEnv*, jclass, jmethodID, va_list) CallStaticIntMethodV; + jint function(JNIEnv*, jclass, jmethodID, jvalue*) CallStaticIntMethodA; + jlong function(JNIEnv*, jclass, jmethodID, ...) CallStaticLongMethod; + jlong function(JNIEnv*, jclass, jmethodID, va_list) CallStaticLongMethodV; + jlong function(JNIEnv*, jclass, jmethodID, jvalue*) CallStaticLongMethodA; + jfloat function(JNIEnv*, jclass, jmethodID, ...) CallStaticFloatMethod; + jfloat function(JNIEnv*, jclass, jmethodID, va_list) CallStaticFloatMethodV; + jfloat function(JNIEnv*, jclass, jmethodID, jvalue*) CallStaticFloatMethodA; + jdouble function(JNIEnv*, jclass, jmethodID, ...) CallStaticDoubleMethod; + jdouble function(JNIEnv*, jclass, jmethodID, va_list) CallStaticDoubleMethodV; + jdouble function(JNIEnv*, jclass, jmethodID, jvalue*) CallStaticDoubleMethodA; + void function(JNIEnv*, jclass, jmethodID, ...) CallStaticVoidMethod; + void function(JNIEnv*, jclass, jmethodID, va_list) CallStaticVoidMethodV; + void function(JNIEnv*, jclass, jmethodID, jvalue*) CallStaticVoidMethodA; + jfieldID function(JNIEnv*, jclass, const(char)*, const(char)*) GetStaticFieldID; + jobject function(JNIEnv*, jclass, jfieldID) GetStaticObjectField; + jboolean function(JNIEnv*, jclass, jfieldID) GetStaticBooleanField; + jbyte function(JNIEnv*, jclass, jfieldID) GetStaticByteField; + jchar function(JNIEnv*, jclass, jfieldID) GetStaticCharField; + jshort function(JNIEnv*, jclass, jfieldID) GetStaticShortField; + jint function(JNIEnv*, jclass, jfieldID) GetStaticIntField; + jlong function(JNIEnv*, jclass, jfieldID) GetStaticLongField; + jfloat function(JNIEnv*, jclass, jfieldID) GetStaticFloatField; + jdouble function(JNIEnv*, jclass, jfieldID) GetStaticDoubleField; + void function(JNIEnv*, jclass, jfieldID, jobject) SetStaticObjectField; + void function(JNIEnv*, jclass, jfieldID, jboolean) SetStaticBooleanField; + void function(JNIEnv*, jclass, jfieldID, jbyte) SetStaticByteField; + void function(JNIEnv*, jclass, jfieldID, jchar) SetStaticCharField; + void function(JNIEnv*, jclass, jfieldID, jshort) SetStaticShortField; + void function(JNIEnv*, jclass, jfieldID, jint) SetStaticIntField; + void function(JNIEnv*, jclass, jfieldID, jlong) SetStaticLongField; + void function(JNIEnv*, jclass, jfieldID, jfloat) SetStaticFloatField; + void function(JNIEnv*, jclass, jfieldID, jdouble) SetStaticDoubleField; + jstring function(JNIEnv*, const(jchar)*, jsize) NewString; + jsize function(JNIEnv*, jstring) GetStringLength; + const(jchar)* function(JNIEnv*, jstring, jboolean*) GetStringChars; + void function(JNIEnv*, jstring, const(jchar)*) ReleaseStringChars; + jstring function(JNIEnv*, const(char)*) NewStringUTF; + jsize function(JNIEnv*, jstring) GetStringUTFLength; + const(char)* function(JNIEnv*, jstring, jboolean*) GetStringUTFChars; + void function(JNIEnv*, jstring, const(char)*) ReleaseStringUTFChars; + jsize function(JNIEnv*, jarray) GetArrayLength; + jobjectArray function(JNIEnv*, jsize, jclass, jobject) NewObjectArray; + jobject function(JNIEnv*, jobjectArray, jsize) GetObjectArrayElement; + void function(JNIEnv*, jobjectArray, jsize, jobject) SetObjectArrayElement; + jbooleanArray function(JNIEnv*, jsize) NewBooleanArray; + jbyteArray function(JNIEnv*, jsize) NewByteArray; + jcharArray function(JNIEnv*, jsize) NewCharArray; + jshortArray function(JNIEnv*, jsize) NewShortArray; + jintArray function(JNIEnv*, jsize) NewIntArray; + jlongArray function(JNIEnv*, jsize) NewLongArray; + jfloatArray function(JNIEnv*, jsize) NewFloatArray; + jdoubleArray function(JNIEnv*, jsize) NewDoubleArray; + jboolean* function(JNIEnv*, jbooleanArray, jboolean*) GetBooleanArrayElements; + jbyte* function(JNIEnv*, jbyteArray, jboolean*) GetByteArrayElements; + jchar* function(JNIEnv*, jcharArray, jboolean*) GetCharArrayElements; + jshort* function(JNIEnv*, jshortArray, jboolean*) GetShortArrayElements; + jint* function(JNIEnv*, jintArray, jboolean*) GetIntArrayElements; + jlong* function(JNIEnv*, jlongArray, jboolean*) GetLongArrayElements; + jfloat* function(JNIEnv*, jfloatArray, jboolean*) GetFloatArrayElements; + jdouble* function(JNIEnv*, jdoubleArray, jboolean*) GetDoubleArrayElements; + void function(JNIEnv*, jbooleanArray, jboolean*, jint) ReleaseBooleanArrayElements; + void function(JNIEnv*, jbyteArray, jbyte*, jint) ReleaseByteArrayElements; + void function(JNIEnv*, jcharArray, jchar*, jint) ReleaseCharArrayElements; + void function(JNIEnv*, jshortArray, jshort*, jint) ReleaseShortArrayElements; + void function(JNIEnv*, jintArray, jint*, jint) ReleaseIntArrayElements; + void function(JNIEnv*, jlongArray, jlong*, jint) ReleaseLongArrayElements; + void function(JNIEnv*, jfloatArray, jfloat*, jint) ReleaseFloatArrayElements; + void function(JNIEnv*, jdoubleArray, jdouble*, jint) ReleaseDoubleArrayElements; + void function(JNIEnv*, jbooleanArray, jsize, jsize, jboolean*) GetBooleanArrayRegion; + void function(JNIEnv*, jbyteArray, jsize, jsize, jbyte*) GetByteArrayRegion; + void function(JNIEnv*, jcharArray, jsize, jsize, jchar*) GetCharArrayRegion; + void function(JNIEnv*, jshortArray, jsize, jsize, jshort*) GetShortArrayRegion; + void function(JNIEnv*, jintArray, jsize, jsize, jint*) GetIntArrayRegion; + void function(JNIEnv*, jlongArray, jsize, jsize, jlong*) GetLongArrayRegion; + void function(JNIEnv*, jfloatArray, jsize, jsize, jfloat*) GetFloatArrayRegion; + void function(JNIEnv*, jdoubleArray, jsize, jsize, jdouble*) GetDoubleArrayRegion; + void function(JNIEnv*, jbooleanArray, jsize, jsize, const(jboolean)*) SetBooleanArrayRegion; + void function(JNIEnv*, jbyteArray, jsize, jsize, const(jbyte)*) SetByteArrayRegion; + void function(JNIEnv*, jcharArray, jsize, jsize, const(jchar)*) SetCharArrayRegion; + void function(JNIEnv*, jshortArray, jsize, jsize, const(jshort)*) SetShortArrayRegion; + void function(JNIEnv*, jintArray, jsize, jsize, const(jint)*) SetIntArrayRegion; + void function(JNIEnv*, jlongArray, jsize, jsize, const(jlong)*) SetLongArrayRegion; + void function(JNIEnv*, jfloatArray, jsize, jsize, const(jfloat)*) SetFloatArrayRegion; + void function(JNIEnv*, jdoubleArray, jsize, jsize, const(jdouble)*) SetDoubleArrayRegion; + jint function(JNIEnv*, jclass, const(JNINativeMethod)*, jint) RegisterNatives; + jint function(JNIEnv*, jclass) UnregisterNatives; + jint function(JNIEnv*, jobject) MonitorEnter; + jint function(JNIEnv*, jobject) MonitorExit; + jint function(JNIEnv*, JavaVM**) GetJavaVM; + void function(JNIEnv*, jstring, jsize, jsize, jchar*) GetStringRegion; + void function(JNIEnv*, jstring, jsize, jsize, char*) GetStringUTFRegion; + void* function(JNIEnv*, jarray, jboolean*) GetPrimitiveArrayCritical; + void function(JNIEnv*, jarray, void*, jint) ReleasePrimitiveArrayCritical; + const(jchar)* function(JNIEnv*, jstring, jboolean*) GetStringCritical; + void function(JNIEnv*, jstring, const(jchar)*) ReleaseStringCritical; + jweak function(JNIEnv*, jobject) NewWeakGlobalRef; + void function(JNIEnv*, jweak) DeleteWeakGlobalRef; + jboolean function(JNIEnv*) ExceptionCheck; + jobject function(JNIEnv*, void*, jlong) NewDirectByteBuffer; + void* function(JNIEnv*, jobject) GetDirectBufferAddress; + jlong function(JNIEnv*, jobject) GetDirectBufferCapacity; + jobjectRefType function(JNIEnv*, jobject) GetObjectRefType; +} + +struct _JNIEnv +{ + const(JNINativeInterface)* functions; +} + +struct JNIInvokeInterface +{ + void* reserved0; + void* reserved1; + void* reserved2; + jint function(JavaVM*) DestroyJavaVM; + jint function(JavaVM*, JNIEnv**, void*) AttachCurrentThread; + jint function(JavaVM*) DetachCurrentThread; + jint function(JavaVM*, void**, jint) GetEnv; + jint function(JavaVM*, JNIEnv**, void*) AttachCurrentThreadAsDaemon; +} + +struct _JavaVM +{ + const(JNIInvokeInterface)* functions; +} + +struct JavaVMAttachArgs +{ + jint version_; + const(char)* name; + jobject group; +} + +struct JavaVMOption +{ + const(char)* optionString; + void* extraInfo; +} + +struct JavaVMInitArgs +{ + jint version_; + jint nOptions; + JavaVMOption* options; + jboolean ignoreUnrecognized; +} + +struct _jfieldID; +struct _jmethodID; + +union jvalue +{ + jboolean z; + jbyte b; + jchar c; + jshort s; + jint i; + jlong j; + jfloat f; + jdouble d; + jobject l; +} + +jint JNI_OnLoad(JavaVM* vm, void* reserved); +void JNI_OnUnload(JavaVM* vm, void* reserved);