Merge branch 'comparators'
[nit.git] / lib / jvm.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2014 Romain Chanoir <romain.chanoir@courrier.uqam.ca>
4 #
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
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
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.
16
17 # Manipulates the Java Virtual Machine
18 #
19 # See: http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/jniTOC.html
20 module jvm is
21 c_compiler_option("-I $(JAVA_HOME)/include/")
22 c_linker_option("-L $(JNI_LIB_PATH) -ljvm")
23 end
24
25 in "C Header" `{
26 #include <jni.h>
27
28 `}
29
30 `{
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)){
33 return NULL;
34 }
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);
37 int i;
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);
43 c_array[i].i = val;
44 }else if (nullable_Object_is_a_Char(nullable_obj)){
45 char val = nullable_Object_as_Char(nullable_obj);
46 c_array[i].c = val;
47 }else if (nullable_Object_is_a_Bool(nullable_obj)){
48 int val = nullable_Object_as_Bool(nullable_obj);
49 c_array[i].z = val;
50 }else if(nullable_Object_is_a_Float(nullable_obj)){
51 float val = nullable_Object_as_Float(nullable_obj);
52 c_array[i].f = val;
53 }else if(nullable_Object_is_a_JObject(nullable_obj)){
54 jobject val = nullable_Object_as_JObject(nullable_obj);
55 c_array[i].l = val;
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);
60 c_array[i].l = js;
61 }else {
62 fprintf(stderr, "NOT YET SUPPORTED: nit objects are not supported\n");
63 exit(1);
64 }
65 }
66 return c_array;
67 }
68 `}
69
70 # Represents a jni JavaVM
71 extern class JavaVM `{JavaVM *`}
72 new(env_ref: JniEnvRef) import jni_error, JniEnvRef.jni_env=, JniEnv as nullable `{
73 JavaVM *jvm;
74 JNIEnv *env;
75 jint res;
76
77 JavaVMInitArgs args;
78 JavaVMOption options[1];
79 options[0].optionString = "-Djava.class.path=.";
80 args.version = 0x00010002;
81 args.options = options;
82 args.nOptions = 1;
83
84 res = JNI_CreateJavaVM(&jvm, (void**)&env, &args);
85
86 if (res != 0) {
87 JavaVM_jni_error(NULL, "Could not create Java VM");
88 return NULL;
89 }
90 else {
91 JniEnvRef_jni_env__assign(env_ref, JniEnv_as_nullable_JniEnv(env));
92 return jvm;
93 }
94 `}
95
96 fun jni_error(msg: NativeString)
97 do
98 print "JNI Error: {msg}"
99 abort
100 end
101
102 fun destroy_java_vm `{
103 (*recv)->DestroyJavaVM(recv);
104 `}
105 end
106
107 # Represents a jni JNIEnv, which is a thread in a JavaVM
108 extern class JniEnv `{JNIEnv *`}
109
110 # Get a class object from its fully-qualified name or null if the class cannot be found
111 fun find_class(class_name : String): JClass import String.to_cstring `{
112 return (*recv)->FindClass(recv,String_to_cstring(class_name));
113 `}
114
115 # Return the method id for an instance of a class or interface
116 # The method is determined by its name and signature
117 # To obtain the method ID of a constructor, supply "<init>" as the method name and "void(V)" as the return type
118 fun get_method_id(clazz : JClass, name : String, signature : String): JMethodID import String.to_cstring `{
119 return (*recv)->GetMethodID(recv, clazz, String_to_cstring(name), String_to_cstring(signature));
120 `}
121
122 # Construct a new Java object from the `clazz`, using the constructor ̀ method_id`
123 fun new_object(clazz: JClass, method_id: JMethodID): JObject `{
124 return (*recv)->NewObject(recv, clazz, method_id);
125 `}
126
127 # Return the JClass of `obj`
128 fun get_object_class(obj: JObject): JClass `{
129 return (*recv)->GetObjectClass(recv, obj);
130 `}
131
132 # Registers native methods with the class specified by the `clazz` argument
133 fun register_natives(clazz: JClass, method: JNINativeMethod, n_method : Int): Int `{
134 return (*recv)->RegisterNatives(recv, clazz, method, n_method);
135 `}
136
137 # Call a method on `obj` designed by `method_id` with an array `args` of arguments
138 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 `{
139 jvalue * args_tab = convert_array_of_Object_to_c(args, recv);
140 (*recv)->CallVoidMethodA(recv, obj, method_id, args_tab);
141 free(args_tab);
142 `}
143
144 # Call a method on `obj` designed by `method_id` with an array `args` of argument returning a JObject
145 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 `{
146 jvalue * args_tab = convert_array_of_Object_to_c(args, recv);
147 (*recv)->CallObjectMethod(recv, obj, method_id, args_tab);
148 free(args_tab);
149 `}
150
151 # Call a method on `obj` designed by `method_id` with an array `args` of arguments returning a Bool
152 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 `{
153 jvalue * args_tab = convert_array_of_Object_to_c(args, recv);
154 return (*recv)->CallBooleanMethod(recv, obj, method_id, args_tab);
155 free(args_tab);
156 `}
157
158 # Call a method on `obj` designed by `method_id` with an array `args` of arguments returning a Char
159 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 `{
160 jvalue * args_tab = convert_array_of_Object_to_c(args, recv);
161 return (*recv)->CallCharMethod(recv, obj, method_id, args_tab);
162 free(args_tab);
163 `}
164
165 # Call a method on `obj` designed by `method_id` with an array `args` of arguments returning an Int
166 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 `{
167 jvalue * args_tab = convert_array_of_Object_to_c(args, recv);
168 return (*recv)->CallIntMethod(recv, obj, method_id, args_tab);
169 free(args_tab);
170 `}
171
172 # Call a method on `obj` designed by `method_id` with an array `args` of arguments returning a Float
173 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 `{
174 jvalue * args_tab = convert_array_of_Object_to_c(args, recv);
175 return (*recv)->CallFloatMethod(recv, obj, method_id, args_tab);
176 free(args_tab);
177 `}
178
179 # Call a method on `obj` designed by `method_id` with an array `args` of arguments returning a NativeString
180 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 `{
181 jvalue * args_tab = convert_array_of_Object_to_c(args, recv);
182 jobject jobj = (*recv)->CallObjectMethod(recv, obj, method_id, args_tab);
183 free(args_tab);
184 return (char*)(*recv)->GetStringUTFChars(recv, (jstring)jobj, NULL);
185 `}
186
187 # Returns the field ID for an instance field of a class. The field is specified by its name and signature
188 fun get_field_id(clazz: JClass, name: String, sign: String): JFieldID import String.to_cstring `{
189 return (*recv)->GetFieldID(recv, clazz, String_to_cstring(name), String_to_cstring(sign));
190 `}
191
192 # 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()
193 fun get_object_field(obj: JObject, fieldID: JFieldID): JObject `{
194 return (*recv)->GetObjectField(recv, obj, fieldID);
195 `}
196
197 fun get_boolean_field(obj: JObject, fieldID: JFieldID): Bool `{
198 return (*recv)->GetBooleanField(recv, obj, fieldID);
199 `}
200
201 fun get_char_field(obj: JObject, fieldID: JFieldID): Char `{
202 return (*recv)->GetCharField(recv, obj, fieldID);
203 `}
204
205 fun get_int_field(obj: JObject, fieldID: JFieldID): Int `{
206 return (*recv)->GetIntField(recv, obj, fieldID);
207 `}
208
209 fun get_float_field(obj: JObject, fieldID: JFieldID): Float `{
210 return (*recv)->GetFloatField(recv, obj, fieldID);
211 `}
212
213 fun set_object_field(obj: JObject, fieldID: JFieldID, value: JObject) `{
214 (*recv)->SetObjectField(recv, obj, fieldID, value);
215 `}
216
217 fun set_boolean_field(obj: JObject, fieldID: JFieldID, value: Bool) `{
218 (*recv)->SetBooleanField(recv, obj, fieldID, value);
219 `}
220
221 fun set_char_field(obj: JObject, fieldID: JFieldID, value: Char) `{
222 (*recv)->SetCharField(recv, obj, fieldID, value);
223 `}
224
225 fun set_int_field(obj: JObject, fieldID: JFieldID, value: Int) `{
226 (*recv)->SetIntField(recv, obj, fieldID, value);
227 `}
228
229 fun set_float_field(obj: JObject, fieldID: JFieldID, value: Float) `{
230 (*recv)->SetFloatField(recv, obj, fieldID, value);
231 `}
232
233 # Check for pending exception without creating a local reference to the exception object
234 fun exception_check: Bool `{
235 return (*recv)->ExceptionCheck(recv);
236 `}
237
238 # Construct an exception object from the specified class with the message specified by `message` and causes that exception to be thrown
239 fun throw_new(clazz: JClass, message: String): Int import String.to_cstring `{
240 return (*recv)->ThrowNew(recv, clazz, String_to_cstring(message));
241 `}
242
243 # return the exception if there is one in the process of being thrown, or NULL if no exception is currently being thrown
244 fun exception_occurred: JObject `{
245 return (*recv)->ExceptionOccurred(recv);
246 `}
247
248 # prints an exception and backtrace to error channel
249 fun exception_describe `{
250 return (*recv)->ExceptionDescribe(recv);
251 `}
252
253 # clears any exception currently being thrown, has no effect if there is no exception
254 fun exception_clear `{
255 return (*recv)->ExceptionClear(recv);
256 `}
257
258 # Raise a fatal error
259 fun fatal_error(msg: String) import String.to_cstring `{
260 (*recv)->FatalError(recv, String_to_cstring(msg));
261 `}
262
263 # Transform a NIT String into a JObject
264 fun string_to_jobject(string: String): JObject `{
265 return (*recv)->NewStringUTF(recv, String_to_cstring(string));
266 `}
267 end
268
269 # used to initialize a JavaVM
270 class JniEnvRef
271 var jni_env: nullable JniEnv = null
272 end
273
274 # Represents a jni jclass
275 extern class JClass `{jclass`}
276 end
277
278 # Represents a jni jmethodID
279 extern class JMethodID `{jmethodID`}
280 end
281
282 # Represens a jni jobject
283 extern class JObject `{jobject`}
284 end
285
286 # Represents a jni JNINNativeMethod
287 extern class JNINativeMethod `{ JNINativeMethod* `}
288 fun name: String import NativeString.to_s `{
289 return NativeString_to_s(recv->name);
290 `}
291
292 fun name=(name: String) import String.to_cstring `{
293 recv->name = String_to_cstring(name);
294 `}
295
296 fun signature: String import NativeString.to_s `{
297 return NativeString_to_s(recv->signature);
298 `}
299
300 fun signature=(signature: String) import String.to_cstring `{
301 recv->signature = String_to_cstring(signature);
302 `}
303 end
304
305 # Represents a jni jfieldID
306 extern class JFieldID `{jfieldID`}
307 end
308
309 # Reprents a jni jvalue
310 extern class JValue `{jvalue`}
311
312 fun set_boolean(b: Bool) `{
313 recv.z = b;
314 `}
315
316 fun get_boolean:Bool `{
317 return recv.z;
318 `}
319
320 fun set_char(c: Char)`{
321 recv.c = c;
322 `}
323
324 fun get_char: Char `{
325 return recv.c;
326 `}
327
328 fun set_int(i: Int) `{
329 recv.i = i;
330 `}
331
332 fun get_int: Int `{
333 return recv.i;
334 `}
335
336 fun set_float(f: Float) `{
337 recv.f = f;
338 `}
339
340 fun get_float: Float `{
341 return recv.f;
342 `}
343
344 fun set_jobject(obj: JObject) `{
345 recv.l = obj;
346 `}
347
348 fun get_jobject: JObject `{
349 return recv.l;
350 `}
351 end
352
353 redef class Int
354 redef fun to_jvalue(env): JValue `{
355 jvalue value;
356 value.i = recv;
357 return value;
358 `}
359 end
360
361 redef class Float
362 redef fun to_jvalue(env): JValue `{
363 jvalue value;
364 value.f = recv;
365 return value;
366 `}
367 end
368
369 redef class Bool
370 redef fun to_jvalue(env): JValue `{
371 jvalue value;
372 value.z = recv;
373 return value;
374 `}
375 end
376
377 redef class NativeString
378 redef fun to_jvalue(env)`{
379 jvalue value;
380 value.l = (*env)->NewStringUTF(env, recv);
381 return value;
382 `}
383 end
384
385 redef class String
386 redef fun to_jvalue(env) do
387 return self.to_cstring.to_jvalue(env)
388 end
389 end
390
391 redef class Object
392 fun to_jvalue(env: JniEnv): JValue is abstract
393 end