X-Git-Url: http://nitlanguage.org diff --git a/lib/jvm.nit b/lib/jvm.nit index 62cebe1..692a1c9 100644 --- a/lib/jvm.nit +++ b/lib/jvm.nit @@ -15,7 +15,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Java Virtual Machine services +# Java Virtual Machine invocation API and others services from the JNI C API +# +# Users of this module and the Java FFI, on desktop computers, must define three environment variables: +# * `JAVA_HOME` points to the installation folder of the target Java VM. +# This folder should contain the JNI header file `include/jni.h`. +# e.g. `/usr/lib/jvm/default-java` on Debian Jessie. +# * `JNI_LIB_PATH` points to the folder with `libjvm.so`. +# e.g. `/usr/lib/jvm/default-java/jre/lib/amd64/server/` on Debian Jessie. +# * `LD_LIBRARY_PATH` has the path to the folder with `libjvm.so`. +# It's the same value as `JNI_LIB_PATH` but `LD_LIBRARY_PATH` is a colon separated list +# which may contain other paths. # # See: http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/jniTOC.html module jvm is @@ -38,17 +48,16 @@ in "C Header" `{ # var env = builder.jni_env # ~~~~ class JavaVMBuilder - super JniEnvRef # Version code of the JVM requested by `create_jvm` # - # Default at 0x00010002 + # Default at 0x00010002 for `JNI_VERSION_1_2`. var version = 0x00010002 is writable # Additional option strings var options = new Array[String] - # Create the JVM and return it on success + # Create a JVM instance, or return `null` on error fun create_jvm: nullable JavaVM do var args = new JavaVMInitArgs @@ -65,7 +74,7 @@ class JavaVMBuilder args.options = c_options - var jvm = new JavaVM(args, self) + var jvm = new JavaVM(args) args.free c_options.free @@ -99,15 +108,15 @@ private extern class JavaVMInitArgs `{ JavaVMInitArgs* `} end private extern class JavaVMOption `{ JavaVMOption* `} - fun string: String import NativeString.to_s `{ - return NativeString_to_s((char*)self->optionString); + fun string: String import CString.to_s `{ + return CString_to_s((char*)self->optionString); `} fun string=(v: String) import String.to_cstring `{ self->optionString = String_to_cstring(v); `} - fun extra_info: String import NativeString.to_s `{ - return NativeString_to_s((char*)self->extraInfo); + fun extra_info: String import CString.to_s `{ + return CString_to_s((char*)self->extraInfo); `} fun extra_info=(v: String) import String.to_cstring `{ self->extraInfo = String_to_cstring(v); @@ -122,11 +131,12 @@ end # Represents a jni JavaVM extern class JavaVM `{JavaVM *`} - # Create the JVM, returns its handle and store the a pointer to JniEnv in `env_ref` + # Create the JVM # - # Unavailable on Android, where you cannot instanciate a new JVM. - private new(args: JavaVMInitArgs, env_ref: JniEnvRef) - import jni_error, JniEnvRef.jni_env=, JniEnv.as nullable `{ + # The corresponding `JniEnv` can be obtained by calling `env`. + # + # Unavailable on some platforms, including Android where you cannot instanciate a new JVM. + private new(args: JavaVMInitArgs) import jni_error `{ #ifdef ANDROID JavaVM_jni_error(NULL, "JVM creation not supported on Android", 0); @@ -139,36 +149,43 @@ extern class JavaVM `{JavaVM *`} res = JNI_CreateJavaVM(&jvm, (void**)&env, args); - if (res != 0) { + if (res != JNI_OK) { JavaVM_jni_error(NULL, "Could not create Java VM", res); return NULL; } - else { - JniEnvRef_jni_env__assign(env_ref, JniEnv_as_nullable_JniEnv(env)); - return jvm; - } + + return jvm; `} - private fun jni_error(msg: NativeString, v: Int) + private fun jni_error(msg: CString, v: Int) do print "JNI Error: {msg} ({v})" abort end + # Unload the Java VM when the calling thread is the only remaining non-daemon attached user thread fun destroy `{ (*self)->DestroyJavaVM(self); `} + # `JniEnv` attached to the calling thread + # + # A null pointer is returned if the calling thread is not attached to the JVM. fun env: JniEnv import jni_error `{ JNIEnv *env; int res = (*self)->GetEnv(self, (void **)&env, JNI_VERSION_1_6); - if (res != JNI_OK) { + if (res == JNI_EDETACHED) { + JavaVM_jni_error(NULL, "Requesting JNIEnv from an unattached thread", res); + return NULL; + } + else if (res != JNI_OK) { JavaVM_jni_error(NULL, "Could not get JNIEnv from Java VM", res); return NULL; } return env; `} + # Attach the calling thread to the JVM and return its `JniEnv` fun attach_current_thread: JniEnv import jni_error `{ JNIEnv *env; #ifdef ANDROID @@ -183,6 +200,14 @@ extern class JavaVM `{JavaVM *`} } return env; `} + + # Detach the calling thread from this JVM + fun detach_current_thread import jni_error `{ + int res = (*self)->DetachCurrentThread(self); + if (res != JNI_OK) { + JavaVM_jni_error(NULL, "Could not detach current thread to Java VM", res); + } + `} end # Represents a jni JNIEnv, which is a thread in a JavaVM @@ -262,8 +287,8 @@ extern class JniEnv `{JNIEnv *`} return res; `} - # Call a method on `obj` designed by `method_id` with an array `args` of arguments returning a NativeString - fun call_string_method(obj: JavaObject, method_id: JMethodID, args: nullable Array[nullable Object]): NativeString import convert_args_to_jni `{ + # Call a method on `obj` designed by `method_id` with an array `args` of arguments returning a CString + fun call_string_method(obj: JavaObject, method_id: JMethodID, args: nullable Array[nullable Object]): CString import convert_args_to_jni `{ jvalue * args_tab = JniEnv_convert_args_to_jni(self, args); jobject jobj = (*self)->CallObjectMethod(self, obj, method_id, args_tab); free(args_tab); @@ -402,11 +427,6 @@ extern class JniEnv `{JNIEnv *`} `} end -# used to initialize a JavaVM -class JniEnvRef - var jni_env: nullable JniEnv = null -end - # Represents a jni jclass extern class JClass `{jclass`} end @@ -421,16 +441,16 @@ end # Represents a jni JNINNativeMethod extern class JNINativeMethod `{ JNINativeMethod* `} - fun name: String import NativeString.to_s `{ - return NativeString_to_s((void*)self->name); + fun name: String import CString.to_s `{ + return CString_to_s((void*)self->name); `} fun name=(name: String) import String.to_cstring `{ self->name = String_to_cstring(name); `} - fun signature: String import NativeString.to_s `{ - return NativeString_to_s((void*)self->signature); + fun signature: String import CString.to_s `{ + return CString_to_s((void*)self->signature); `} fun signature=(signature: String) import String.to_cstring `{ @@ -510,7 +530,7 @@ redef class Bool `} end -redef class NativeString +redef class CString redef fun to_jvalue(env)`{ jvalue value; value.l = (*env)->NewStringUTF(env, self);