# This file is part of NIT ( http://www.nitlanguage.org ).
#
-# Copyright 2014 Romain Chanoir <romain.chanoir@courrier.uqam.ca>
+# Copyright 2014 Romain Chanoir <romain.chanoir@courrier.uqam.ca>
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
#
# See: http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/jniTOC.html
module jvm is
- c_compiler_option("-I $(JAVA_HOME)/include/")
- c_linker_option("-L $(JNI_LIB_PATH) -ljvm")
+ cflags "-I $(JAVA_HOME)/include/ -I $(JAVA_HOME)/include/linux/"
+ ldflags "-L $(JNI_LIB_PATH) -ljvm"
end
in "C Header" `{
#include <jni.h>
-
-`}
-
-`{
- inline jvalue * convert_array_of_Object_to_c(nullable_Array_of_nullable_Object nullable_nit_array, JNIEnv* env){
- if(nullable_Array_of_nullable_Object_is_null(nullable_nit_array)){
- return NULL;
- }
- Array_of_nullable_Object nit_array = nullable_Array_of_nullable_Object_as_Array_of_nullable_Object(nullable_nit_array);
- int nit_array_length = Array_of_nullable_Object_length(nit_array);
- int i;
- jvalue *c_array = malloc(sizeof(jvalue)*(nit_array_length));
- for (i = 0; i < nit_array_length; i ++) {
- nullable_Object nullable_obj = Array_of_nullable_Object__index(nit_array, i);
- if(nullable_Object_is_a_Int(nullable_obj)) {
- int val = nullable_Object_as_Int(nullable_obj);
- c_array[i].i = val;
- }else if (nullable_Object_is_a_Char(nullable_obj)){
- char val = nullable_Object_as_Char(nullable_obj);
- c_array[i].c = val;
- }else if (nullable_Object_is_a_Bool(nullable_obj)){
- int val = nullable_Object_as_Bool(nullable_obj);
- c_array[i].z = val;
- }else if(nullable_Object_is_a_Float(nullable_obj)){
- float val = nullable_Object_as_Float(nullable_obj);
- c_array[i].f = val;
- }else if(nullable_Object_is_a_JObject(nullable_obj)){
- jobject val = nullable_Object_as_JObject(nullable_obj);
- c_array[i].l = val;
- }else if(nullable_Object_is_a_String(nullable_obj)){
- String val = nullable_Object_as_String(nullable_obj);
- char* c = String_to_cstring(val);
- jstring js = (*env)->NewStringUTF(env, c);
- c_array[i].l = js;
- }else {
- fprintf(stderr, "NOT YET SUPPORTED: nit objects are not supported\n");
- exit(1);
- }
- }
- return c_array;
- }
`}
# Utility to select options to create the VM using `create_jvm`
#
# Usage example:
-# ~~~~
+#
+# ~~~~nitish
# var builder = new JavaVMBuilder
# builder.options.add "-Djava.class.path=."
# var jvm = builder.create_jvm
class JavaVMBuilder
super JniEnvRef
- var version: Int = "00010002".to_hex
+ # Version code of the JVM requested by `create_jvm`
+ #
+ # Default at 0x00010002
+ var version = 0x00010002 is writable
+
+ # Additional option strings
var options = new Array[String]
+ # Create the JVM and return it on success
fun create_jvm: nullable JavaVM
do
var args = new JavaVMInitArgs
end
end
-extern class JavaVMInitArgs `{ JavaVMInitArgs* `}
+private extern class JavaVMInitArgs `{ JavaVMInitArgs* `}
new `{ return (JavaVMInitArgs*)malloc(sizeof(JavaVMInitArgs)); `}
# Set the defaut config for a VM
# Can be called after setting the version
- fun set_default `{ JNI_GetDefaultJavaVMInitArgs(recv); `}
+ #
+ # Unavailable on Android, where you cannot instanciate a new JVM.
+ fun set_default `{
+ #ifndef ANDROID
+ JNI_GetDefaultJavaVMInitArgs(recv);
+ #endif
+ `}
fun version: Int `{ return recv->version; `}
fun version=(v: Int) `{ recv->version = v; `}
fun n_options=(v: Int) `{ recv->nOptions = v; `}
end
-extern class JavaVMOption `{ JavaVMOption* `}
+private extern class JavaVMOption `{ JavaVMOption* `}
fun string: String import NativeString.to_s `{
- return NativeString_to_s(recv->optionString);
+ return NativeString_to_s((char*)recv->optionString);
`}
fun string=(v: String) import String.to_cstring `{
recv->optionString = String_to_cstring(v);
`}
fun extra_info: String import NativeString.to_s `{
- return NativeString_to_s(recv->extraInfo);
+ return NativeString_to_s((char*)recv->extraInfo);
`}
fun extra_info=(v: String) import String.to_cstring `{
recv->extraInfo = String_to_cstring(v);
`}
end
-extern class JavaVMOptionArray `{ JavaVMOption* `}
+private extern class JavaVMOptionArray `{ JavaVMOption* `}
new(size: Int) `{ return (JavaVMOption*)malloc(sizeof(JavaVMOption)*size); `}
fun [](i: Int): JavaVMOption `{ return recv+i; `}
# Represents a jni JavaVM
extern class JavaVM `{JavaVM *`}
# Create the JVM, returns its handle and store the a pointer to JniEnv in `env_ref`
- new(args: JavaVMInitArgs, env_ref: JniEnvRef) import jni_error, JniEnvRef.jni_env=, JniEnv as nullable `{
+ #
+ # 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 `{
+
+ #ifdef ANDROID
+ JavaVM_jni_error(NULL, "JVM creation not supported on Android", 0);
+ return NULL;
+ #endif
+
JavaVM *jvm;
JNIEnv *env;
jint res;
}
`}
- fun jni_error(msg: NativeString, v: Int)
+ private fun jni_error(msg: NativeString, v: Int)
do
print "JNI Error: {msg} ({v})"
abort
fun destroy `{
(*recv)->DestroyJavaVM(recv);
`}
+
+ fun env: JniEnv import jni_error `{
+ JNIEnv *env;
+ int res = (*recv)->GetEnv(recv, (void **)&env, JNI_VERSION_1_6);
+ if (res != JNI_OK) {
+ JavaVM_jni_error(NULL, "Could not get JNIEnv from Java VM", res);
+ return NULL;
+ }
+ return env;
+ `}
+
+ fun attach_current_thread: JniEnv import jni_error `{
+ JNIEnv *env;
+ #ifdef ANDROID
+ // the signature is different (better actually) on Android
+ int res = (*recv)->AttachCurrentThread(recv, &env, NULL);
+ #else
+ int res = (*recv)->AttachCurrentThread(recv, (void**)&env, NULL);
+ #endif
+ if (res != JNI_OK) {
+ JavaVM_jni_error(NULL, "Could not attach current thread to Java VM", res);
+ return NULL;
+ }
+ return env;
+ `}
end
# Represents a jni JNIEnv, which is a thread in a JavaVM
extern class JniEnv `{JNIEnv *`}
-
+
# Get a class object from its fully-qualified name or null if the class cannot be found
fun find_class(class_name : String): JClass import String.to_cstring `{
return (*recv)->FindClass(recv,String_to_cstring(class_name));
`}
-
+
# Return the method id for an instance of a class or interface
# The method is determined by its name and signature
# To obtain the method ID of a constructor, supply "<init>" as the method name and "void(V)" as the return type
fun get_method_id(clazz : JClass, name : String, signature : String): JMethodID import String.to_cstring `{
return (*recv)->GetMethodID(recv, clazz, String_to_cstring(name), String_to_cstring(signature));
`}
-
+
# Construct a new Java object from the `clazz`, using the constructor ̀ method_id`
- fun new_object(clazz: JClass, method_id: JMethodID): JObject `{
+ fun new_object(clazz: JClass, method_id: JMethodID): JavaObject `{
return (*recv)->NewObject(recv, clazz, method_id);
`}
-
+
# Return the JClass of `obj`
- fun get_object_class(obj: JObject): JClass `{
+ fun get_object_class(obj: JavaObject): JClass `{
return (*recv)->GetObjectClass(recv, obj);
`}
- # Registers native methods with the class specified by the `clazz` argument
+ # Registers native methods with the class specified by the `clazz` argument
fun register_natives(clazz: JClass, method: JNINativeMethod, n_method : Int): Int `{
return (*recv)->RegisterNatives(recv, clazz, method, n_method);
`}
# Call a method on `obj` designed by `method_id` with an array `args` of arguments
- fun call_void_method(obj: JObject, method_id: JMethodID, args: nullable Array[nullable Object]) import Array[nullable Object] as not nullable, Array[nullable Object].[], Array[nullable Object].length, nullable Object.as(Int), nullable Object.as(Char), nullable Object.as(Bool), nullable Object.as(Float), nullable Object.as(JObject), nullable Object.as(String), String.to_cstring `{
- jvalue * args_tab = convert_array_of_Object_to_c(args, recv);
+ fun call_void_method(obj: JavaObject, method_id: JMethodID, args: nullable Array[nullable Object]) import convert_args_to_jni `{
+ jvalue * args_tab = JniEnv_convert_args_to_jni(recv, args);
(*recv)->CallVoidMethodA(recv, obj, method_id, args_tab);
free(args_tab);
`}
-
- # Call a method on `obj` designed by `method_id` with an array `args` of argument returning a JObject
- fun call_object_method(obj: JObject, method_id: JMethodID, args: nullable Array[nullable Object]): JObject import Array[nullable Object] as not nullable, Array[nullable Object].[], Array[nullable Object].length, nullable Object.as(Int), nullable Object.as(Char), nullable Object.as(Bool), nullable Object.as(Float), nullable Object.as(JObject), nullable Object.as(String), String.to_cstring `{
- jvalue * args_tab = convert_array_of_Object_to_c(args, recv);
- (*recv)->CallObjectMethod(recv, obj, method_id, args_tab);
+
+ # Call a method on `obj` designed by `method_id` with an array `args` of argument returning a JavaObject
+ fun call_object_method(obj: JavaObject, method_id: JMethodID, args: nullable Array[nullable Object]): JavaObject import convert_args_to_jni `{
+ jvalue * args_tab = JniEnv_convert_args_to_jni(recv, args);
+ jobject res = (*recv)->CallObjectMethod(recv, obj, method_id, args_tab);
free(args_tab);
+ return res;
`}
-
+
# Call a method on `obj` designed by `method_id` with an array `args` of arguments returning a Bool
- fun call_boolean_method(obj: JObject, method_id: JMethodID, args: nullable Array[nullable Object]): Bool import Array[nullable Object] as not nullable, Array[nullable Object].[], Array[nullable Object].length, nullable Object.as(Int), nullable Object.as(Char), nullable Object.as(Bool), nullable Object.as(Float), nullable Object.as(JObject), nullable Object.as(String), String.to_cstring `{
- jvalue * args_tab = convert_array_of_Object_to_c(args, recv);
- return (*recv)->CallBooleanMethod(recv, obj, method_id, args_tab);
+ fun call_boolean_method(obj: JavaObject, method_id: JMethodID, args: nullable Array[nullable Object]): Bool import convert_args_to_jni `{
+ jvalue * args_tab = JniEnv_convert_args_to_jni(recv, args);
+ jboolean res = (*recv)->CallBooleanMethod(recv, obj, method_id, args_tab);
free(args_tab);
+ return res;
`}
# Call a method on `obj` designed by `method_id` with an array `args` of arguments returning a Char
- fun call_char_method(obj: JObject, method_id: JMethodID, args: nullable Array[nullable Object]): Char import Array[nullable Object] as not nullable, Array[nullable Object].[], Array[nullable Object].length, nullable Object.as(Int), nullable Object.as(Char), nullable Object.as(Bool), nullable Object.as(Float), nullable Object.as(JObject), nullable Object.as(String), String.to_cstring `{
- jvalue * args_tab = convert_array_of_Object_to_c(args, recv);
- return (*recv)->CallCharMethod(recv, obj, method_id, args_tab);
+ fun call_char_method(obj: JavaObject, method_id: JMethodID, args: nullable Array[nullable Object]): Char import convert_args_to_jni `{
+ jvalue * args_tab = JniEnv_convert_args_to_jni(recv, args);
+ jchar res = (*recv)->CallCharMethod(recv, obj, method_id, args_tab);
free(args_tab);
+ return res;
`}
# Call a method on `obj` designed by `method_id` with an array `args` of arguments returning an Int
- fun call_int_method(obj: JObject, method_id: JMethodID, args: nullable Array[nullable Object]): Int import Array[nullable Object] as not nullable, Array[nullable Object].[], Array[nullable Object].length, nullable Object.as(Int), nullable Object.as(Char), nullable Object.as(Bool), nullable Object.as(Float), nullable Object.as(JObject), nullable Object.as(String), String.to_cstring `{
- jvalue * args_tab = convert_array_of_Object_to_c(args, recv);
- return (*recv)->CallIntMethod(recv, obj, method_id, args_tab);
+ fun call_int_method(obj: JavaObject, method_id: JMethodID, args: nullable Array[nullable Object]): Int import convert_args_to_jni `{
+ jvalue * args_tab = JniEnv_convert_args_to_jni(recv, args);
+ jint res = (*recv)->CallIntMethod(recv, obj, method_id, args_tab);
free(args_tab);
+ return res;
`}
-
+
# Call a method on `obj` designed by `method_id` with an array `args` of arguments returning a Float
- fun call_float_method(obj: JObject, method_id: JMethodID, args: nullable Array[nullable Object]): Float import Array[nullable Object] as not nullable, Array[nullable Object].[], Array[nullable Object].length, nullable Object.as(Int), nullable Object.as(Char), nullable Object.as(Bool), nullable Object.as(Float), nullable Object.as(JObject), nullable Object.as(String), String.to_cstring `{
- jvalue * args_tab = convert_array_of_Object_to_c(args, recv);
- return (*recv)->CallFloatMethod(recv, obj, method_id, args_tab);
+ fun call_float_method(obj: JavaObject, method_id: JMethodID, args: nullable Array[nullable Object]): Float import convert_args_to_jni `{
+ jvalue * args_tab = JniEnv_convert_args_to_jni(recv, args);
+ jfloat res = (*recv)->CallFloatMethod(recv, obj, method_id, args_tab);
free(args_tab);
+ 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: JObject, method_id: JMethodID, args: nullable Array[nullable Object]): NativeString import Array[nullable Object] as not nullable, Array[nullable Object].[], Array[nullable Object].length, nullable Object.as(Int), nullable Object.as(Char), nullable Object.as(Bool), nullable Object.as(Float), nullable Object.as(JObject), nullable Object.as(String), String.to_cstring, String.length `{
- jvalue * args_tab = convert_array_of_Object_to_c(args, recv);
+ fun call_string_method(obj: JavaObject, method_id: JMethodID, args: nullable Array[nullable Object]): NativeString import convert_args_to_jni `{
+ jvalue * args_tab = JniEnv_convert_args_to_jni(recv, args);
jobject jobj = (*recv)->CallObjectMethod(recv, obj, method_id, args_tab);
free(args_tab);
return (char*)(*recv)->GetStringUTFChars(recv, (jstring)jobj, NULL);
`}
+ private fun convert_args_to_jni(args: nullable Array[nullable Object]): Pointer import Array[nullable Object].as not nullable, Array[nullable Object].[], Array[nullable Object].length, nullable Object.as(Int), nullable Object.as(Char), nullable Object.as(Bool), nullable Object.as(Float), nullable Object.as(JavaObject), nullable Object.as(String), String.to_cstring, String.length `{
+ if(nullable_Array_of_nullable_Object_is_null(args)){
+ return NULL;
+ }
+ Array_of_nullable_Object nit_array = nullable_Array_of_nullable_Object_as_Array_of_nullable_Object(args);
+ int nit_array_length = Array_of_nullable_Object_length(nit_array);
+ int i;
+ jvalue *c_array = malloc(sizeof(jvalue)*(nit_array_length));
+ for (i = 0; i < nit_array_length; i ++) {
+ nullable_Object nullable_obj = Array_of_nullable_Object__index(nit_array, i);
+ if(nullable_Object_is_a_Int(nullable_obj)) {
+ int val = nullable_Object_as_Int(nullable_obj);
+ c_array[i].i = val;
+ } else if (nullable_Object_is_a_Char(nullable_obj)){
+ char val = nullable_Object_as_Char(nullable_obj);
+ c_array[i].c = val;
+ } else if (nullable_Object_is_a_Bool(nullable_obj)){
+ int val = nullable_Object_as_Bool(nullable_obj);
+ c_array[i].z = val;
+ } else if(nullable_Object_is_a_Float(nullable_obj)){
+ float val = nullable_Object_as_Float(nullable_obj);
+ c_array[i].f = val;
+ } else if(nullable_Object_is_a_JavaObject(nullable_obj)){
+ jobject val = nullable_Object_as_JavaObject(nullable_obj);
+ c_array[i].l = val;
+ } else if(nullable_Object_is_a_String(nullable_obj)){
+ String val = nullable_Object_as_String(nullable_obj);
+ char* c = String_to_cstring(val);
+ jstring js = (*recv)->NewStringUTF(recv, c);
+ c_array[i].l = js;
+ } else {
+ fprintf(stderr, "NOT YET SUPPORTED: nit objects are not supported\n");
+ exit(1);
+ }
+ }
+ return c_array;
+ `}
+
# Returns the field ID for an instance field of a class. The field is specified by its name and signature
fun get_field_id(clazz: JClass, name: String, sign: String): JFieldID import String.to_cstring `{
return (*recv)->GetFieldID(recv, clazz, String_to_cstring(name), String_to_cstring(sign));
`}
-
+
# returns the value of an instance (nonstatic) field of an object. The field to access is specified by a field ID obtained by calling get_field_id()
- fun get_object_field(obj: JObject, fieldID: JFieldID): JObject `{
+ fun get_object_field(obj: JavaObject, fieldID: JFieldID): JavaObject `{
return (*recv)->GetObjectField(recv, obj, fieldID);
`}
- fun get_boolean_field(obj: JObject, fieldID: JFieldID): Bool `{
+ fun get_boolean_field(obj: JavaObject, fieldID: JFieldID): Bool `{
return (*recv)->GetBooleanField(recv, obj, fieldID);
`}
-
- fun get_char_field(obj: JObject, fieldID: JFieldID): Char `{
+
+ fun get_char_field(obj: JavaObject, fieldID: JFieldID): Char `{
return (*recv)->GetCharField(recv, obj, fieldID);
`}
- fun get_int_field(obj: JObject, fieldID: JFieldID): Int `{
+ fun get_int_field(obj: JavaObject, fieldID: JFieldID): Int `{
return (*recv)->GetIntField(recv, obj, fieldID);
`}
- fun get_float_field(obj: JObject, fieldID: JFieldID): Float `{
+ fun get_float_field(obj: JavaObject, fieldID: JFieldID): Float `{
return (*recv)->GetFloatField(recv, obj, fieldID);
`}
- fun set_object_field(obj: JObject, fieldID: JFieldID, value: JObject) `{
+ fun set_object_field(obj: JavaObject, fieldID: JFieldID, value: JavaObject) `{
(*recv)->SetObjectField(recv, obj, fieldID, value);
`}
- fun set_boolean_field(obj: JObject, fieldID: JFieldID, value: Bool) `{
+ fun set_boolean_field(obj: JavaObject, fieldID: JFieldID, value: Bool) `{
(*recv)->SetBooleanField(recv, obj, fieldID, value);
`}
- fun set_char_field(obj: JObject, fieldID: JFieldID, value: Char) `{
+ fun set_char_field(obj: JavaObject, fieldID: JFieldID, value: Char) `{
(*recv)->SetCharField(recv, obj, fieldID, value);
`}
- fun set_int_field(obj: JObject, fieldID: JFieldID, value: Int) `{
+ fun set_int_field(obj: JavaObject, fieldID: JFieldID, value: Int) `{
(*recv)->SetIntField(recv, obj, fieldID, value);
- `}
+ `}
- fun set_float_field(obj: JObject, fieldID: JFieldID, value: Float) `{
+ fun set_float_field(obj: JavaObject, fieldID: JFieldID, value: Float) `{
(*recv)->SetFloatField(recv, obj, fieldID, value);
`}
-
+
# Check for pending exception without creating a local reference to the exception object
fun exception_check: Bool `{
return (*recv)->ExceptionCheck(recv);
`}
# return the exception if there is one in the process of being thrown, or NULL if no exception is currently being thrown
- fun exception_occurred: JObject `{
+ fun exception_occurred: JavaObject `{
return (*recv)->ExceptionOccurred(recv);
`}
fun exception_clear `{
return (*recv)->ExceptionClear(recv);
`}
-
+
# Raise a fatal error
fun fatal_error(msg: String) import String.to_cstring `{
(*recv)->FatalError(recv, String_to_cstring(msg));
`}
- # Transform a NIT String into a JObject
- fun string_to_jobject(string: String): JObject `{
+ # Transform a NIT String into a JavaObject
+ fun string_to_jobject(string: String): JavaObject `{
return (*recv)->NewStringUTF(recv, String_to_cstring(string));
`}
+
+ # Pushes a local reference frame on the JNI stack
+ fun push_local_frame(capacity: Int): Bool `{
+ return (*recv)->PushLocalFrame(recv, capacity);
+ `}
+
+ # Pops the current local reference frame on the JNI stack
+ #
+ # Similiar to `JavaObject::pop_from_local_frame` which returns a value.
+ fun pop_local_frame `{
+ (*recv)->PopLocalFrame(recv, NULL);
+ `}
end
-# used to initialize a JavaVM
+# used to initialize a JavaVM
class JniEnvRef
var jni_env: nullable JniEnv = null
end
end
# Represens a jni jobject
-extern class JObject `{jobject`}
+extern class JavaObject in "Java" `{ java.lang.Object `}
end
# Represents a jni JNINNativeMethod
extern class JNINativeMethod `{ JNINativeMethod* `}
fun name: String import NativeString.to_s `{
- return NativeString_to_s(recv->name);
+ return NativeString_to_s((void*)recv->name);
`}
fun name=(name: String) import String.to_cstring `{
`}
fun signature: String import NativeString.to_s `{
- return NativeString_to_s(recv->signature);
+ return NativeString_to_s((void*)recv->signature);
`}
fun signature=(signature: String) import String.to_cstring `{
fun get_boolean:Bool `{
return recv.z;
`}
-
+
fun set_char(c: Char)`{
recv.c = c;
`}
-
+
fun get_char: Char `{
return recv.c;
`}
return recv.f;
`}
- fun set_jobject(obj: JObject) `{
+ fun set_jobject(obj: JavaObject) `{
recv.l = obj;
`}
- fun get_jobject: JObject `{
+ fun get_jobject: JavaObject `{
return recv.l;
`}
end