1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2014 Romain Chanoir <romain.chanoir@courrier.uqam.ca>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Manipulates the Java Virtual Machine
19 # See: http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/jniTOC.html
21 c_compiler_option
("-I $(JAVA_HOME)/include/")
22 c_linker_option
("-L $(JNI_LIB_PATH) -ljvm")
31 inline jvalue * convert_array_of_Object_to_c(nullable_Array_of_nullable_Object nullable_nit_array, JNIEnv* env){
32 if(nullable_Array_of_nullable_Object_is_null(nullable_nit_array)){
35 Array_of_nullable_Object nit_array = nullable_Array_of_nullable_Object_as_Array_of_nullable_Object(nullable_nit_array);
36 int nit_array_length = Array_of_nullable_Object_length(nit_array);
38 jvalue *c_array = malloc(sizeof(jvalue)*(nit_array_length));
39 for (i = 0; i < nit_array_length; i ++) {
40 nullable_Object nullable_obj = Array_of_nullable_Object__index(nit_array, i);
41 if(nullable_Object_is_a_Int(nullable_obj)) {
42 int val = nullable_Object_as_Int(nullable_obj);
44 }else if (nullable_Object_is_a_Char(nullable_obj)){
45 char val = nullable_Object_as_Char(nullable_obj);
47 }else if (nullable_Object_is_a_Bool(nullable_obj)){
48 int val = nullable_Object_as_Bool(nullable_obj);
50 }else if(nullable_Object_is_a_Float(nullable_obj)){
51 float val = nullable_Object_as_Float(nullable_obj);
53 }else if(nullable_Object_is_a_JObject(nullable_obj)){
54 jobject val = nullable_Object_as_JObject(nullable_obj);
56 }else if(nullable_Object_is_a_String(nullable_obj)){
57 String val = nullable_Object_as_String(nullable_obj);
58 char* c = String_to_cstring(val);
59 jstring js = (*env)->NewStringUTF(env, c);
62 fprintf(stderr, "NOT YET SUPPORTED: nit objects are not supported\n");
70 # Utility to select options to create the VM using `create_jvm`
74 # var builder = new JavaVMBuilder
75 # builder.options.add "-Djava.class.path=."
76 # var jvm = builder.create_jvm
77 # var env = builder.jni_env
82 var version
: Int = "00010002".to_hex
83 var options
= new Array[String]
85 fun create_jvm
: nullable JavaVM
87 var args
= new JavaVMInitArgs
88 args
.version
= version
90 args
.n_options
= options
.length
92 var c_options
= new JavaVMOptionArray(options
.length
)
93 for o
in options
.length
.times
do
94 var option
= options
[o
]
95 var c_option
= c_options
[o
]
96 c_option
.string
= option
99 args
.options
= c_options
101 var jvm
= new JavaVM(args
, self)
106 if jvm
.address_is_null
then return null
111 extern class JavaVMInitArgs `{ JavaVMInitArgs* `}
112 new `{ return (JavaVMInitArgs*)malloc(sizeof(JavaVMInitArgs)); `}
114 # Set the defaut config for a VM
115 # Can be called after setting the version
116 fun set_default
`{ JNI_GetDefaultJavaVMInitArgs(recv); `}
118 fun version: Int `{ return recv->version; `}
119 fun version
=(v
: Int) `{ recv->version = v; `}
121 fun options: JavaVMOptionArray `{ return recv->options; `}
122 fun options
=(v
: JavaVMOptionArray) `{ recv->options = v; `}
124 fun n_options: Int `{ return recv->nOptions; `}
125 fun n_options
=(v
: Int) `{ recv->nOptions = v; `}
128 extern class JavaVMOption `{ JavaVMOption* `}
129 fun string
: String import NativeString.to_s
`{
130 return NativeString_to_s(recv->optionString);
132 fun string
=(v
: String) import String.to_cstring
`{
133 recv->optionString = String_to_cstring(v);
136 fun extra_info
: String import NativeString.to_s
`{
137 return NativeString_to_s(recv->extraInfo);
139 fun extra_info
=(v
: String) import String.to_cstring
`{
140 recv->extraInfo = String_to_cstring(v);
144 extern class JavaVMOptionArray `{ JavaVMOption* `}
145 new(size: Int) `{ return (JavaVMOption*)malloc(sizeof(JavaVMOption)*size); `}
147 fun [](i
: Int): JavaVMOption `{ return recv+i; `}
150 # Represents a jni JavaVM
151 extern class JavaVM `{JavaVM *`}
152 # Create the JVM, returns its handle and store the a pointer to JniEnv in `env_ref`
153 new(args
: JavaVMInitArgs, env_ref
: JniEnvRef) import jni_error
, JniEnvRef.jni_env
=, JniEnv as nullable `{
158 res = JNI_CreateJavaVM(&jvm, (void**)&env, args);
161 JavaVM_jni_error(NULL, "Could not create Java VM, error: {res}");
165 JniEnvRef_jni_env__assign(env_ref, JniEnv_as_nullable_JniEnv(env));
170 fun jni_error
(msg
: NativeString)
172 print
"JNI Error: {msg}"
176 fun destroy_java_vm
`{
177 (*recv)->DestroyJavaVM(recv);
181 # Represents a jni JNIEnv, which is a thread in a JavaVM
182 extern class JniEnv `{JNIEnv *`}
184 # Get a class object from its fully-qualified name or null if the class cannot be found
185 fun find_class(class_name : String): JClass import String.to_cstring `{
186 return (*recv
)->FindClass(recv
,String_to_cstring(class_name
));
189 # Return the method id for an instance of a class or interface
190 # The method is determined by its name and signature
191 # To obtain the method ID of a constructor, supply "<init>" as the method name and "void(V)" as the return type
192 fun get_method_id(clazz : JClass, name : String, signature : String): JMethodID import String.to_cstring `{
193 return (*recv
)->GetMethodID(recv
, clazz
, String_to_cstring(name
), String_to_cstring(signature
));
196 # Construct a new Java object from the `clazz
`, using the constructor ̀ method_id`
197 fun new_object
(clazz
: JClass, method_id
: JMethodID): JObject `{
198 return (*recv)->NewObject(recv, clazz, method_id);
201 # Return the JClass of `obj`
202 fun get_object_class
(obj
: JObject): JClass `{
203 return (*recv)->GetObjectClass(recv, obj);
206 # Registers native methods with the class specified by the `clazz` argument
207 fun register_natives
(clazz
: JClass, method
: JNINativeMethod, n_method
: Int): Int `{
208 return (*recv)->RegisterNatives(recv, clazz, method, n_method);
211 # Call a method on `obj` designed by `method_id` with an array `args` of arguments
212 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
`{
213 jvalue * args_tab = convert_array_of_Object_to_c(args, recv);
214 (*recv)->CallVoidMethodA(recv, obj, method_id, args_tab);
218 # Call a method on `obj` designed by `method_id` with an array `args` of argument returning a JObject
219 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
`{
220 jvalue * args_tab = convert_array_of_Object_to_c(args, recv);
221 (*recv)->CallObjectMethod(recv, obj, method_id, args_tab);
225 # Call a method on `obj` designed by `method_id` with an array `args` of arguments returning a Bool
226 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
`{
227 jvalue * args_tab = convert_array_of_Object_to_c(args, recv);
228 return (*recv)->CallBooleanMethod(recv, obj, method_id, args_tab);
232 # Call a method on `obj` designed by `method_id` with an array `args` of arguments returning a Char
233 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
`{
234 jvalue * args_tab = convert_array_of_Object_to_c(args, recv);
235 return (*recv)->CallCharMethod(recv, obj, method_id, args_tab);
239 # Call a method on `obj` designed by `method_id` with an array `args` of arguments returning an Int
240 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
`{
241 jvalue * args_tab = convert_array_of_Object_to_c(args, recv);
242 return (*recv)->CallIntMethod(recv, obj, method_id, args_tab);
246 # Call a method on `obj` designed by `method_id` with an array `args` of arguments returning a Float
247 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
`{
248 jvalue * args_tab = convert_array_of_Object_to_c(args, recv);
249 return (*recv)->CallFloatMethod(recv, obj, method_id, args_tab);
253 # Call a method on `obj` designed by `method_id` with an array `args` of arguments returning a NativeString
254 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
`{
255 jvalue * args_tab = convert_array_of_Object_to_c(args, recv);
256 jobject jobj = (*recv)->CallObjectMethod(recv, obj, method_id, args_tab);
258 return (char*)(*recv)->GetStringUTFChars(recv, (jstring)jobj, NULL);
261 # Returns the field ID for an instance field of a class. The field is specified by its name and signature
262 fun get_field_id
(clazz
: JClass, name
: String, sign
: String): JFieldID import String.to_cstring
`{
263 return (*recv)->GetFieldID(recv, clazz, String_to_cstring(name), String_to_cstring(sign));
266 # 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()
267 fun get_object_field
(obj
: JObject, fieldID
: JFieldID): JObject `{
268 return (*recv)->GetObjectField(recv, obj, fieldID);
271 fun get_boolean_field
(obj
: JObject, fieldID
: JFieldID): Bool `{
272 return (*recv)->GetBooleanField(recv, obj, fieldID);
275 fun get_char_field
(obj
: JObject, fieldID
: JFieldID): Char `{
276 return (*recv)->GetCharField(recv, obj, fieldID);
279 fun get_int_field
(obj
: JObject, fieldID
: JFieldID): Int `{
280 return (*recv)->GetIntField(recv, obj, fieldID);
283 fun get_float_field
(obj
: JObject, fieldID
: JFieldID): Float `{
284 return (*recv)->GetFloatField(recv, obj, fieldID);
287 fun set_object_field
(obj
: JObject, fieldID
: JFieldID, value
: JObject) `{
288 (*recv)->SetObjectField(recv, obj, fieldID, value);
291 fun set_boolean_field
(obj
: JObject, fieldID
: JFieldID, value
: Bool) `{
292 (*recv)->SetBooleanField(recv, obj, fieldID, value);
295 fun set_char_field
(obj
: JObject, fieldID
: JFieldID, value
: Char) `{
296 (*recv)->SetCharField(recv, obj, fieldID, value);
299 fun set_int_field
(obj
: JObject, fieldID
: JFieldID, value
: Int) `{
300 (*recv)->SetIntField(recv, obj, fieldID, value);
303 fun set_float_field
(obj
: JObject, fieldID
: JFieldID, value
: Float) `{
304 (*recv)->SetFloatField(recv, obj, fieldID, value);
307 # Check for pending exception without creating a local reference to the exception object
308 fun exception_check
: Bool `{
309 return (*recv)->ExceptionCheck(recv);
312 # Construct an exception object from the specified class with the message specified by `message` and causes that exception to be thrown
313 fun throw_new
(clazz
: JClass, message
: String): Int import String.to_cstring
`{
314 return (*recv)->ThrowNew(recv, clazz, String_to_cstring(message));
317 # return the exception if there is one in the process of being thrown, or NULL if no exception is currently being thrown
318 fun exception_occurred
: JObject `{
319 return (*recv)->ExceptionOccurred(recv);
322 # prints an exception and backtrace to error channel
323 fun exception_describe
`{
324 return (*recv)->ExceptionDescribe(recv);
327 # clears any exception currently being thrown, has no effect if there is no exception
328 fun exception_clear
`{
329 return (*recv)->ExceptionClear(recv);
332 # Raise a fatal error
333 fun fatal_error
(msg
: String) import String.to_cstring
`{
334 (*recv)->FatalError(recv, String_to_cstring(msg));
337 # Transform a NIT String into a JObject
338 fun string_to_jobject
(string
: String): JObject `{
339 return (*recv)->NewStringUTF(recv, String_to_cstring(string));
343 # used to initialize a JavaVM
345 var jni_env
: nullable JniEnv = null
348 # Represents a jni jclass
349 extern class JClass `{jclass`}
352 # Represents a jni jmethodID
353 extern class JMethodID `{jmethodID`}
356 # Represens a jni jobject
357 extern class JObject `{jobject`}
360 # Represents a jni JNINNativeMethod
361 extern class JNINativeMethod `{ JNINativeMethod* `}
362 fun name
: String import NativeString.to_s
`{
363 return NativeString_to_s(recv->name);
366 fun name
=(name
: String) import String.to_cstring
`{
367 recv->name = String_to_cstring(name);
370 fun signature
: String import NativeString.to_s
`{
371 return NativeString_to_s(recv->signature);
374 fun signature
=(signature
: String) import String.to_cstring
`{
375 recv->signature = String_to_cstring(signature);
379 # Represents a jni jfieldID
380 extern class JFieldID `{jfieldID`}
383 # Reprents a jni jvalue
384 extern class JValue `{jvalue`}
386 fun set_boolean
(b
: Bool) `{
390 fun get_boolean
:Bool `{
394 fun set_char
(c
: Char)`{
398 fun get_char
: Char `{
402 fun set_int
(i
: Int) `{
410 fun set_float
(f
: Float) `{
414 fun get_float
: Float `{
418 fun set_jobject
(obj
: JObject) `{
422 fun get_jobject
: JObject `{
428 redef fun to_jvalue
(env
): JValue `{
436 redef fun to_jvalue
(env
): JValue `{
444 redef fun to_jvalue
(env
): JValue `{
451 redef class NativeString
452 redef fun to_jvalue
(env
)`{
454 value.l = (*env)->NewStringUTF(env, recv);
460 redef fun to_jvalue
(env
) do
461 return self.to_cstring
.to_jvalue
(env
)
466 fun to_jvalue
(env
: JniEnv): JValue is abstract