jamvm

view src/jni.c @ 405:99039a39df1f

Support creating a DirectByteBuffer in OpenJDK from JNI.

2008-08-04 Andrew John Hughes <gnu_andrew@member.fsf.org>

* src/jni.c,
* src/symbol.h:
Support creating a DirectByteBuffer from JNI
under OpenJDK.
author andrew
date Tue Aug 05 06:24:55 2008 +0100 (2008-08-05)
parents 907df5a02819
children
line source
1 /*
2 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
3 * Robert Lougher <rob@lougher.org.uk>.
4 *
5 * This file is part of JamVM.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2,
10 * or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
22 #ifndef NO_JNI
23 #include <string.h>
24 #include <stdlib.h>
25 #include "jni.h"
26 #include "jam.h"
27 #include "thread.h"
28 #include "lock.h"
29 #include "symbol.h"
30 #include "excep.h"
32 #define JNI_VERSION JNI_VERSION_1_4
34 /* The extra used in expanding the local refs table.
35 * This must be >= size of JNIFrame to be thread safe
36 * wrt GC thread suspension */
37 #define LIST_INCR 8
39 /* The amount of local reference space "ensured" before
40 entering a JNI method. The method is garaunteed to
41 be able to create this amount without failure */
42 #define JNI_DEFAULT_LREFS 16
44 /* Forward declarations */
45 const jchar *Jam_GetStringChars(JNIEnv *env, jstring string, jboolean *isCopy);
46 void Jam_ReleaseStringChars(JNIEnv *env, jstring string, const jchar *chars);
47 jobject Jam_NewGlobalRef(JNIEnv *env, jobject obj);
48 void Jam_DeleteGlobalRef(JNIEnv *env, jobject obj);
49 JNIFrame *ensureJNILrefCapacity(int cap);
50 static void initJNIGrefs();
52 /* Cached values initialised on startup for JNI 1.4 NIO support */
53 static int buffCap_offset, buffAddr_offset, rawdata_offset;
54 static Class *buffImpl_class, *rawdata_class;
55 static MethodBlock *buffImpl_init_mb;
56 static char nio_init_OK = FALSE;
58 void initialiseJNI() {
59 FieldBlock *buffCap_fb, *buffAddr_fb, *rawdata_fb;
60 Class *buffer_class = NULL;
62 /* Initialise the global references table */
63 initJNIGrefs();
65 /* Cache class and method/fields for JNI 1.4 NIO support */
67 buffer_class = findSystemClass0(SYMBOL(java_nio_Buffer));
68 /* VMDIFF: GNU Classpath's direct buffer implementation is called
69 DirectByteBufferImpl.ReadWrite whereas OpenJDK's is simply DirectByteBuffer.
70 GNU Classpath requires that the pointer to the buffer is encapsulated
71 in a gnu.classpath.Pointer */
72 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
73 buffImpl_class = findSystemClass0(SYMBOL(java_nio_DirectByteBufferImpl_ReadWrite));
74 rawdata_class = findSystemClass0(sizeof(uintptr_t) == 4 ? SYMBOL(gnu_classpath_Pointer32)
75 : SYMBOL(gnu_classpath_Pointer64));
77 if(buffer_class != NULL && buffImpl_class != NULL && rawdata_class != NULL) {
78 buffImpl_init_mb = findMethod(buffImpl_class, SYMBOL(object_init),
79 SYMBOL(_java_lang_Object_gnu_classpath_Pointer_III__V));
80 buffCap_fb = findField(buffer_class, SYMBOL(cap), SYMBOL(I));
81 rawdata_fb = findField(rawdata_class, SYMBOL(data), sizeof(uintptr_t) == 4 ? SYMBOL(I)
82 : SYMBOL(J));
83 buffAddr_fb = findField(buffer_class, SYMBOL(address), SYMBOL(sig_gnu_classpath_Pointer));
84 }
86 if(buffImpl_init_mb == NULL || buffCap_fb == NULL ||
87 rawdata_fb == NULL || buffAddr_fb == NULL) {
88 return;
89 #elif WITH_JAVA_RUNTIME_LIBRARY_OPENJDK
90 buffImpl_class = findSystemClass0(SYMBOL(java_nio_DirectByteBuffer));
92 if(buffer_class != NULL && buffImpl_class != NULL) {
93 buffImpl_init_mb = findMethod(buffImpl_class, SYMBOL(object_init),
94 SYMBOL(_LI__V));
95 buffCap_fb = findField(buffer_class, SYMBOL(capacity), SYMBOL(I));
96 buffAddr_fb = findField(buffer_class, SYMBOL(address), SYMBOL(J));
97 }
99 if(buffImpl_init_mb == NULL || buffCap_fb == NULL ||
100 buffAddr_fb == NULL) {
101 return;
102 #endif
103 }
105 registerStaticClassRef(&buffImpl_class);
107 buffCap_offset = buffCap_fb->offset;
108 buffAddr_offset = buffAddr_fb->offset;
110 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
111 registerStaticClassRef(&rawdata_class);
112 rawdata_offset = rawdata_fb->offset;
113 #endif
115 nio_init_OK = TRUE;
116 }
118 int initJNILrefs() {
119 JNIFrame *frame = ensureJNILrefCapacity(JNI_DEFAULT_LREFS);
121 if(frame != NULL) {
122 frame->next_ref = frame->lrefs + frame->mb->args_count;
123 return TRUE;
124 }
126 return FALSE;
127 }
129 JNIFrame *expandJNILrefs(ExecEnv *ee, JNIFrame *frame, int incr) {
130 JNIFrame *new_frame = (JNIFrame*)((Object**)frame + incr);
132 if((char*)(new_frame + 1) > ee->stack_end)
133 return NULL;
135 memcpy(new_frame, frame, sizeof(JNIFrame));
136 new_frame->ostack = (uintptr_t*)(new_frame + 1);
137 ee->last_frame = (Frame*)new_frame;
138 memset(frame, 0, incr * sizeof(Object*));
139 return new_frame;
140 }
142 JNIFrame *ensureJNILrefCapacity(int cap) {
143 ExecEnv *ee = getExecEnv();
144 JNIFrame *frame = (JNIFrame*)ee->last_frame;
145 int size = (Object**)frame - frame->lrefs - frame->mb->args_count;
147 if(size < cap) {
148 int incr = cap-size;
149 if(incr < sizeof(JNIFrame)/sizeof(Object*))
150 incr = sizeof(JNIFrame)/sizeof(Object*);
152 if((frame = expandJNILrefs(ee, frame, incr)) == NULL)
153 signalException(java_lang_OutOfMemoryError, "JNI local references");
154 }
156 return frame;
157 }
159 Object *addJNILref(Object *ref) {
160 ExecEnv *ee = getExecEnv();
161 JNIFrame *frame = (JNIFrame*)ee->last_frame;
163 if(ref == NULL)
164 return NULL;
166 if(frame->next_ref == (Object**)frame)
167 if((frame = expandJNILrefs(ee, frame, LIST_INCR)) == NULL) {
168 jam_fprintf(stderr, "JNI - FatalError: cannot expand local references.\n");
169 exitVM(1);
170 }
172 return *frame->next_ref++ = ref;
173 }
175 void delJNILref(Object *ref) {
176 ExecEnv *ee = getExecEnv();
177 JNIFrame *frame = (JNIFrame*)ee->last_frame;
178 Object **opntr = frame->lrefs;
180 for(; opntr < frame->next_ref; opntr++)
181 if(*opntr == ref) {
182 *opntr = NULL;
183 return;
184 }
185 }
187 JNIFrame *pushJNILrefFrame(int cap) {
188 ExecEnv *ee = getExecEnv();
189 JNIFrame *frame = (JNIFrame*)ee->last_frame;
190 JNIFrame *new_frame = (JNIFrame*)((Object**)(frame + 1) + cap);
192 if((char*)(new_frame + 1) > ee->stack_end) {
193 signalException(java_lang_OutOfMemoryError, "JNI local references");
194 return NULL;
195 }
197 new_frame->lrefs = new_frame->next_ref = (Object**)(frame + 1);
198 new_frame->ostack = (uintptr_t*)(new_frame + 1);
199 new_frame->prev = frame->prev;
200 new_frame->mb = frame->mb;
202 memset(frame + 1, 0, cap * sizeof(Object*));
203 ee->last_frame = (Frame*)new_frame;
205 return new_frame;
206 }
208 void popJNILrefFrame() {
209 ExecEnv *ee = getExecEnv();
210 JNIFrame *frame = (JNIFrame*)ee->last_frame;
211 JNIFrame *prev = (JNIFrame*)frame->lrefs - 1;
213 ee->last_frame = (Frame*)prev;
214 }
216 static VMLock global_ref_lock;
217 static Object **global_ref_table;
218 static int global_ref_size = 0;
219 static int global_ref_next = 0;
220 static int global_ref_deleted = 0;
222 static void initJNIGrefs() {
223 initVMLock(global_ref_lock);
224 }
226 static Object *addJNIGref(Object *ref) {
227 Thread *self = threadSelf();
228 disableSuspend(self);
229 lockVMLock(global_ref_lock, self);
231 if(global_ref_next == global_ref_size) {
232 int new_size;
233 Object **new_table;
234 int i, j;
236 if(global_ref_deleted >= LIST_INCR) {
237 new_size = global_ref_size;
238 new_table = global_ref_table;
239 } else {
240 new_size = global_ref_size + LIST_INCR - global_ref_deleted;
241 new_table = (Object**)sysMalloc(new_size * sizeof(Object*));
242 }
244 for(i = 0, j = 0; i < global_ref_size; i++)
245 if(global_ref_table[i])
246 new_table[j++] = global_ref_table[i];
248 global_ref_next = j;
249 global_ref_size = new_size;
250 global_ref_table = new_table;
251 global_ref_deleted = 0;
252 }
254 global_ref_table[global_ref_next++] = ref;
256 unlockVMLock(global_ref_lock, self);
257 enableSuspend(self);
259 return ref;
260 }
262 static void delJNIGref(Object *ref) {
263 Thread *self = threadSelf();
264 int i;
266 disableSuspend(self);
267 lockVMLock(global_ref_lock, self);
269 for(i = 0; i < global_ref_next; i++)
270 if(global_ref_table[i] == ref) {
271 global_ref_table[i] = NULL;
272 global_ref_deleted++;
273 break;
274 }
276 unlockVMLock(global_ref_lock, self);
277 enableSuspend(self);
278 }
280 /* Called during mark phase of GC. Safe from
281 suspension but must grab lock to ensure list
282 isn't being modified by another thread. */
284 void markJNIGlobalRefs() {
285 Thread *self = threadSelf();
286 int i;
288 lockVMLock(global_ref_lock, self);
290 for(i = 0; i < global_ref_next; i++)
291 if(global_ref_table[i])
292 markConservativeRoot(global_ref_table[i]);
294 unlockVMLock(global_ref_lock, self);
295 }
297 /* Extensions added to JNI in JDK 1.4 */
299 jobject Jam_NewDirectByteBuffer(JNIEnv *env, void *addr, jlong capacity) {
300 Object *buff, *rawdata;
302 if(!nio_init_OK)
303 return NULL;
305 /* VMDIFF: GNU Classpath encapsulates the pointer in a Pointer object
306 referenced by the rawdata variable. It also requires more arguments
307 which are simply defaulted on OpenJDK. */
308 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
309 if((buff = allocObject(buffImpl_class)) != NULL &&
310 (rawdata = allocObject(rawdata_class)) != NULL) {
312 INST_DATA(rawdata)[rawdata_offset] = (uintptr_t)addr;
313 executeMethod(buff, buffImpl_init_mb, NULL, rawdata, (int)capacity,
314 (int)capacity, 0);
315 }
316 #elif WITH_JAVA_RUNTIME_LIBRARY_OPENJDK
317 if((buff = allocObject(buffImpl_class)) != NULL)
318 executeMethod(buff, buffImpl_init_mb, (jlong) addr, (jint)capacity);
319 #endif
321 return (jobject) addJNILref(buff);
322 }
324 static void *Jam_GetDirectBufferAddress(JNIEnv *env, jobject buffer) {
325 Object *buff = (Object*)buffer;
327 if(!nio_init_OK)
328 return NULL;
330 if(buff != NULL) {
331 /* VMDIFF: GNU Classpath uses a gnu.classpath.Pointer object to
332 store the address whereas it can be found in the buffer itself
333 in OpenJDK. */
334 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
335 Object *rawdata = (Object *)INST_DATA(buff)[buffAddr_offset];
336 if(rawdata != NULL)
337 return (void*)INST_DATA(rawdata)[rawdata_offset];
338 #elif WITH_JAVA_RUNTIME_LIBRARY_OPENJDK
339 return (void*)INST_DATA(buff)[buffAddr_offset];
340 #endif
341 }
343 return NULL;
344 }
346 jlong Jam_GetDirectBufferCapacity(JNIEnv *env, jobject buffer) {
347 Object *buff = (Object*)buffer;
349 if(!nio_init_OK)
350 return -1;
352 if(buff != NULL) {
353 Object *rawdata = (Object *)INST_DATA(buff)[buffAddr_offset];
354 if(rawdata != NULL)
355 return (jlong)INST_DATA(buff)[buffCap_offset];
356 }
358 return -1;
359 }
361 /* Extensions added to JNI in JDK 1.2 */
363 jmethodID Jam_FromReflectedMethod(JNIEnv *env, jobject method) {
364 return mbFromReflectObject((Object*)method);
365 }
367 jfieldID Jam_FromReflectedField(JNIEnv *env, jobject field) {
368 return fbFromReflectObject((Object*)field);
369 }
371 jobject Jam_ToReflectedMethod(JNIEnv *env, jclass cls, jmethodID methodID, jboolean isStatic) {
372 MethodBlock *mb = (MethodBlock *)methodID;
373 if(mb->name == SYMBOL(object_init))
374 return (jobject) createReflectConstructorObject(mb);
375 else
376 return (jobject) createReflectMethodObject(mb);
377 }
379 jobject Jam_ToReflectedField(JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic) {
380 return (jobject) createReflectFieldObject((FieldBlock *)fieldID);
381 }
383 jint Jam_PushLocalFrame(JNIEnv *env, jint capacity) {
384 return pushJNILrefFrame(capacity) == NULL ? JNI_ERR : JNI_OK;
385 }
387 jobject Jam_PopLocalFrame(JNIEnv *env, jobject result) {
388 popJNILrefFrame();
389 return addJNILref(result);
390 }
392 jobject Jam_NewLocalRef(JNIEnv *env, jobject obj) {
393 return addJNILref(obj);
394 }
396 jint Jam_EnsureLocalCapacity(JNIEnv *env, jint capacity) {
397 return ensureJNILrefCapacity(capacity) == NULL ? JNI_ERR : JNI_OK;
398 }
400 void Jam_GetStringRegion(JNIEnv *env, jstring string, jsize start, jsize len, jchar *buf) {
401 if((start + len) > getStringLen((Object*)string))
402 signalException(java_lang_StringIndexOutOfBoundsException, NULL);
403 else
404 memcpy(buf, getStringChars((Object*)string) + start, len * sizeof(short));
405 }
407 void Jam_GetStringUTFRegion(JNIEnv *env, jstring string, jsize start, jsize len, char *buf) {
408 if((start + len) > getStringLen((Object*)string))
409 signalException(java_lang_StringIndexOutOfBoundsException, NULL);
410 else
411 StringRegion2Utf8((Object*)string, start, len, buf);
412 }
414 void *Jam_GetPrimitiveArrayCritical(JNIEnv *env, jarray array, jboolean *isCopy) {
415 if(isCopy != NULL)
416 *isCopy = JNI_FALSE;
417 addJNIGref((Object*)array);
418 return ARRAY_DATA((Object*)array);
419 }
421 void Jam_ReleasePrimitiveArrayCritical(JNIEnv *env, jarray array, void *carray, jint mode) {
422 delJNIGref((Object*)array);
423 }
425 const jchar *Jam_GetStringCritical(JNIEnv *env, jstring string, jboolean *isCopy) {
426 return Jam_GetStringChars(env, string, isCopy);
427 }
429 void Jam_ReleaseStringCritical(JNIEnv *env, jstring string, const jchar *chars) {
430 Jam_ReleaseStringChars(env, string, chars);
431 }
433 jweak Jam_NewWeakGlobalRef(JNIEnv *env, jobject obj) {
434 return Jam_NewGlobalRef(env, obj);
435 }
437 void Jam_DeleteWeakGlobalRef(JNIEnv *env, jweak obj) {
438 Jam_DeleteGlobalRef(env, obj);
439 }
441 jboolean Jam_ExceptionCheck(JNIEnv *env) {
442 return exceptionOccurred() ? JNI_TRUE : JNI_FALSE;
443 }
445 /* JNI 1.1 interface */
447 jint Jam_GetVersion(JNIEnv *env) {
448 return JNI_VERSION;
449 }
451 jclass Jam_DefineClass(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize bufLen) {
452 return (jclass)defineClass((char*)name, (char *)buf, 0, (int)bufLen, (Object *)loader, NULL);
453 }
455 jclass Jam_FindClass(JNIEnv *env, const char *name) {
456 /* We use the class loader associated with the calling native method.
457 However, if this has been called from an attached thread there may
458 be no native Java frame. In this case use the system class loader */
459 Frame *last = getExecEnv()->last_frame;
460 Object *loader;
462 if(last->prev) {
463 ClassBlock *cb = CLASS_CB(last->mb->class);
464 loader = cb->class_loader;
466 /* Ensure correct context if called from JNI_OnLoad */
467 if(loader == NULL && cb->name == SYMBOL(java_lang_VMRuntime))
468 loader = (Object*)last->lvars[1];
469 } else
470 loader = getSystemClassLoader();
472 return (jclass) findClassFromClassLoader((char*) name, loader);
473 }
475 jclass Jam_GetSuperClass(JNIEnv *env, jclass clazz) {
476 ClassBlock *cb = CLASS_CB((Class *)clazz);
477 return IS_INTERFACE(cb) ? NULL : (jclass)cb->super;
478 }
480 jboolean Jam_IsAssignableFrom(JNIEnv *env, jclass clazz1, jclass clazz2) {
481 return isInstanceOf((Class*)clazz2, (Class*)clazz1);
482 }
484 jint Jam_Throw(JNIEnv *env, jthrowable obj) {
485 Object *ob = (Object*)obj;
486 setException(ob);
487 return JNI_TRUE;
488 }
490 jint Jam_ThrowNew(JNIEnv *env, jclass clazz, const char *message) {
491 signalExceptionClass((Class*)clazz, (char*)message);
492 return JNI_TRUE;
493 }
495 jthrowable Jam_ExceptionOccurred(JNIEnv *env) {
496 return (jthrowable) addJNILref(exceptionOccurred());
497 }
499 void Jam_ExceptionDescribe(JNIEnv *env) {
500 printException();
501 }
503 void Jam_ExceptionClear(JNIEnv *env) {
504 clearException();
505 }
507 void Jam_FatalError(JNIEnv *env, const char *message) {
508 jam_fprintf(stderr, "JNI - FatalError: %s\n", message);
509 exitVM(1);
510 }
512 jobject Jam_NewGlobalRef(JNIEnv *env, jobject obj) {
513 return addJNIGref((Object*)obj);
514 }
516 void Jam_DeleteGlobalRef(JNIEnv *env, jobject obj) {
517 delJNIGref((Object*)obj);
518 }
520 void Jam_DeleteLocalRef(JNIEnv *env, jobject obj) {
521 delJNILref((Object*)obj);
522 }
524 jboolean Jam_IsSameObject(JNIEnv *env, jobject obj1, jobject obj2) {
525 return obj1 == obj2;
526 }
528 /* JNI helper function. The class may be invalid
529 or it may not have been initialised yet */
530 Object *allocObjectClassCheck(Class *class) {
531 ClassBlock *cb = CLASS_CB(class);
533 /* Check the class can be instantiated */
534 if(cb->access_flags & (ACC_INTERFACE | ACC_ABSTRACT)) {
535 signalException(java_lang_InstantiationError, cb->name);
536 return NULL;
537 }
539 /* Creating an instance of a class is an active use;
540 make sure it is initialised */
541 if(initClass(class) == NULL)
542 return NULL;
544 return allocObject(class);
545 }
547 jobject Jam_AllocObject(JNIEnv *env, jclass clazz) {
548 return (jobject) addJNILref(allocObjectClassCheck((Class*)clazz));
549 }
551 jclass Jam_GetObjectClass(JNIEnv *env, jobject obj) {
552 return (jobject)((Object*)obj)->class;
553 }
555 jboolean Jam_IsInstanceOf(JNIEnv *env, jobject obj, jclass clazz) {
556 return (obj == NULL) || isInstanceOf((Class*)clazz, ((Object*)obj)->class);
557 }
559 jmethodID getMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig, char is_static) {
560 Class *class = initClass((Class *)clazz);
561 MethodBlock *mb = NULL;
563 if(class != NULL) {
564 if(!IS_PRIMITIVE(CLASS_CB(class))) {
565 char *method_name = findUtf8((char*)name), *method_sig = findUtf8((char*)sig);
567 if(method_name != NULL && method_sig != NULL) {
568 if(method_name == SYMBOL(object_init) ||
569 method_name == SYMBOL(class_init))
570 mb = findMethod(class, method_name, method_sig);
571 else
572 mb = lookupMethod(class, method_name, method_sig);
573 }
574 }
576 if(mb == NULL || ((mb->access_flags & ACC_STATIC) != 0) != is_static)
577 signalException(java_lang_NoSuchMethodError, (char*)name);
578 }
580 return (jmethodID) mb;
581 }
583 jmethodID Jam_GetMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig) {
584 return getMethodID(env, clazz, name, sig, FALSE);
585 }
587 jfieldID Jam_GetFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig) {
588 char *field_name = findUtf8((char*)name), *field_sig = findUtf8((char*)sig);
589 Class *class = initClass((Class *)clazz);
590 FieldBlock *fb = NULL;
592 if(class != NULL) {
593 if(field_name != NULL && field_sig != NULL)
594 fb = lookupField(class, field_name, field_sig);
596 if(fb == NULL)
597 signalException(java_lang_NoSuchFieldError, field_name);
598 }
600 return (jfieldID) fb;
601 }
603 jmethodID Jam_GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig) {
604 return getMethodID(env, clazz, name, sig, TRUE);
605 }
607 jfieldID Jam_GetStaticFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig) {
608 char *field_name = findUtf8((char*)name), *field_sig = findUtf8((char*)sig);
609 Class *class = initClass((Class *)clazz);
610 FieldBlock *fb = NULL;
612 if(class != NULL) {
613 if(field_name != NULL && field_sig != NULL)
614 fb = findField(class, field_name, field_sig);
616 if(fb == NULL)
617 signalException(java_lang_NoSuchFieldError, field_name);
618 }
620 return (jfieldID) fb;
621 }
623 jstring Jam_NewString(JNIEnv *env, const jchar *unicodeChars, jsize len) {
624 return (jstring) addJNILref(createStringFromUnicode((unsigned short*)unicodeChars, len));
625 }
627 jsize Jam_GetStringLength(JNIEnv *env, jstring string) {
628 return getStringLen((Object*)string);
629 }
631 const jchar *Jam_GetStringChars(JNIEnv *env, jstring string, jboolean *isCopy) {
632 if(isCopy != NULL)
633 *isCopy = JNI_FALSE;
635 /* Pin the reference */
636 addJNIGref(getStringCharsArray((Object*)string));
638 return (const jchar *)getStringChars((Object*)string);
639 }
641 void Jam_ReleaseStringChars(JNIEnv *env, jstring string, const jchar *chars) {
642 /* Unpin the reference */
643 delJNIGref(getStringCharsArray((Object*)string));
644 }
646 jstring Jam_NewStringUTF(JNIEnv *env, const char *bytes) {
647 return (jstring) addJNILref(createString((char*)bytes));
648 }
650 jsize Jam_GetStringUTFLength(JNIEnv *env, jstring string) {
651 if(string == NULL)
652 return 0;
653 return getStringUtf8Len((Object*)string);
654 }
656 const char *Jam_GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy) {
657 if(isCopy != NULL)
658 *isCopy = JNI_TRUE;
660 if(string == NULL)
661 return NULL;
662 return (const char*)String2Utf8((Object*)string);
663 }
665 void Jam_ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *chars) {
666 sysFree((void*)chars);
667 }
669 jsize Jam_GetArrayLength(JNIEnv *env, jarray array) {
670 return ARRAY_LEN((Object*)array);
671 }
673 jobject Jam_NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...) {
674 Object *ob = allocObjectClassCheck((Class*)clazz);
676 if(ob) {
677 va_list jargs;
678 va_start(jargs, methodID);
679 executeMethodVaList(ob, ob->class, (MethodBlock*)methodID, jargs);
680 va_end(jargs);
681 }
683 return (jobject) addJNILref(ob);
684 }
686 jobject Jam_NewObjectA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args) {
687 Object *ob = allocObjectClassCheck((Class*)clazz);
689 if(ob) executeMethodList(ob, ob->class, (MethodBlock*)methodID, (u8*)args);
690 return (jobject) addJNILref(ob);
691 }
693 jobject Jam_NewObjectV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args) {
694 Object *ob = allocObjectClassCheck((Class*)clazz);
696 if(ob) executeMethodVaList(ob, ob->class, (MethodBlock*)methodID, args);
697 return (jobject) addJNILref(ob);
698 }
700 jarray Jam_NewObjectArray(JNIEnv *env, jsize length, jclass elementClass, jobject initialElement) {
701 char *element_name = CLASS_CB((Class*)elementClass)->name;
702 char ac_name[strlen(element_name) + 4];
703 Class *array_class;
705 if(length < 0) {
706 signalException(java_lang_NegativeArraySizeException, NULL);
707 return NULL;
708 }
710 if(element_name[0] == '[')
711 strcat(strcpy(ac_name, "["), element_name);
712 else
713 strcat(strcat(strcpy(ac_name, "[L"), element_name), ";");
715 array_class = findArrayClassFromClass(ac_name, (Class*)elementClass);
716 if(array_class != NULL) {
717 Object *array = allocArray(array_class, length, sizeof(Object*));
718 if(array != NULL) {
719 if(initialElement != NULL) {
720 Object **data = ARRAY_DATA(array);
722 while(length--)
723 *data++ = (Object*) initialElement;
724 }
725 return (jarray) addJNILref(array);
726 }
727 }
728 return NULL;
729 }
731 jarray Jam_GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index) {
732 return (jarray) addJNILref(((Object**)ARRAY_DATA((Object*)array))[index]);
733 }
735 void Jam_SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject value) {
736 ((Object**)ARRAY_DATA((Object*)array))[index] = (Object*)value;
737 }
739 jint Jam_RegisterNatives(JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint nMethods) {
740 return JNI_OK;
741 }
743 jint Jam_UnregisterNatives(JNIEnv *env, jclass clazz) {
744 return JNI_OK;
745 }
747 jint Jam_MonitorEnter(JNIEnv *env, jobject obj) {
748 objectLock((Object*)obj);
749 return JNI_OK;
750 }
752 jint Jam_MonitorExit(JNIEnv *env, jobject obj) {
753 objectUnlock((Object*)obj);
754 return JNI_OK;
755 }
757 struct _JNIInvokeInterface Jam_JNIInvokeInterface;
758 JavaVM invokeIntf = &Jam_JNIInvokeInterface;
760 jint Jam_GetJavaVM(JNIEnv *env, JavaVM **vm) {
761 *vm = &invokeIntf;
762 return JNI_OK;
763 }
765 #define GET_FIELD(type, native_type) \
766 native_type Jam_Get##type##Field(JNIEnv *env, jobject obj, jfieldID fieldID) { \
767 FieldBlock *fb = (FieldBlock *) fieldID; \
768 Object *ob = (Object*) obj; \
769 return *(native_type *)&(INST_DATA(ob)[fb->offset]); \
770 }
772 #define INT_GET_FIELD(type, native_type) \
773 native_type Jam_Get##type##Field(JNIEnv *env, jobject obj, jfieldID fieldID) { \
774 FieldBlock *fb = (FieldBlock *) fieldID; \
775 Object *ob = (Object*) obj; \
776 return (native_type)(INST_DATA(ob)[fb->offset]); \
777 }
779 #define SET_FIELD(type, native_type) \
780 void Jam_Set##type##Field(JNIEnv *env, jobject obj, jfieldID fieldID, native_type value) { \
781 Object *ob = (Object*) obj; \
782 FieldBlock *fb = (FieldBlock *) fieldID; \
783 *(native_type *)&(INST_DATA(ob)[fb->offset]) = value; \
784 }
786 #define INT_SET_FIELD(type, native_type) \
787 void Jam_Set##type##Field(JNIEnv *env, jobject obj, jfieldID fieldID, native_type value) { \
788 Object *ob = (Object*) obj; \
789 FieldBlock *fb = (FieldBlock *) fieldID; \
790 INST_DATA(ob)[fb->offset] = (intptr_t)value; \
791 }
793 #define GET_STATIC_FIELD(type, native_type) \
794 native_type Jam_GetStatic##type##Field(JNIEnv *env, jclass clazz, jfieldID fieldID) { \
795 FieldBlock *fb = (FieldBlock *) fieldID; \
796 return *(native_type *)&fb->static_value; \
797 }
799 #define INT_GET_STATIC_FIELD(type, native_type) \
800 native_type Jam_GetStatic##type##Field(JNIEnv *env, jclass clazz, jfieldID fieldID) { \
801 FieldBlock *fb = (FieldBlock *) fieldID; \
802 return (native_type)fb->static_value; \
803 }
805 #define SET_STATIC_FIELD(type, native_type) \
806 void Jam_SetStatic##type##Field(JNIEnv *env, jclass clazz, jfieldID fieldID, \
807 native_type value) { \
808 FieldBlock *fb = (FieldBlock *) fieldID; \
809 *(native_type *)&fb->static_value = value; \
810 }
812 #define INT_SET_STATIC_FIELD(type, native_type) \
813 void Jam_SetStatic##type##Field(JNIEnv *env, jclass clazz, jfieldID fieldID, \
814 native_type value) { \
815 FieldBlock *fb = (FieldBlock *) fieldID; \
816 fb->static_value = (intptr_t)value; \
817 }
819 #define FIELD_ACCESS(type, native_type) \
820 GET_FIELD(type, native_type); \
821 SET_FIELD(type, native_type); \
822 GET_STATIC_FIELD(type, native_type); \
823 SET_STATIC_FIELD(type, native_type);
825 #define INT_FIELD_ACCESS(type, native_type) \
826 INT_GET_FIELD(type, native_type); \
827 INT_SET_FIELD(type, native_type); \
828 INT_GET_STATIC_FIELD(type, native_type); \
829 INT_SET_STATIC_FIELD(type, native_type);
831 INT_FIELD_ACCESS(Boolean, jboolean);
832 INT_FIELD_ACCESS(Byte, jbyte);
833 INT_FIELD_ACCESS(Char, jchar);
834 INT_FIELD_ACCESS(Short, jshort);
835 INT_FIELD_ACCESS(Int, jint);
836 FIELD_ACCESS(Long, jlong);
837 FIELD_ACCESS(Float, jfloat);
838 FIELD_ACCESS(Double, jdouble);
840 jobject Jam_GetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID) {
841 FieldBlock *fb = (FieldBlock *) fieldID;
842 Object *ob = (Object*) obj;
843 return (jobject) addJNILref((Object*)(INST_DATA(ob)[fb->offset]));
844 }
846 void Jam_SetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID, jobject value) {
847 Object *ob = (Object*) obj;
848 FieldBlock *fb = (FieldBlock *) fieldID;
849 INST_DATA(ob)[fb->offset] = (uintptr_t)value;
850 }
852 jobject Jam_GetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldID) {
853 FieldBlock *fb = (FieldBlock *) fieldID;
854 return (jobject) addJNILref((Object*)fb->static_value);
855 }
857 void Jam_SetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value) {
858 FieldBlock *fb = (FieldBlock *) fieldID;
859 fb->static_value = (uintptr_t)value;
860 }
862 #define VIRTUAL_METHOD(type, native_type) \
863 native_type Jam_Call##type##Method(JNIEnv *env, jobject obj, jmethodID mID, ...) { \
864 Object *ob = (Object *)obj; \
865 native_type *ret; \
866 va_list jargs; \
867 \
868 MethodBlock *mb = lookupVirtualMethod(ob, (MethodBlock*)mID); \
869 if(mb == NULL) \
870 return (native_type)0; \
871 \
872 va_start(jargs, mID); \
873 ret = (native_type*) executeMethodVaList(ob, ob->class, mb, jargs); \
874 va_end(jargs); \
875 \
876 return *ret; \
877 } \
878 \
879 native_type Jam_Call##type##MethodV(JNIEnv *env, jobject obj, jmethodID mID, va_list jargs) { \
880 Object *ob = (Object *)obj; \
881 MethodBlock *mb = lookupVirtualMethod(ob, (MethodBlock*)mID); \
882 return mb == NULL ? (native_type)0 : \
883 *(native_type*)executeMethodVaList(ob, ob->class, mb, jargs); \
884 } \
885 \
886 native_type Jam_Call##type##MethodA(JNIEnv *env, jobject obj, jmethodID mID, jvalue *jargs) { \
887 Object *ob = (Object *)obj; \
888 MethodBlock *mb = lookupVirtualMethod(ob, (MethodBlock*)mID); \
889 return mb == NULL ? (native_type)0 : \
890 *(native_type*)executeMethodList(ob, ob->class, mb, (u8*)jargs); \
891 }
893 #define INT_VIRTUAL_METHOD(type, native_type) \
894 native_type Jam_Call##type##Method(JNIEnv *env, jobject obj, jmethodID mID, ...) { \
895 Object *ob = (Object *)obj; \
896 uintptr_t *ret; \
897 va_list jargs; \
898 \
899 MethodBlock *mb = lookupVirtualMethod(ob, (MethodBlock*)mID); \
900 if(mb == NULL) \
901 return (native_type)0; \
902 \
903 va_start(jargs, mID); \
904 ret = executeMethodVaList(ob, ob->class, mb, jargs); \
905 va_end(jargs); \
906 \
907 return (native_type)*ret; \
908 } \
909 \
910 native_type Jam_Call##type##MethodV(JNIEnv *env, jobject obj, jmethodID mID, va_list jargs) { \
911 Object *ob = (Object *)obj; \
912 MethodBlock *mb = lookupVirtualMethod(ob, (MethodBlock*)mID); \
913 return mb == NULL ? (native_type)0 : \
914 (native_type)*(uintptr_t*)executeMethodVaList(ob, ob->class, mb, jargs); \
915 } \
916 \
917 native_type Jam_Call##type##MethodA(JNIEnv *env, jobject obj, jmethodID mID, jvalue *jargs) { \
918 Object *ob = (Object *)obj; \
919 MethodBlock *mb = lookupVirtualMethod(ob, (MethodBlock*)mID); \
920 return mb == NULL ? (native_type)0 : (native_type)*(uintptr_t*) \
921 executeMethodList(ob, ob->class, mb, (u8*)jargs); \
922 }
924 #define NONVIRTUAL_METHOD(type, native_type) \
925 native_type Jam_CallNonvirtual##type##Method(JNIEnv *env, jobject obj, jclass clazz, \
926 jmethodID methodID, ...) { \
927 native_type *ret; \
928 va_list jargs; \
929 \
930 va_start(jargs, methodID); \
931 ret = (native_type*) \
932 executeMethodVaList((Object*)obj, (Class*)clazz, (MethodBlock*)methodID, jargs); \
933 va_end(jargs); \
934 \
935 return *ret; \
936 } \
937 \
938 native_type Jam_CallNonvirtual##type##MethodV(JNIEnv *env, jobject obj, jclass clazz, \
939 jmethodID methodID, va_list jargs) { \
940 return *(native_type*) \
941 executeMethodVaList((Object*)obj, (Class*)clazz, (MethodBlock*)methodID, jargs); \
942 } \
943 \
944 native_type Jam_CallNonvirtual##type##MethodA(JNIEnv *env, jobject obj, jclass clazz, \
945 jmethodID methodID, jvalue *jargs) { \
946 return *(native_type*) \
947 executeMethodList((Object*)obj, (Class*)clazz, (MethodBlock*)methodID, (u8*)jargs); \
948 }
950 #define INT_NONVIRTUAL_METHOD(type, native_type) \
951 native_type Jam_CallNonvirtual##type##Method(JNIEnv *env, jobject obj, jclass clazz, \
952 jmethodID methodID, ...) { \
953 uintptr_t *ret; \
954 va_list jargs; \
955 \
956 va_start(jargs, methodID); \
957 ret = executeMethodVaList((Object*)obj, (Class*)clazz, (MethodBlock*)methodID, jargs); \
958 va_end(jargs); \
959 \
960 return (native_type)*ret; \
961 } \
962 \
963 native_type Jam_CallNonvirtual##type##MethodV(JNIEnv *env, jobject obj, jclass clazz, \
964 jmethodID methodID, va_list jargs) { \
965 return (native_type)*(uintptr_t*) \
966 executeMethodVaList((Object*)obj, (Class*)clazz, (MethodBlock*)methodID, jargs); \
967 } \
968 \
969 native_type Jam_CallNonvirtual##type##MethodA(JNIEnv *env, jobject obj, jclass clazz, \
970 jmethodID methodID, jvalue *jargs) { \
971 return (native_type)*(uintptr_t*) \
972 executeMethodList((Object*)obj, (Class*)clazz, (MethodBlock*)methodID, (u8*)jargs); \
973 }
975 #define STATIC_METHOD(type, native_type) \
976 native_type Jam_CallStatic##type##Method(JNIEnv *env, jclass clazz, \
977 jmethodID methodID, ...) { \
978 native_type *ret; \
979 va_list jargs; \
980 \
981 va_start(jargs, methodID); \
982 ret = (native_type*) executeMethodVaList(NULL, (Class*)clazz, (MethodBlock*)methodID, jargs);\
983 va_end(jargs); \
984 \
985 return *ret; \
986 } \
987 \
988 native_type Jam_CallStatic##type##MethodV(JNIEnv *env, jclass clazz, jmethodID methodID, \
989 va_list jargs) { \
990 return *(native_type*) \
991 executeMethodVaList(NULL, (Class*)clazz, (MethodBlock*)methodID, jargs); \
992 } \
993 \
994 native_type Jam_CallStatic##type##MethodA(JNIEnv *env, jclass clazz, jmethodID methodID, \
995 jvalue *jargs) { \
996 return *(native_type*) \
997 executeMethodList(NULL, (Class*)clazz, (MethodBlock*)methodID, (u8*)jargs); \
998 }
1000 #define INT_STATIC_METHOD(type, native_type) \
1001 native_type Jam_CallStatic##type##Method(JNIEnv *env, jclass clazz, \
1002 jmethodID methodID, ...) { \
1003 uintptr_t *ret; \
1004 va_list jargs; \
1006 va_start(jargs, methodID); \
1007 ret = executeMethodVaList(NULL, (Class*)clazz, (MethodBlock*)methodID, jargs); \
1008 va_end(jargs); \
1010 return (native_type)*ret; \
1011 } \
1013 native_type Jam_CallStatic##type##MethodV(JNIEnv *env, jclass clazz, jmethodID methodID, \
1014 va_list jargs) { \
1015 return (native_type) *(uintptr_t*) \
1016 executeMethodVaList(NULL, (Class*)clazz, (MethodBlock*)methodID, jargs); \
1017 } \
1019 native_type Jam_CallStatic##type##MethodA(JNIEnv *env, jclass clazz, jmethodID methodID, \
1020 jvalue *jargs) { \
1021 return (native_type)*(uintptr_t*) \
1022 executeMethodList(NULL, (Class*)clazz, (MethodBlock*)methodID, (u8*)jargs); \
1025 #define CALL_METHOD(access) \
1026 INT_##access##_METHOD(Boolean, jboolean); \
1027 INT_##access##_METHOD(Byte, jbyte); \
1028 INT_##access##_METHOD(Char, jchar); \
1029 INT_##access##_METHOD(Short, jshort); \
1030 INT_##access##_METHOD(Int, jint); \
1031 access##_METHOD(Long, jlong); \
1032 access##_METHOD(Float, jfloat); \
1033 access##_METHOD(Double, jdouble);
1035 CALL_METHOD(VIRTUAL);
1036 CALL_METHOD(NONVIRTUAL);
1037 CALL_METHOD(STATIC);
1039 jobject Jam_CallObjectMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...) {
1040 Object *ob = (Object *)obj;
1041 Object *ret;
1042 va_list jargs;
1043 MethodBlock *mb = lookupVirtualMethod(ob, (MethodBlock*)methodID);
1044 if(mb == NULL)
1045 return NULL;
1047 va_start(jargs, methodID);
1048 ret = addJNILref(*(Object**) executeMethodVaList(ob, ob->class, mb, jargs));
1049 va_end(jargs);
1050 return (jobject)ret;
1053 jobject Jam_CallObjectMethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list jargs) {
1054 Object *ob = (Object *)obj;
1055 MethodBlock *mb = lookupVirtualMethod(ob, (MethodBlock*)methodID);
1057 return mb == NULL ? NULL : (jobject)addJNILref(*(Object**)
1058 executeMethodVaList(ob, ob->class, mb, jargs));
1061 jobject Jam_CallObjectMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *jargs) {
1062 Object *ob = (Object *)obj;
1063 MethodBlock *mb = lookupVirtualMethod(ob, (MethodBlock*)methodID);
1065 return mb == NULL ? NULL : (jobject)addJNILref(*(Object**)
1066 executeMethodList(ob, ob->class, mb, (u8*)jargs));
1069 jobject Jam_CallNonvirtualObjectMethod(JNIEnv *env, jobject obj, jclass clazz,
1070 jmethodID methodID, ...) {
1071 Object *ret;
1072 va_list jargs;
1073 va_start(jargs, methodID);
1074 ret = addJNILref(*(Object**) executeMethodVaList((Object*)obj,
1075 (Class*)clazz, (MethodBlock*)methodID, jargs));
1076 va_end(jargs);
1077 return (jobject)ret;
1080 jobject Jam_CallNonvirtualObjectMethodV(JNIEnv *env, jobject obj, jclass clazz,
1081 jmethodID methodID, va_list jargs) {
1082 return (jobject)addJNILref(*(Object**) executeMethodVaList((Object*)obj,
1083 (Class*)clazz, (MethodBlock*)methodID, jargs));
1086 jobject Jam_CallNonvirtualObjectMethodA(JNIEnv *env, jobject obj, jclass clazz,
1087 jmethodID methodID, jvalue *jargs) {
1088 return (jobject)addJNILref(*(Object**) executeMethodList((Object*)obj,
1089 (Class*)clazz, (MethodBlock*)methodID, (u8*)jargs));
1092 jobject Jam_CallStaticObjectMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...) {
1093 Object *ret;
1094 va_list jargs;
1095 va_start(jargs, methodID);
1096 ret = addJNILref(*(Object**) executeMethodVaList(NULL,
1097 (Class*)clazz, (MethodBlock*)methodID, jargs));
1098 va_end(jargs);
1099 return (jobject)ret;
1102 jobject Jam_CallStaticObjectMethodV(JNIEnv *env, jclass clazz,
1103 jmethodID methodID, va_list jargs) {
1104 return (jobject)addJNILref(*(Object**) executeMethodVaList(NULL,
1105 (Class*)clazz, (MethodBlock*)methodID, jargs));
1108 jobject Jam_CallStaticObjectMethodA(JNIEnv *env, jclass clazz,
1109 jmethodID methodID, jvalue *jargs) {
1110 return (jobject)addJNILref(*(Object**) executeMethodList(NULL,
1111 (Class*)clazz, (MethodBlock*)methodID, (u8*)jargs));
1114 void Jam_CallVoidMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...) {
1115 va_list jargs;
1116 MethodBlock *mb;
1117 Object *ob = (Object *)obj;
1119 va_start(jargs, methodID);
1120 if((mb = lookupVirtualMethod(ob, (MethodBlock*)methodID)) != NULL)
1121 executeMethodVaList(ob, ob->class, mb, jargs);
1122 va_end(jargs);
1125 void Jam_CallVoidMethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list jargs) {
1126 MethodBlock *mb;
1127 Object *ob = (Object *)obj;
1128 if((mb = lookupVirtualMethod(ob, (MethodBlock*)methodID)) != NULL)
1129 executeMethodVaList(ob, ob->class, mb, jargs);
1132 void Jam_CallVoidMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *jargs) {
1133 MethodBlock *mb;
1134 Object *ob = (Object *)obj;
1135 if((mb = lookupVirtualMethod(ob, (MethodBlock*)methodID)) != NULL)
1136 executeMethodList(ob, ob->class, mb, (u8*)jargs);
1139 void Jam_CallNonvirtualVoidMethod(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...) {
1140 va_list jargs;
1141 va_start(jargs, methodID);
1142 executeMethodVaList((Object*)obj, (Class*)clazz, (MethodBlock*)methodID, jargs);
1143 va_end(jargs);
1146 void Jam_CallNonvirtualVoidMethodV(JNIEnv *env, jobject obj, jclass clazz,
1147 jmethodID methodID, va_list jargs) {
1148 executeMethodVaList((Object*)obj, (Class*)clazz, (MethodBlock*)methodID, jargs);
1151 void Jam_CallNonvirtualVoidMethodA(JNIEnv *env, jobject obj, jclass clazz,
1152 jmethodID methodID, jvalue *jargs) {
1153 executeMethodList((Object*)obj, (Class*)clazz, (MethodBlock*)methodID, (u8*)jargs);
1156 void Jam_CallStaticVoidMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...) {
1157 va_list jargs;
1158 va_start(jargs, methodID);
1159 executeMethodVaList(NULL, (Class*)clazz, (MethodBlock*)methodID, jargs);
1160 va_end(jargs);
1163 void Jam_CallStaticVoidMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list jargs) {
1164 executeMethodVaList(NULL, (Class*)clazz, (MethodBlock*)methodID, jargs);
1167 void Jam_CallStaticVoidMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *jargs) {
1168 executeMethodList(NULL, (Class*)clazz, (MethodBlock*)methodID, (u8*)jargs);
1171 #define NEW_PRIM_ARRAY(type, native_type, array_type) \
1172 native_type##Array Jam_New##type##Array(JNIEnv *env, jsize length) { \
1173 return (native_type##Array) addJNILref(allocTypeArray(array_type, length)); \
1176 #define GET_PRIM_ARRAY_ELEMENTS(type, native_type) \
1177 native_type *Jam_Get##type##ArrayElements(JNIEnv *env, native_type##Array array, \
1178 jboolean *isCopy) { \
1179 if(isCopy != NULL) \
1180 *isCopy = JNI_FALSE; \
1181 addJNIGref((Object*)array); \
1182 return (native_type*)ARRAY_DATA((Object*)array); \
1185 #define RELEASE_PRIM_ARRAY_ELEMENTS(type, native_type) \
1186 void Jam_Release##type##ArrayElements(JNIEnv *env, native_type##Array array, \
1187 native_type *elems, jint mode) { \
1188 delJNIGref((Object*)array); \
1191 #define GET_PRIM_ARRAY_REGION(type, native_type) \
1192 void Jam_Get##type##ArrayRegion(JNIEnv *env, native_type##Array array, jsize start, \
1193 jsize len, native_type *buf) { \
1194 memcpy(buf, (native_type*)ARRAY_DATA((Object*)array) + start, len * sizeof(native_type)); \
1197 #define SET_PRIM_ARRAY_REGION(type, native_type) \
1198 void Jam_Set##type##ArrayRegion(JNIEnv *env, native_type##Array array, jsize start, jsize len, \
1199 native_type *buf) { \
1200 memcpy((native_type*)ARRAY_DATA((Object*)array) + start, buf, len * sizeof(native_type)); \
1203 #define PRIM_ARRAY_OP(type, native_type, array_type) \
1204 NEW_PRIM_ARRAY(type, native_type, array_type); \
1205 GET_PRIM_ARRAY_ELEMENTS(type, native_type); \
1206 RELEASE_PRIM_ARRAY_ELEMENTS(type, native_type); \
1207 GET_PRIM_ARRAY_REGION(type, native_type); \
1208 SET_PRIM_ARRAY_REGION(type, native_type);
1210 PRIM_ARRAY_OP(Boolean, jboolean, T_BOOLEAN);
1211 PRIM_ARRAY_OP(Byte, jbyte, T_BYTE);
1212 PRIM_ARRAY_OP(Char, jchar, T_CHAR);
1213 PRIM_ARRAY_OP(Short, jshort, T_SHORT);
1214 PRIM_ARRAY_OP(Int, jint, T_INT);
1215 PRIM_ARRAY_OP(Long, jlong, T_LONG);
1216 PRIM_ARRAY_OP(Float, jfloat, T_FLOAT);
1217 PRIM_ARRAY_OP(Double, jdouble, T_DOUBLE);
1219 #define METHOD(type, ret_type) \
1220 Jam_Call##type##ret_type##Method, \
1221 Jam_Call##type##ret_type##MethodV, \
1222 Jam_Call##type##ret_type##MethodA
1224 #define METHODS(type) \
1225 METHOD(type, Object), \
1226 METHOD(type, Boolean), \
1227 METHOD(type, Byte), \
1228 METHOD(type, Char), \
1229 METHOD(type, Short), \
1230 METHOD(type, Int), \
1231 METHOD(type, Long), \
1232 METHOD(type, Float), \
1233 METHOD(type, Double), \
1234 METHOD(type, Void)
1236 #define FIELD(direction, type, field_type) \
1237 Jam_##direction##type##field_type##Field
1239 #define FIELDS2(direction, type) \
1240 FIELD(direction, type, Object), \
1241 FIELD(direction, type, Boolean), \
1242 FIELD(direction, type, Byte), \
1243 FIELD(direction, type, Char), \
1244 FIELD(direction, type, Short), \
1245 FIELD(direction, type, Int), \
1246 FIELD(direction, type, Long), \
1247 FIELD(direction, type, Float), \
1248 FIELD(direction, type, Double)
1250 #define FIELDS(type) \
1251 FIELDS2(Get, type), \
1252 FIELDS2(Set, type)
1254 #define ARRAY(op, el_type, type) \
1255 Jam_##op##el_type##Array##type
1257 #define ARRAY_OPS(op, type) \
1258 ARRAY(op, Boolean, type), \
1259 ARRAY(op, Byte, type), \
1260 ARRAY(op, Char, type), \
1261 ARRAY(op, Short, type), \
1262 ARRAY(op, Int, type), \
1263 ARRAY(op, Long, type), \
1264 ARRAY(op, Float, type), \
1265 ARRAY(op, Double, type)
1267 struct _JNINativeInterface Jam_JNINativeInterface = {
1268 NULL,
1269 NULL,
1270 NULL,
1271 NULL,
1272 Jam_GetVersion,
1273 Jam_DefineClass,
1274 Jam_FindClass,
1275 Jam_FromReflectedMethod,
1276 Jam_FromReflectedField,
1277 Jam_ToReflectedMethod,
1278 Jam_GetSuperClass,
1279 Jam_IsAssignableFrom,
1280 Jam_ToReflectedField,
1281 Jam_Throw,
1282 Jam_ThrowNew,
1283 Jam_ExceptionOccurred,
1284 Jam_ExceptionDescribe,
1285 Jam_ExceptionClear,
1286 Jam_FatalError,
1287 Jam_PushLocalFrame,
1288 Jam_PopLocalFrame,
1289 Jam_NewGlobalRef,
1290 Jam_DeleteGlobalRef,
1291 Jam_DeleteLocalRef,
1292 Jam_IsSameObject,
1293 Jam_NewLocalRef,
1294 Jam_EnsureLocalCapacity,
1295 Jam_AllocObject,
1296 Jam_NewObject,
1297 Jam_NewObjectV,
1298 Jam_NewObjectA,
1299 Jam_GetObjectClass,
1300 Jam_IsInstanceOf,
1301 Jam_GetMethodID,
1302 METHODS(/*virtual*/),
1303 METHODS(Nonvirtual),
1304 Jam_GetFieldID,
1305 FIELDS(/*instance*/),
1306 Jam_GetStaticMethodID,
1307 METHODS(Static),
1308 Jam_GetStaticFieldID,
1309 FIELDS(Static),
1310 Jam_NewString,
1311 Jam_GetStringLength,
1312 Jam_GetStringChars,
1313 Jam_ReleaseStringChars,
1314 Jam_NewStringUTF,
1315 Jam_GetStringUTFLength,
1316 Jam_GetStringUTFChars,
1317 Jam_ReleaseStringUTFChars,
1318 Jam_GetArrayLength,
1319 ARRAY(New, Object,),
1320 ARRAY(Get, Object, Element),
1321 ARRAY(Set, Object, Element),
1322 ARRAY_OPS(New,),
1323 ARRAY_OPS(Get, Elements),
1324 ARRAY_OPS(Release, Elements),
1325 ARRAY_OPS(Get, Region),
1326 ARRAY_OPS(Set, Region),
1327 Jam_RegisterNatives,
1328 Jam_UnregisterNatives,
1329 Jam_MonitorEnter,
1330 Jam_MonitorExit,
1331 Jam_GetJavaVM,
1332 Jam_GetStringRegion,
1333 Jam_GetStringUTFRegion,
1334 Jam_GetPrimitiveArrayCritical,
1335 Jam_ReleasePrimitiveArrayCritical,
1336 Jam_GetStringCritical,
1337 Jam_ReleaseStringCritical,
1338 Jam_NewWeakGlobalRef,
1339 Jam_DeleteWeakGlobalRef,
1340 Jam_ExceptionCheck,
1341 Jam_NewDirectByteBuffer,
1342 Jam_GetDirectBufferAddress,
1343 Jam_GetDirectBufferCapacity
1344 };
1346 jint Jam_DestroyJavaVM(JavaVM *vm) {
1347 mainThreadWaitToExitVM();
1348 exitVM(0);
1350 return JNI_OK;
1353 static void *env = &Jam_JNINativeInterface;
1355 static jint attachCurrentThread(void **penv, void *args, int is_daemon) {
1356 if(threadSelf() == NULL) {
1357 char *name = NULL;
1358 Object *group = NULL;
1360 if(args != NULL) {
1361 JavaVMAttachArgs *attach_args = (JavaVMAttachArgs*)args;
1362 if((attach_args->version != JNI_VERSION_1_4) && (attach_args->version != JNI_VERSION_1_2))
1363 return JNI_EVERSION;
1365 name = attach_args->name;
1366 group = attach_args->group;
1369 if(attachJNIThread(name, is_daemon, group) == NULL)
1370 return JNI_ERR;
1372 initJNILrefs();
1375 *penv = &env;
1376 return JNI_OK;
1379 jint Jam_AttachCurrentThread(JavaVM *vm, void **penv, void *args) {
1380 return attachCurrentThread(penv, args, FALSE);
1383 jint Jam_AttachCurrentThreadAsDaemon(JavaVM *vm, void **penv, void *args) {
1384 return attachCurrentThread(penv, args, TRUE);
1387 jint Jam_DetachCurrentThread(JavaVM *vm) {
1388 Thread *thread = threadSelf();
1390 if(thread == NULL)
1391 return JNI_EDETACHED;
1393 detachJNIThread(thread);
1394 return JNI_OK;
1397 jint Jam_GetEnv(JavaVM *vm, void **penv, jint version) {
1398 if((version != JNI_VERSION_1_4) && (version != JNI_VERSION_1_2)
1399 && (version != JNI_VERSION_1_1)) {
1400 *penv = NULL;
1401 return JNI_EVERSION;
1404 if(threadSelf() == NULL) {
1405 *penv = NULL;
1406 return JNI_EDETACHED;
1409 *penv = &env;
1410 return JNI_OK;
1413 struct _JNIInvokeInterface Jam_JNIInvokeInterface = {
1414 NULL,
1415 NULL,
1416 NULL,
1417 Jam_DestroyJavaVM,
1418 Jam_AttachCurrentThread,
1419 Jam_DetachCurrentThread,
1420 Jam_GetEnv,
1421 Jam_AttachCurrentThreadAsDaemon,
1422 };
1424 jint JNI_GetDefaultJavaVMInitArgs(void *args) {
1425 JavaVMInitArgs *vm_args = (JavaVMInitArgs*) args;
1427 if((vm_args->version != JNI_VERSION_1_4) && (vm_args->version != JNI_VERSION_1_2))
1428 return JNI_EVERSION;
1430 return JNI_OK;
1433 jint parseInitOptions(JavaVMInitArgs *vm_args, InitArgs *args) {
1434 Property props[vm_args->nOptions];
1435 int props_count = 0;
1436 int i;
1438 for(i = 0; i < vm_args->nOptions; i++) {
1439 char *string = vm_args->options[i].optionString;
1441 if(strcmp(string, "vfprintf") == 0)
1442 args->vfprintf = vm_args->options[i].extraInfo;
1444 else if(strcmp(string, "exit") == 0)
1445 args->exit = vm_args->options[i].extraInfo;
1447 else if(strcmp(string, "abort") == 0)
1448 args->abort = vm_args->options[i].extraInfo;
1450 else if(strncmp(string, "-verbose:", 9) == 0) {
1451 char *type = &string[8];
1453 do {
1454 type++;
1456 if(strncmp(type, "class", 5) == 0) {
1457 args->verboseclass = TRUE;
1458 type += 5;
1460 else if(strncmp(type, "gc", 2) == 0) {
1461 args->verbosegc = TRUE;
1462 type += 2;
1464 else if(strncmp(type, "jni", 3) == 0) {
1465 args->verbosedll = TRUE;
1466 type += 3;
1468 } while(*type == ',');
1470 } else if(strcmp(string, "-Xnoasyncgc") == 0)
1471 args->noasyncgc = TRUE;
1473 else if(strncmp(string, "-Xms", 4) == 0) {
1474 args->min_heap = parseMemValue(string + 4);
1475 if(args->min_heap < MIN_HEAP)
1476 goto error;
1478 } else if(strncmp(string, "-Xmx", 4) == 0) {
1479 args->max_heap = parseMemValue(string + 4);
1480 if(args->max_heap < MIN_HEAP)
1481 goto error;
1483 } else if(strncmp(string, "-Xss", 4) == 0) {
1484 args->java_stack = parseMemValue(string + 4);
1485 if(args->java_stack < MIN_STACK)
1486 goto error;
1488 } else if(strncmp(string, "-D", 2) == 0) {
1489 char *pntr, *key = strcpy(sysMalloc(strlen(string+2) + 1), string+2);
1490 for(pntr = key; *pntr && (*pntr != '='); pntr++);
1491 if(pntr == key)
1492 goto error;
1494 *pntr++ = '\0';
1495 props[props_count].key = key;
1496 props[props_count++].value = pntr;
1498 } else if(strncmp(string, "-Xbootclasspath:", 16) == 0) {
1500 args->bootpathopt = '\0';
1501 args->bootpath = string + 16;
1503 } else if(strncmp(string, "-Xbootclasspath/a:", 18) == 0 ||
1504 strncmp(string, "-Xbootclasspath/p:", 18) == 0 ||
1505 strncmp(string, "-Xbootclasspath/c:", 18) == 0 ||
1506 strncmp(string, "-Xbootclasspath/v:", 18) == 0) {
1508 args->bootpathopt = string[16];
1509 args->bootpath = string + 18;
1511 } else if(strcmp(string, "-Xnocompact") == 0) {
1512 args->compact_specified = TRUE;
1513 args->do_compact = FALSE;
1515 } else if(strcmp(string, "-Xcompactalways") == 0) {
1516 args->compact_specified = args->do_compact = TRUE;
1517 #ifdef INLINING
1518 } else if(strcmp(string, "-Xnoinlining") == 0) {
1519 /* Turning inlining off is equivalent to setting
1520 code memory to zero */
1521 args->codemem = 0;
1523 } else if(strncmp(string, "-Xreplication:", 14) == 0) {
1524 char *pntr = string + 14;
1526 if(strcmp(pntr, "none") == 0)
1527 args->replication = INT_MAX;
1528 else
1529 if(strcmp(pntr, "always") == 0)
1530 args->replication = 0;
1531 else
1532 args->replication = strtol(pntr, NULL, 0);
1534 } else if(strncmp(string, "-Xcodemem:", 10) == 0) {
1535 char *pntr = string + 10;
1537 args->codemem = strncmp(pntr, "unlimited", 10) == 0 ?
1538 INT_MAX : parseMemValue(pntr);
1539 #endif
1540 } else if(!vm_args->ignoreUnrecognized)
1541 goto error;
1544 if(args->min_heap > args->max_heap)
1545 goto error;
1547 if((args->props_count = props_count)) {
1548 args->commandline_props = (Property*)sysMalloc(props_count * sizeof(Property));
1549 memcpy(args->commandline_props, &props[0], props_count * sizeof(Property));
1552 return JNI_OK;
1554 error:
1555 return JNI_ERR;
1558 jint JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args) {
1559 JavaVMInitArgs *vm_args = (JavaVMInitArgs*) args;
1560 InitArgs init_args;
1562 if((vm_args->version != JNI_VERSION_1_4) && (vm_args->version != JNI_VERSION_1_2))
1563 return JNI_EVERSION;
1565 setDefaultInitArgs(&init_args);
1567 if(parseInitOptions(vm_args, &init_args) == JNI_ERR)
1568 return JNI_ERR;
1570 init_args.main_stack_base = nativeStackBase();
1571 initVM(&init_args);
1572 initJNILrefs();
1574 *penv = &env;
1575 *pvm = &invokeIntf;
1577 return JNI_OK;
1580 jint JNI_GetCreatedJavaVMs(JavaVM **buff, jsize buff_len, jsize *num) {
1581 if(buff_len > 0) {
1582 *buff = &invokeIntf;
1583 *num = 1;
1584 return JNI_OK;
1586 return JNI_ERR;
1589 void *getJNIInterface() {
1590 return &Jam_JNINativeInterface;
1592 #endif