842840bdcc4122375a74fb77e2def6126a52b490
[cacao.git] / src / native / jni.cpp
1 /* src/native/jni.cpp - implementation of the Java Native Interface functions
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <assert.h>
29 #include <stdint.h>
30 #include <string.h>
31
32 #include "vm/types.h"
33
34 #include "mm/gc.hpp"
35 #include "mm/memory.h"
36
37 #include "native/jni.h"
38 #include "native/llni.h"
39 #include "native/localref.h"
40 #include "native/native.h"
41
42 #if defined(ENABLE_JVMTI)
43 # include "native/jvmti/cacaodbg.h"
44 #endif
45
46 #include "threads/lock-common.h"
47 #include "threads/thread.hpp"
48
49 #include "toolbox/logging.h"
50
51 #include "vm/array.h"
52 #include "vm/builtin.h"
53 #include "vm/exceptions.hpp"
54 #include "vm/global.h"
55 #include "vm/globals.hpp"
56 #include "vm/initialize.h"
57 #include "vm/javaobjects.hpp"
58 #include "vm/loader.h"
59 #include "vm/options.h"
60 #include "vm/primitive.hpp"
61 #include "vm/resolve.h"
62 #include "vm/statistics.h"
63 #include "vm/string.hpp"
64 #include "vm/vm.hpp"
65
66 #include "vm/jit/argument.h"
67 #include "vm/jit/asmpart.h"
68 #include "vm/jit/jit.h"
69 #include "vm/jit/stacktrace.hpp"
70
71
72 /* debug **********************************************************************/
73
74 #if !defined(NDEBUG)
75
76 # define TRACEJNICALLS(x)                                               \
77     do {                                                                                \
78         if (opt_TraceJNICalls) {                                \
79             log_println x;                                              \
80         }                                                                               \
81     } while (0)
82
83 # define TRACEJNICALLSENTER(x)                                                                  \
84     do {                                                                                                                \
85         if (opt_TraceJNICalls) {                                                                \
86                         log_start();                                                                            \
87             log_print x;                                                                                \
88         }                                                                                                               \
89     } while (0)
90
91 # define TRACEJNICALLSEXIT(x)                                                                   \
92     do {                                                                                                                \
93         if (opt_TraceJNICalls) {                                                                \
94                         log_print x;                                                                            \
95                         log_finish();                                                                           \
96         }                                                                                                               \
97     } while (0)
98
99 #else
100
101 # define TRACEJNICALLS(x)
102 # define TRACEJNICALLSENTER(x)
103 # define TRACEJNICALLSEXIT(x)
104
105 #endif
106
107
108 /* global variables ***********************************************************/
109
110 /* global reference table *****************************************************/
111
112 /* hashsize must be power of 2 */
113
114 #define HASHTABLE_GLOBAL_REF_SIZE    64 /* initial size of globalref-hash     */
115
116 static hashtable *hashtable_global_ref; /* hashtable for globalrefs           */
117
118
119 /* direct buffer stuff ********************************************************/
120
121 #if defined(ENABLE_JAVASE)
122 static classinfo *class_java_nio_Buffer;
123
124 # if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
125
126 static classinfo *class_java_nio_DirectByteBufferImpl;
127 static classinfo *class_java_nio_DirectByteBufferImpl_ReadWrite;
128
129 #  if SIZEOF_VOID_P == 8
130 static classinfo *class_gnu_classpath_Pointer64;
131 #  else
132 static classinfo *class_gnu_classpath_Pointer32;
133 #  endif
134
135 static methodinfo *dbbirw_init;
136
137 # elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
138
139 static classinfo *class_sun_nio_ch_DirectBuffer;
140 static classinfo *class_java_nio_DirectByteBuffer;
141
142 static methodinfo *dbb_init;
143
144 # endif
145 #endif
146
147
148 /* some forward declarations **************************************************/
149
150 extern "C" {
151 jobject jni_NewLocalRef(JNIEnv *env, jobject ref);
152 }
153
154
155 /* jni_init ********************************************************************
156
157    Initialize the JNI subsystem.
158
159 *******************************************************************************/
160
161 bool jni_init(void)
162 {
163         TRACESUBSYSTEMINITIALIZATION("jni_init");
164
165         /* create global ref hashtable */
166
167         hashtable_global_ref = NEW(hashtable);
168
169         hashtable_create(hashtable_global_ref, HASHTABLE_GLOBAL_REF_SIZE);
170
171
172 #if defined(ENABLE_JAVASE)
173         /* Direct buffer stuff. */
174
175         if (!(class_java_nio_Buffer =
176                   load_class_bootstrap(utf_new_char("java/nio/Buffer"))) ||
177                 !link_class(class_java_nio_Buffer))
178                 return false;
179
180 # if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
181
182         if (!(class_java_nio_DirectByteBufferImpl =
183                   load_class_bootstrap(utf_new_char("java/nio/DirectByteBufferImpl"))) ||
184                 !link_class(class_java_nio_DirectByteBufferImpl))
185                 return false;
186
187         if (!(class_java_nio_DirectByteBufferImpl_ReadWrite =
188                   load_class_bootstrap(utf_new_char("java/nio/DirectByteBufferImpl$ReadWrite"))) ||
189                 !link_class(class_java_nio_DirectByteBufferImpl_ReadWrite))
190                 return false;
191
192         if (!(dbbirw_init =
193                 class_resolvemethod(class_java_nio_DirectByteBufferImpl_ReadWrite,
194                                                         utf_init,
195                                                         utf_new_char("(Ljava/lang/Object;Lgnu/classpath/Pointer;III)V"))))
196                 return false;
197
198 #  if SIZEOF_VOID_P == 8
199         if (!(class_gnu_classpath_Pointer64 =
200                   load_class_bootstrap(utf_new_char("gnu/classpath/Pointer64"))) ||
201                 !link_class(class_gnu_classpath_Pointer64))
202                 return false;
203 #  else
204         if (!(class_gnu_classpath_Pointer32 =
205                   load_class_bootstrap(utf_new_char("gnu/classpath/Pointer32"))) ||
206                 !link_class(class_gnu_classpath_Pointer32))
207                 return false;
208 #  endif
209
210 # elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
211
212         if (!(class_sun_nio_ch_DirectBuffer =
213                   load_class_bootstrap(utf_new_char("sun/nio/ch/DirectBuffer"))))
214                 vm_abort("jni_init: loading sun/nio/ch/DirectBuffer failed");
215
216         if (!link_class(class_sun_nio_ch_DirectBuffer))
217                 vm_abort("jni_init: linking sun/nio/ch/DirectBuffer failed");
218
219         if (!(class_java_nio_DirectByteBuffer =
220                   load_class_bootstrap(utf_new_char("java/nio/DirectByteBuffer"))))
221                 vm_abort("jni_init: loading java/nio/DirectByteBuffer failed");
222
223         if (!link_class(class_java_nio_DirectByteBuffer))
224                 vm_abort("jni_init: linking java/nio/DirectByteBuffer failed");
225
226         if (!(dbb_init =
227                   class_resolvemethod(class_java_nio_DirectByteBuffer,
228                                                           utf_init,
229                                                           utf_new_char("(JI)V"))))
230                 vm_abort("jni_init: resolving java/nio/DirectByteBuffer.init(JI)V failed");
231
232 # endif
233
234 #endif /* defined(ENABLE_JAVASE) */
235
236         return true;
237 }
238
239
240 /* jni_version_check ***********************************************************
241
242    Check if the given JNI version is supported.
243
244    IN:
245        version....JNI version to check
246
247    RETURN VALUE:
248        true.......supported
249        false......not supported
250
251 *******************************************************************************/
252
253 bool jni_version_check(int version)
254 {
255         switch (version) {
256         case JNI_VERSION_1_1:
257         case JNI_VERSION_1_2:
258         case JNI_VERSION_1_4:
259         case JNI_VERSION_1_6:
260                 return true;
261         default:
262                 return false;
263         }
264 }
265
266
267 /* _Jv_jni_CallObjectMethod ****************************************************
268
269    Internal function to call Java Object methods.
270
271 *******************************************************************************/
272
273 static java_handle_t *_Jv_jni_CallObjectMethod(java_handle_t *o,
274                                                                                            vftbl_t *vftbl,
275                                                                                            methodinfo *m, va_list ap)
276 {
277         methodinfo    *resm;
278         java_handle_t *ro;
279
280         STATISTICS(jniinvokation());
281
282         if (m == NULL) {
283                 exceptions_throw_nullpointerexception();
284                 return NULL;
285         }
286
287         /* Class initialization is done by the JIT compiler.  This is ok
288            since a static method always belongs to the declaring class. */
289
290         if (m->flags & ACC_STATIC) {
291                 /* For static methods we reset the object. */
292
293                 if (o != NULL)
294                         o = NULL;
295
296                 /* for convenience */
297
298                 resm = m;
299
300         } else {
301                 /* For instance methods we make a virtual function table lookup. */
302
303                 resm = method_vftbl_lookup(vftbl, m);
304         }
305
306         STATISTICS(jnicallXmethodnvokation());
307
308         ro = vm_call_method_valist(resm, o, ap);
309
310         return ro;
311 }
312
313
314 /* _Jv_jni_CallObjectMethodA ***************************************************
315
316    Internal function to call Java Object methods.
317
318 *******************************************************************************/
319
320 static java_handle_t *_Jv_jni_CallObjectMethodA(java_handle_t *o,
321                                                                                                 vftbl_t *vftbl,
322                                                                                                 methodinfo *m,
323                                                                                                 const jvalue *args)
324 {
325         methodinfo    *resm;
326         java_handle_t *ro;
327
328         STATISTICS(jniinvokation());
329
330         if (m == NULL) {
331                 exceptions_throw_nullpointerexception();
332                 return NULL;
333         }
334
335         /* Class initialization is done by the JIT compiler.  This is ok
336            since a static method always belongs to the declaring class. */
337
338         if (m->flags & ACC_STATIC) {
339                 /* For static methods we reset the object. */
340
341                 if (o != NULL)
342                         o = NULL;
343
344                 /* for convenience */
345
346                 resm = m;
347
348         } else {
349                 /* For instance methods we make a virtual function table lookup. */
350
351                 resm = method_vftbl_lookup(vftbl, m);
352         }
353
354         STATISTICS(jnicallXmethodnvokation());
355
356         ro = vm_call_method_jvalue(resm, o, args);
357
358         return ro;
359 }
360
361
362 /* _Jv_jni_CallIntMethod *******************************************************
363
364    Internal function to call Java integer class methods (boolean,
365    byte, char, short, int).
366
367 *******************************************************************************/
368
369 static jint _Jv_jni_CallIntMethod(java_handle_t *o, vftbl_t *vftbl,
370                                                                   methodinfo *m, va_list ap)
371 {
372         methodinfo *resm;
373         jint        i;
374
375         STATISTICS(jniinvokation());
376
377         if (m == NULL) {
378                 exceptions_throw_nullpointerexception();
379                 return 0;
380         }
381         
382         /* Class initialization is done by the JIT compiler.  This is ok
383            since a static method always belongs to the declaring class. */
384
385         if (m->flags & ACC_STATIC) {
386                 /* For static methods we reset the object. */
387
388                 if (o != NULL)
389                         o = NULL;
390
391                 /* for convenience */
392
393                 resm = m;
394
395         } else {
396                 /* For instance methods we make a virtual function table lookup. */
397
398                 resm = method_vftbl_lookup(vftbl, m);
399         }
400
401         STATISTICS(jnicallXmethodnvokation());
402
403         i = vm_call_method_int_valist(resm, o, ap);
404
405         return i;
406 }
407
408
409 /* _Jv_jni_CallIntMethodA ******************************************************
410
411    Internal function to call Java integer class methods (boolean,
412    byte, char, short, int).
413
414 *******************************************************************************/
415
416 static jint _Jv_jni_CallIntMethodA(java_handle_t *o, vftbl_t *vftbl,
417                                                                    methodinfo *m, const jvalue *args)
418 {
419         methodinfo *resm;
420         jint        i;
421
422         STATISTICS(jniinvokation());
423
424         if (m == NULL) {
425                 exceptions_throw_nullpointerexception();
426                 return 0;
427         }
428         
429         /* Class initialization is done by the JIT compiler.  This is ok
430            since a static method always belongs to the declaring class. */
431
432         if (m->flags & ACC_STATIC) {
433                 /* For static methods we reset the object. */
434
435                 if (o != NULL)
436                         o = NULL;
437
438                 /* for convenience */
439
440                 resm = m;
441
442         } else {
443                 /* For instance methods we make a virtual function table lookup. */
444
445                 resm = method_vftbl_lookup(vftbl, m);
446         }
447
448         STATISTICS(jnicallXmethodnvokation());
449
450         i = vm_call_method_int_jvalue(resm, o, args);
451
452         return i;
453 }
454
455
456 /* _Jv_jni_CallLongMethod ******************************************************
457
458    Internal function to call Java long methods.
459
460 *******************************************************************************/
461
462 static jlong _Jv_jni_CallLongMethod(java_handle_t *o, vftbl_t *vftbl,
463                                                                         methodinfo *m, va_list ap)
464 {
465         methodinfo *resm;
466         jlong       l;
467
468         STATISTICS(jniinvokation());
469
470         if (m == NULL) {
471                 exceptions_throw_nullpointerexception();
472                 return 0;
473         }
474
475         /* Class initialization is done by the JIT compiler.  This is ok
476            since a static method always belongs to the declaring class. */
477
478         if (m->flags & ACC_STATIC) {
479                 /* For static methods we reset the object. */
480
481                 if (o != NULL)
482                         o = NULL;
483
484                 /* for convenience */
485
486                 resm = m;
487
488         } else {
489                 /* For instance methods we make a virtual function table lookup. */
490
491                 resm = method_vftbl_lookup(vftbl, m);
492         }
493
494         STATISTICS(jnicallXmethodnvokation());
495
496         l = vm_call_method_long_valist(resm, o, ap);
497
498         return l;
499 }
500
501
502 /* _Jv_jni_CallLongMethodA *****************************************************
503
504    Internal function to call Java long methods.
505
506 *******************************************************************************/
507
508 static jlong _Jv_jni_CallLongMethodA(java_handle_t *o, vftbl_t *vftbl,
509                                                                          methodinfo *m, const jvalue *args)
510 {
511         methodinfo *resm;
512         jlong       l;
513
514         STATISTICS(jniinvokation());
515
516         if (m == NULL) {
517                 exceptions_throw_nullpointerexception();
518                 return 0;
519         }
520
521         /* Class initialization is done by the JIT compiler.  This is ok
522            since a static method always belongs to the declaring class. */
523
524         if (m->flags & ACC_STATIC) {
525                 /* For static methods we reset the object. */
526
527                 if (o != NULL)
528                         o = NULL;
529
530                 /* for convenience */
531
532                 resm = m;
533         }
534         else {
535                 /* For instance methods we make a virtual function table lookup. */
536
537                 resm = method_vftbl_lookup(vftbl, m);
538         }
539
540         STATISTICS(jnicallXmethodnvokation());
541
542         l = vm_call_method_long_jvalue(resm, o, args);
543
544         return l;
545 }
546
547
548 /* _Jv_jni_CallFloatMethod *****************************************************
549
550    Internal function to call Java float methods.
551
552 *******************************************************************************/
553
554 static jfloat _Jv_jni_CallFloatMethod(java_handle_t *o, vftbl_t *vftbl,
555                                                                           methodinfo *m, va_list ap)
556 {
557         methodinfo *resm;
558         jfloat      f;
559
560         /* Class initialization is done by the JIT compiler.  This is ok
561            since a static method always belongs to the declaring class. */
562
563         if (m->flags & ACC_STATIC) {
564                 /* For static methods we reset the object. */
565
566                 if (o != NULL)
567                         o = NULL;
568
569                 /* for convenience */
570
571                 resm = m;
572
573         } else {
574                 /* For instance methods we make a virtual function table lookup. */
575
576                 resm = method_vftbl_lookup(vftbl, m);
577         }
578
579         STATISTICS(jnicallXmethodnvokation());
580
581         f = vm_call_method_float_valist(resm, o, ap);
582
583         return f;
584 }
585
586
587 /* _Jv_jni_CallFloatMethodA ****************************************************
588
589    Internal function to call Java float methods.
590
591 *******************************************************************************/
592
593 static jfloat _Jv_jni_CallFloatMethodA(java_handle_t *o, vftbl_t *vftbl,
594                                                                            methodinfo *m, const jvalue *args)
595 {
596         methodinfo *resm;
597         jfloat      f;
598
599         /* Class initialization is done by the JIT compiler.  This is ok
600            since a static method always belongs to the declaring class. */
601
602         if (m->flags & ACC_STATIC) {
603                 /* For static methods we reset the object. */
604
605                 if (o != NULL)
606                         o = NULL;
607
608                 /* for convenience */
609
610                 resm = m;
611         }
612         else {
613                 /* For instance methods we make a virtual function table lookup. */
614
615                 resm = method_vftbl_lookup(vftbl, m);
616         }
617
618         STATISTICS(jnicallXmethodnvokation());
619
620         f = vm_call_method_float_jvalue(resm, o, args);
621
622         return f;
623 }
624
625
626 /* _Jv_jni_CallDoubleMethod ****************************************************
627
628    Internal function to call Java double methods.
629
630 *******************************************************************************/
631
632 static jdouble _Jv_jni_CallDoubleMethod(java_handle_t *o, vftbl_t *vftbl,
633                                                                                 methodinfo *m, va_list ap)
634 {
635         methodinfo *resm;
636         jdouble     d;
637
638         /* Class initialization is done by the JIT compiler.  This is ok
639            since a static method always belongs to the declaring class. */
640
641         if (m->flags & ACC_STATIC) {
642                 /* For static methods we reset the object. */
643
644                 if (o != NULL)
645                         o = NULL;
646
647                 /* for convenience */
648
649                 resm = m;
650
651         } else {
652                 /* For instance methods we make a virtual function table lookup. */
653
654                 resm = method_vftbl_lookup(vftbl, m);
655         }
656
657         d = vm_call_method_double_valist(resm, o, ap);
658
659         return d;
660 }
661
662
663 /* _Jv_jni_CallDoubleMethodA ***************************************************
664
665    Internal function to call Java double methods.
666
667 *******************************************************************************/
668
669 static jdouble _Jv_jni_CallDoubleMethodA(java_handle_t *o, vftbl_t *vftbl,
670                                                                                  methodinfo *m, const jvalue *args)
671 {
672         methodinfo *resm;
673         jdouble     d;
674
675         /* Class initialization is done by the JIT compiler.  This is ok
676            since a static method always belongs to the declaring class. */
677
678         if (m->flags & ACC_STATIC) {
679                 /* For static methods we reset the object. */
680
681                 if (o != NULL)
682                         o = NULL;
683
684                 /* for convenience */
685
686                 resm = m;
687         }
688         else {
689                 /* For instance methods we make a virtual function table lookup. */
690
691                 resm = method_vftbl_lookup(vftbl, m);
692         }
693
694         d = vm_call_method_double_jvalue(resm, o, args);
695
696         return d;
697 }
698
699
700 /* _Jv_jni_CallVoidMethod ******************************************************
701
702    Internal function to call Java void methods.
703
704 *******************************************************************************/
705
706 static void _Jv_jni_CallVoidMethod(java_handle_t *o, vftbl_t *vftbl,
707                                                                    methodinfo *m, va_list ap)
708 {       
709         methodinfo *resm;
710
711         if (m == NULL) {
712                 exceptions_throw_nullpointerexception();
713                 return;
714         }
715
716         /* Class initialization is done by the JIT compiler.  This is ok
717            since a static method always belongs to the declaring class. */
718
719         if (m->flags & ACC_STATIC) {
720                 /* For static methods we reset the object. */
721
722                 if (o != NULL)
723                         o = NULL;
724
725                 /* for convenience */
726
727                 resm = m;
728
729         } else {
730                 /* For instance methods we make a virtual function table lookup. */
731
732                 resm = method_vftbl_lookup(vftbl, m);
733         }
734
735         STATISTICS(jnicallXmethodnvokation());
736
737         (void) vm_call_method_valist(resm, o, ap);
738 }
739
740
741 /* _Jv_jni_CallVoidMethodA *****************************************************
742
743    Internal function to call Java void methods.
744
745 *******************************************************************************/
746
747 static void _Jv_jni_CallVoidMethodA(java_handle_t *o, vftbl_t *vftbl,
748                                                                         methodinfo *m, const jvalue *args)
749 {       
750         methodinfo *resm;
751
752         if (m == NULL) {
753                 exceptions_throw_nullpointerexception();
754                 return;
755         }
756
757         /* Class initialization is done by the JIT compiler.  This is ok
758            since a static method always belongs to the declaring class. */
759
760         if (m->flags & ACC_STATIC) {
761                 /* For static methods we reset the object. */
762
763                 if (o != NULL)
764                         o = NULL;
765
766                 /* for convenience */
767
768                 resm = m;
769
770         } else {
771                 /* For instance methods we make a virtual function table lookup. */
772
773                 resm = method_vftbl_lookup(vftbl, m);
774         }
775
776         STATISTICS(jnicallXmethodnvokation());
777
778         (void) vm_call_method_jvalue(resm, o, args);
779 }
780
781
782 // JNI functions are exported as C functions.
783 extern "C" {
784
785 /* GetVersion ******************************************************************
786
787    Returns the major version number in the higher 16 bits and the
788    minor version number in the lower 16 bits.
789
790 *******************************************************************************/
791
792 jint _Jv_JNI_GetVersion(JNIEnv *env)
793 {
794         TRACEJNICALLS(("_Jv_JNI_GetVersion(env=%p)", env));
795
796         /* We support JNI 1.6. */
797
798         return JNI_VERSION_1_6;
799 }
800
801
802 /* Class Operations ***********************************************************/
803
804 /* DefineClass *****************************************************************
805
806    Loads a class from a buffer of raw class data. The buffer
807    containing the raw class data is not referenced by the VM after the
808    DefineClass call returns, and it may be discarded if desired.
809
810 *******************************************************************************/
811
812 jclass jni_DefineClass(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize bufLen)
813 {
814 #if defined(ENABLE_JAVASE)
815         utf           *u;
816         classloader_t *cl;
817         classinfo     *c;
818         java_handle_t* h;
819
820         TRACEJNICALLS(("jni_DefineClass(env=%p, name=%s, loader=%p, buf=%p, bufLen=%d)", env, name, loader, buf, bufLen));
821
822         u  = utf_new_char(name);
823         cl = loader_hashtable_classloader_add((java_handle_t *) loader);
824
825         c = class_define(u, cl, bufLen, (uint8_t *) buf, NULL);
826
827         h = LLNI_classinfo_wrap(c);
828
829         return (jclass) jni_NewLocalRef(env, (jobject) h);
830 #else
831         vm_abort("jni_DefineClass: Not implemented in this configuration");
832
833         // Keep compiler happy.
834
835         return 0;
836 #endif
837 }
838
839
840 /* FindClass *******************************************************************
841
842    This function loads a locally-defined class. It searches the
843    directories and zip files specified by the CLASSPATH environment
844    variable for the class with the specified name.
845
846 *******************************************************************************/
847
848 jclass jni_FindClass(JNIEnv *env, const char *name)
849 {
850 #if defined(ENABLE_JAVASE)
851
852         utf*       u;    
853         classinfo* cc;
854         classinfo* c;
855         java_handle_t* h;
856
857         TRACEJNICALLS(("jni_FindClass(env=%p, name=%s)", env, name));
858
859         /* FIXME If name is NULL we have a problem here. */
860
861         u = utf_new_char_classname((char *) name);
862
863         if ((u == NULL) /*|| (int)strlen(name) > symbolOopDesc::max_length() */) {
864                 exceptions_throw_noclassdeffounderror(u);
865                 return NULL;
866         }
867
868         /* Check stacktrace for classloader, if one found use it,
869            otherwise use the system classloader. */
870
871         /* Quote from the JNI documentation:
872          
873            In the Java 2 Platform, FindClass locates the class loader
874            associated with the current native method.  If the native code
875            belongs to a system class, no class loader will be
876            involved. Otherwise, the proper class loader will be invoked to
877            load and link the named class. When FindClass is called through
878            the Invocation Interface, there is no current native method or
879            its associated class loader. In that case, the result of
880            ClassLoader.getBaseClassLoader is used." */
881
882         cc = stacktrace_get_current_class();
883
884         if (cc == NULL)
885                 c = load_class_from_sysloader(u);
886         else
887                 c = load_class_from_classloader(u, cc->classloader);
888
889         if (c == NULL) {
890                 resolve_handle_pending_exception(true);
891                 return NULL;
892         }
893
894         if (!link_class(c))
895                 return NULL;
896
897         h = LLNI_classinfo_wrap(c);
898
899         return (jclass) jni_NewLocalRef(env, (jobject) h);
900
901 #elif defined(ENABLE_JAVAME_CLDC1_1)
902
903         utf       *u;
904         classinfo *c;
905
906         TRACEJNICALLS(("jni_FindClass(env=%p, name=%s)", env, name));
907
908         u = utf_new_char_classname((char *) name);
909         c = load_class_bootstrap(u);
910
911         if (c == NULL) {
912                 resolve_handle_pending_exception(true);
913                 return NULL;
914         }
915
916         if (!link_class(c))
917                 return NULL;
918
919         return (jclass) jni_NewLocalRef(env, (jobject) c);
920         
921 #else
922         vm_abort("jni_FindClass: not implemented in this configuration");
923
924         /* keep compiler happy */
925
926         return NULL;
927 #endif
928 }
929   
930
931 /* GetSuperclass ***************************************************************
932
933    If clazz represents any class other than the class Object, then
934    this function returns the object that represents the superclass of
935    the class specified by clazz.
936
937 *******************************************************************************/
938  
939 jclass jni_GetSuperclass(JNIEnv *env, jclass sub)
940 {
941         classinfo* c;
942         classinfo* super;
943
944         TRACEJNICALLS(("jni_GetSuperclass(env=%p, sub=%p)", env, sub));
945
946         c = LLNI_classinfo_unwrap(sub);
947
948         if (c == NULL)
949                 return NULL;
950
951         super = class_get_superclass(c);
952
953         java_handle_t* h = LLNI_classinfo_wrap(super);
954
955         return (jclass) jni_NewLocalRef(env, (jobject) h);
956 }
957   
958  
959 /* IsAssignableFrom ************************************************************
960
961    Determines whether an object of sub can be safely cast to sup.
962
963 *******************************************************************************/
964
965 jboolean _Jv_JNI_IsAssignableFrom(JNIEnv *env, jclass sub, jclass sup)
966 {
967         classinfo *to;
968         classinfo *from;
969
970         TRACEJNICALLS(("_Jv_JNI_IsAssignableFrom(env=%p, sub=%p, sup=%p)", env, sub, sup));
971
972         to   = (classinfo *) sup;
973         from = (classinfo *) sub;
974
975         return class_is_assignable_from(to, from);
976 }
977
978
979 /* Throw ***********************************************************************
980
981    Causes a java.lang.Throwable object to be thrown.
982
983 *******************************************************************************/
984
985 jint _Jv_JNI_Throw(JNIEnv *env, jthrowable obj)
986 {
987         java_handle_t *o;
988
989         STATISTICS(jniinvokation());
990
991         o = (java_handle_t *) obj;
992
993         exceptions_set_exception(o);
994
995         return JNI_OK;
996 }
997
998
999 /* ThrowNew ********************************************************************
1000
1001    Constructs an exception object from the specified class with the
1002    message specified by message and causes that exception to be
1003    thrown.
1004
1005 *******************************************************************************/
1006
1007 jint _Jv_JNI_ThrowNew(JNIEnv* env, jclass clazz, const char *msg) 
1008 {
1009         classinfo     *c;
1010         java_handle_t *o;
1011         java_handle_t *s;
1012
1013         STATISTICS(jniinvokation());
1014
1015         c = LLNI_classinfo_unwrap(clazz);
1016         if (msg == NULL)
1017                 msg = "";
1018         s = javastring_new_from_utf_string(msg);
1019
1020         /* instantiate exception object */
1021
1022         o = native_new_and_init_string(c, s);
1023
1024         if (o == NULL)
1025                 return -1;
1026
1027         exceptions_set_exception(o);
1028
1029         return 0;
1030 }
1031
1032
1033 /* ExceptionOccurred ***********************************************************
1034
1035    Determines if an exception is being thrown. The exception stays
1036    being thrown until either the native code calls ExceptionClear(),
1037    or the Java code handles the exception.
1038
1039 *******************************************************************************/
1040
1041 jthrowable _Jv_JNI_ExceptionOccurred(JNIEnv *env)
1042 {
1043         java_handle_t *o;
1044
1045         TRACEJNICALLS(("_Jv_JNI_ExceptionOccurred(env=%p)", env));
1046
1047         o = exceptions_get_exception();
1048
1049         return (jthrowable) jni_NewLocalRef(env, (jthrowable) o);
1050 }
1051
1052
1053 /* ExceptionDescribe ***********************************************************
1054
1055    Prints an exception and a backtrace of the stack to a system
1056    error-reporting channel, such as stderr. This is a convenience
1057    routine provided for debugging.
1058
1059 *******************************************************************************/
1060
1061 void jni_ExceptionDescribe(JNIEnv *env)
1062 {
1063         TRACEJNICALLS(("jni_ExceptionDescribe(env=%p)", env));
1064
1065         exceptions_print_stacktrace();
1066 }
1067
1068
1069 /* ExceptionClear **************************************************************
1070
1071    Clears any exception that is currently being thrown. If no
1072    exception is currently being thrown, this routine has no effect.
1073
1074 *******************************************************************************/
1075
1076 void jni_ExceptionClear(JNIEnv *env)
1077 {
1078         TRACEJNICALLS(("jni_ExceptionClear(env=%p)", env));
1079
1080         exceptions_clear_exception();
1081 }
1082
1083
1084 /* FatalError ******************************************************************
1085
1086    Raises a fatal error and does not expect the VM to recover. This
1087    function does not return.
1088
1089 *******************************************************************************/
1090
1091 void _Jv_JNI_FatalError(JNIEnv *env, const char *msg)
1092 {
1093         STATISTICS(jniinvokation());
1094
1095         /* this seems to be the best way */
1096
1097         vm_abort("JNI Fatal error: %s", msg);
1098 }
1099
1100
1101 /* PushLocalFrame **************************************************************
1102
1103    Creates a new local reference frame, in which at least a given
1104    number of local references can be created.
1105
1106 *******************************************************************************/
1107
1108 jint jni_PushLocalFrame(JNIEnv* env, jint capacity)
1109 {
1110         TRACEJNICALLS(("jni_PushLocalFrame(env=%p, capacity=%d)", env, capacity));
1111
1112         if (capacity <= 0)
1113                 return -1;
1114
1115         /* add new local reference frame to current table */
1116
1117         if (!localref_frame_push(capacity))
1118                 return -1;
1119
1120         return 0;
1121 }
1122
1123
1124 /* PopLocalFrame ***************************************************************
1125
1126    Pops off the current local reference frame, frees all the local
1127    references, and returns a local reference in the previous local
1128    reference frame for the given result object.
1129
1130 *******************************************************************************/
1131
1132 jobject jni_PopLocalFrame(JNIEnv* env, jobject result)
1133 {
1134         TRACEJNICALLS(("jni_PopLocalFrame(env=%p, result=%p)", env, result));
1135
1136         /* release all current local frames */
1137
1138         localref_frame_pop_all();
1139
1140         /* add local reference and return the value */
1141
1142         return jni_NewLocalRef(env, result);
1143 }
1144
1145
1146 /* DeleteLocalRef **************************************************************
1147
1148    Deletes the local reference pointed to by localRef.
1149
1150 *******************************************************************************/
1151
1152 void jni_DeleteLocalRef(JNIEnv *env, jobject localRef)
1153 {
1154         java_handle_t *o;
1155
1156         TRACEJNICALLS(("jni_DeleteLocalRef(env=%p, ref=%p)", env, localRef));
1157
1158         o = (java_handle_t *) localRef;
1159
1160         if (o == NULL)
1161                 return;
1162
1163         /* delete the reference */
1164
1165         localref_del(o);
1166 }
1167
1168
1169 /* IsSameObject ****************************************************************
1170
1171    Tests whether two references refer to the same Java object.
1172
1173 *******************************************************************************/
1174
1175 jboolean _Jv_JNI_IsSameObject(JNIEnv *env, jobject ref1, jobject ref2)
1176 {
1177         java_handle_t *o1;
1178         java_handle_t *o2;
1179         jboolean       result;
1180
1181         STATISTICS(jniinvokation());
1182
1183         o1 = (java_handle_t *) ref1;
1184         o2 = (java_handle_t *) ref2;
1185
1186         LLNI_CRITICAL_START;
1187
1188         if (LLNI_UNWRAP(o1) == LLNI_UNWRAP(o2))
1189                 result = JNI_TRUE;
1190         else
1191                 result = JNI_FALSE;
1192
1193         LLNI_CRITICAL_END;
1194
1195         return result;
1196 }
1197
1198
1199 /* NewLocalRef *****************************************************************
1200
1201    Creates a new local reference that refers to the same object as ref.
1202
1203 *******************************************************************************/
1204
1205 jobject jni_NewLocalRef(JNIEnv *env, jobject ref)
1206 {
1207         java_handle_t *o;
1208         java_handle_t *localref;
1209
1210         TRACEJNICALLS(("jni_NewLocalRef(env=%p, ref=%p)", env, ref));
1211
1212         o = (java_handle_t *) ref;
1213
1214         if (o == NULL)
1215                 return NULL;
1216
1217         /* insert the reference */
1218
1219         localref = localref_add(LLNI_DIRECT(o));
1220
1221         return (jobject) localref;
1222 }
1223
1224
1225 /* EnsureLocalCapacity *********************************************************
1226
1227    Ensures that at least a given number of local references can be
1228    created in the current thread
1229
1230 *******************************************************************************/
1231
1232 jint jni_EnsureLocalCapacity(JNIEnv* env, jint capacity)
1233 {
1234         localref_table *lrt;
1235
1236         TRACEJNICALLS(("jni_EnsureLocalCapacity(env=%p, capacity=%d)", env, capacity));
1237
1238         /* get local reference table (thread specific) */
1239
1240         lrt = LOCALREFTABLE;
1241
1242         /* check if capacity elements are available in the local references table */
1243
1244         if ((lrt->used + capacity) > lrt->capacity)
1245                 return jni_PushLocalFrame(env, capacity);
1246
1247         return 0;
1248 }
1249
1250
1251 /* AllocObject *****************************************************************
1252
1253    Allocates a new Java object without invoking any of the
1254    constructors for the object. Returns a reference to the object.
1255
1256 *******************************************************************************/
1257
1258 jobject _Jv_JNI_AllocObject(JNIEnv *env, jclass clazz)
1259 {
1260         classinfo     *c;
1261         java_handle_t *o;
1262
1263         STATISTICS(jniinvokation());
1264
1265         c = LLNI_classinfo_unwrap(clazz);
1266
1267         if ((c->flags & ACC_INTERFACE) || (c->flags & ACC_ABSTRACT)) {
1268                 exceptions_throw_instantiationexception(c);
1269                 return NULL;
1270         }
1271                 
1272         o = builtin_new(c);
1273
1274         return jni_NewLocalRef(env, (jobject) o);
1275 }
1276
1277
1278 /* NewObject *******************************************************************
1279
1280    Programmers place all arguments that are to be passed to the
1281    constructor immediately following the methodID
1282    argument. NewObject() accepts these arguments and passes them to
1283    the Java method that the programmer wishes to invoke.
1284
1285 *******************************************************************************/
1286
1287 jobject jni_NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
1288 {
1289         java_handle_t *o;
1290         classinfo     *c;
1291         methodinfo    *m;
1292         va_list        ap;
1293
1294         TRACEJNICALLSENTER(("jni_NewObject(env=%p, clazz=%p, methodID=%p, ...)", env, clazz, methodID));
1295
1296         c = LLNI_classinfo_unwrap(clazz);
1297         m = (methodinfo *) methodID;
1298
1299         /* create object */
1300
1301         o = builtin_new(c);
1302         
1303         if (o == NULL)
1304                 return NULL;
1305
1306         /* call constructor */
1307
1308         va_start(ap, methodID);
1309         _Jv_jni_CallVoidMethod(o, LLNI_vftbl_direct(o), m, ap);
1310         va_end(ap);
1311
1312         TRACEJNICALLSEXIT(("->%p", o));
1313
1314         return jni_NewLocalRef(env, (jobject) o);
1315 }
1316
1317
1318 /* NewObjectV ******************************************************************
1319
1320    Programmers place all arguments that are to be passed to the
1321    constructor in an args argument of type va_list that immediately
1322    follows the methodID argument. NewObjectV() accepts these
1323    arguments, and, in turn, passes them to the Java method that the
1324    programmer wishes to invoke.
1325
1326 *******************************************************************************/
1327
1328 jobject _Jv_JNI_NewObjectV(JNIEnv* env, jclass clazz, jmethodID methodID,
1329                                                    va_list args)
1330 {
1331         java_handle_t *o;
1332         classinfo     *c;
1333         methodinfo    *m;
1334
1335         STATISTICS(jniinvokation());
1336
1337         c = LLNI_classinfo_unwrap(clazz);
1338         m = (methodinfo *) methodID;
1339
1340         /* create object */
1341
1342         o = builtin_new(c);
1343         
1344         if (o == NULL)
1345                 return NULL;
1346
1347         /* call constructor */
1348
1349         _Jv_jni_CallVoidMethod(o, LLNI_vftbl_direct(o), m, args);
1350
1351         return jni_NewLocalRef(env, (jobject) o);
1352 }
1353
1354
1355 /* NewObjectA ***************************************************************** 
1356
1357    Programmers place all arguments that are to be passed to the
1358    constructor in an args array of jvalues that immediately follows
1359    the methodID argument. NewObjectA() accepts the arguments in this
1360    array, and, in turn, passes them to the Java method that the
1361    programmer wishes to invoke.
1362
1363 *******************************************************************************/
1364
1365 jobject _Jv_JNI_NewObjectA(JNIEnv* env, jclass clazz, jmethodID methodID,
1366                                                    const jvalue *args)
1367 {
1368         java_handle_t *o;
1369         classinfo     *c;
1370         methodinfo    *m;
1371
1372         STATISTICS(jniinvokation());
1373
1374         c = LLNI_classinfo_unwrap(clazz);
1375         m = (methodinfo *) methodID;
1376
1377         /* create object */
1378
1379         o = builtin_new(c);
1380         
1381         if (o == NULL)
1382                 return NULL;
1383
1384         /* call constructor */
1385
1386         _Jv_jni_CallVoidMethodA(o, LLNI_vftbl_direct(o), m, args);
1387
1388         return jni_NewLocalRef(env, (jobject) o);
1389 }
1390
1391
1392 /* GetObjectClass **************************************************************
1393
1394  Returns the class of an object.
1395
1396 *******************************************************************************/
1397
1398 jclass jni_GetObjectClass(JNIEnv *env, jobject obj)
1399 {
1400         java_handle_t* o;
1401         classinfo*     c;
1402
1403         TRACEJNICALLS(("jni_GetObjectClass(env=%p, obj=%p)", env, obj));
1404
1405         o = (java_handle_t *) obj;
1406
1407         if ((o == NULL) || (LLNI_vftbl_direct(o) == NULL))
1408                 return NULL;
1409
1410         LLNI_class_get(o, c);
1411
1412         java_handle_t* h = LLNI_classinfo_wrap(c);
1413
1414         return (jclass) jni_NewLocalRef(env, (jobject) h);
1415 }
1416
1417
1418 /* IsInstanceOf ****************************************************************
1419
1420    Tests whether an object is an instance of a class.
1421
1422 *******************************************************************************/
1423
1424 jboolean _Jv_JNI_IsInstanceOf(JNIEnv *env, jobject obj, jclass clazz)
1425 {
1426         classinfo     *c;
1427         java_handle_t *h;
1428
1429         TRACEJNICALLS(("_Jv_JNI_IsInstanceOf(env=%p, obj=%p, clazz=%p)", env, obj, clazz));
1430
1431         /* XXX Is this correct? */
1432         c = LLNI_classinfo_unwrap(clazz);
1433         h = (java_handle_t *) obj;
1434
1435         return class_is_instance(c, h);
1436 }
1437
1438
1439 /* Reflection Support *********************************************************/
1440
1441 /* FromReflectedMethod *********************************************************
1442
1443    Converts java.lang.reflect.Method or java.lang.reflect.Constructor
1444    object to a method ID.
1445   
1446 *******************************************************************************/
1447   
1448 jmethodID jni_FromReflectedMethod(JNIEnv *env, jobject method)
1449 {
1450 #if defined(ENABLE_JAVASE)
1451         java_handle_t* o;
1452         methodinfo*    m;
1453
1454         TRACEJNICALLS(("jni_FromReflectedMethod(env=%p, method=%p)", env, method));
1455
1456         o = (java_handle_t *) method;
1457
1458         if (o == NULL)
1459                 return NULL;
1460
1461         // FIXME We can't access the object here directly.
1462         if (o->vftbl->clazz == class_java_lang_reflect_Constructor) {
1463                 java_lang_reflect_Constructor rc(method);
1464                 m = rc.get_method();
1465         }
1466         else {
1467                 // FIXME We can't access the object here directly.
1468                 assert(o->vftbl->clazz == class_java_lang_reflect_Method);
1469
1470                 java_lang_reflect_Method rm(method);
1471                 m = rm.get_method();
1472         }
1473
1474         return (jmethodID) m;
1475 #else
1476         vm_abort("jni_FromReflectedMethod: Not implemented in this configuration.");
1477
1478         // Keep compiler happy.
1479         return NULL;
1480 #endif
1481 }
1482
1483
1484 /* FromReflectedField **********************************************************
1485
1486    Converts a java.lang.reflect.Field to a field ID.
1487
1488 *******************************************************************************/
1489  
1490 jfieldID jni_FromReflectedField(JNIEnv* env, jobject field)
1491 {
1492 #if defined(ENABLE_JAVASE)
1493
1494         TRACEJNICALLS(("jni_FromReflectedField(env=%p, field=%p)", env, field));
1495
1496         java_lang_reflect_Field rf(field);
1497
1498         if (rf.is_null())
1499                 return NULL;
1500
1501         fieldinfo* f = rf.get_field();
1502
1503         return (jfieldID) f;
1504 #else
1505         vm_abort("jni_FromReflectedField: Not implemented in this configuration.");
1506
1507         // Keep compiler happy.
1508         return NULL;
1509 #endif
1510 }
1511
1512
1513 /* ToReflectedMethod ***********************************************************
1514
1515    Converts a method ID derived from cls to an instance of the
1516    java.lang.reflect.Method class or to an instance of the
1517    java.lang.reflect.Constructor class.
1518
1519 *******************************************************************************/
1520
1521 jobject jni_ToReflectedMethod(JNIEnv* env, jclass cls, jmethodID methodID, jboolean isStatic)
1522 {
1523 #if defined(ENABLE_JAVASE)
1524         TRACEJNICALLS(("jni_ToReflectedMethod(env=%p, cls=%p, methodID=%p, isStatic=%d)", env, cls, methodID, isStatic));
1525
1526         methodinfo* m = (methodinfo *) methodID;
1527
1528         /* HotSpot does the same assert. */
1529
1530         assert(((m->flags & ACC_STATIC) != 0) == (isStatic != 0));
1531
1532         java_handle_t* h;
1533
1534         if (m->name == utf_init) {
1535                 h = java_lang_reflect_Constructor(m).get_handle();
1536         }
1537         else {
1538                 h = java_lang_reflect_Method(m).get_handle();
1539         }
1540
1541         return (jobject) h;
1542 #else
1543         vm_abort("jni_ToReflectedMethod: Not implemented in this configuration.");
1544
1545         /* keep compiler happy */
1546
1547         return NULL;
1548 #endif
1549 }
1550
1551
1552 /* ToReflectedField ************************************************************
1553
1554    Converts a field ID derived from cls to an instance of the
1555    java.lang.reflect.Field class.
1556
1557 *******************************************************************************/
1558
1559 jobject _Jv_JNI_ToReflectedField(JNIEnv* env, jclass cls, jfieldID fieldID,
1560                                                                  jboolean isStatic)
1561 {
1562         STATISTICS(jniinvokation());
1563
1564         log_text("JNI-Call: ToReflectedField: IMPLEMENT ME!");
1565
1566         return NULL;
1567 }
1568
1569
1570 /* Calling Instance Methods ***************************************************/
1571
1572 /* GetMethodID *****************************************************************
1573
1574    Returns the method ID for an instance (nonstatic) method of a class
1575    or interface. The method may be defined in one of the clazz's
1576    superclasses and inherited by clazz. The method is determined by
1577    its name and signature.
1578
1579    GetMethodID() causes an uninitialized class to be initialized.
1580
1581 *******************************************************************************/
1582
1583 jmethodID _Jv_JNI_GetMethodID(JNIEnv* env, jclass clazz, const char *name,
1584                                                           const char *sig)
1585 {
1586         classinfo  *c;
1587         utf        *uname;
1588         utf        *udesc;
1589         methodinfo *m;
1590
1591         STATISTICS(jniinvokation());
1592
1593         c = LLNI_classinfo_unwrap(clazz);
1594
1595         if (c == NULL)
1596                 return NULL;
1597
1598         if (!(c->state & CLASS_INITIALIZED))
1599                 if (!initialize_class(c))
1600                         return NULL;
1601
1602         /* try to get the method of the class or one of it's superclasses */
1603
1604         uname = utf_new_char((char *) name);
1605         udesc = utf_new_char((char *) sig);
1606
1607         m = class_resolvemethod(c, uname, udesc);
1608
1609         if ((m == NULL) || (m->flags & ACC_STATIC)) {
1610                 exceptions_throw_nosuchmethoderror(c, uname, udesc);
1611
1612                 return NULL;
1613         }
1614
1615         return (jmethodID) m;
1616 }
1617
1618
1619 /* JNI-functions for calling instance methods *********************************/
1620
1621 #define JNI_CALL_VIRTUAL_METHOD(name, type, intern)         \
1622 type _Jv_JNI_Call##name##Method(JNIEnv *env, jobject obj,   \
1623                                                                 jmethodID methodID, ...)    \
1624 {                                                           \
1625         java_handle_t *o;                                       \
1626         methodinfo    *m;                                       \
1627         va_list        ap;                                      \
1628         type           ret;                                     \
1629                                                             \
1630         o = (java_handle_t *) obj;                              \
1631         m = (methodinfo *) methodID;                            \
1632                                                             \
1633         va_start(ap, methodID);                                 \
1634         ret = _Jv_jni_Call##intern##Method(o, LLNI_vftbl_direct(o), m, ap); \
1635         va_end(ap);                                             \
1636                                                             \
1637         return ret;                                             \
1638 }
1639
1640 JNI_CALL_VIRTUAL_METHOD(Boolean, jboolean, Int)
1641 JNI_CALL_VIRTUAL_METHOD(Byte,    jbyte,    Int)
1642 JNI_CALL_VIRTUAL_METHOD(Char,    jchar,    Int)
1643 JNI_CALL_VIRTUAL_METHOD(Short,   jshort,   Int)
1644 JNI_CALL_VIRTUAL_METHOD(Int,     jint,     Int)
1645 JNI_CALL_VIRTUAL_METHOD(Long,    jlong,    Long)
1646 JNI_CALL_VIRTUAL_METHOD(Float,   jfloat,   Float)
1647 JNI_CALL_VIRTUAL_METHOD(Double,  jdouble,  Double)
1648
1649
1650 #define JNI_CALL_VIRTUAL_METHOD_V(name, type, intern)              \
1651 type _Jv_JNI_Call##name##MethodV(JNIEnv *env, jobject obj,         \
1652                                                                  jmethodID methodID, va_list args) \
1653 {                                                                  \
1654         java_handle_t *o;                                              \
1655         methodinfo    *m;                                              \
1656         type           ret;                                            \
1657                                                                    \
1658         o = (java_handle_t *) obj;                                     \
1659         m = (methodinfo *) methodID;                                   \
1660                                                                    \
1661         ret = _Jv_jni_Call##intern##Method(o, LLNI_vftbl_direct(o), m, args);      \
1662                                                                    \
1663         return ret;                                                    \
1664 }
1665
1666 JNI_CALL_VIRTUAL_METHOD_V(Boolean, jboolean, Int)
1667 JNI_CALL_VIRTUAL_METHOD_V(Byte,    jbyte,    Int)
1668 JNI_CALL_VIRTUAL_METHOD_V(Char,    jchar,    Int)
1669 JNI_CALL_VIRTUAL_METHOD_V(Short,   jshort,   Int)
1670 JNI_CALL_VIRTUAL_METHOD_V(Int,     jint,     Int)
1671 JNI_CALL_VIRTUAL_METHOD_V(Long,    jlong,    Long)
1672 JNI_CALL_VIRTUAL_METHOD_V(Float,   jfloat,   Float)
1673 JNI_CALL_VIRTUAL_METHOD_V(Double,  jdouble,  Double)
1674
1675
1676 #define JNI_CALL_VIRTUAL_METHOD_A(name, type, intern)          \
1677 type _Jv_JNI_Call##name##MethodA(JNIEnv *env, jobject obj,     \
1678                                                                  jmethodID methodID,           \
1679                                                                  const jvalue *args)           \
1680 {                                                              \
1681         java_handle_t *o;                                          \
1682         methodinfo    *m;                                          \
1683         type           ret;                                        \
1684                                                                \
1685         o = (java_handle_t *) obj;                                 \
1686         m = (methodinfo *) methodID;                               \
1687                                                                \
1688         ret = _Jv_jni_Call##intern##MethodA(o, LLNI_vftbl_direct(o), m, args); \
1689                                                                \
1690         return ret;                                                \
1691 }
1692
1693 JNI_CALL_VIRTUAL_METHOD_A(Boolean, jboolean, Int)
1694 JNI_CALL_VIRTUAL_METHOD_A(Byte,    jbyte,    Int)
1695 JNI_CALL_VIRTUAL_METHOD_A(Char,    jchar,    Int)
1696 JNI_CALL_VIRTUAL_METHOD_A(Short,   jshort,   Int)
1697 JNI_CALL_VIRTUAL_METHOD_A(Int,     jint,     Int)
1698 JNI_CALL_VIRTUAL_METHOD_A(Long,    jlong,    Long)
1699 JNI_CALL_VIRTUAL_METHOD_A(Float,   jfloat,   Float)
1700 JNI_CALL_VIRTUAL_METHOD_A(Double,  jdouble,  Double)
1701
1702
1703 jobject _Jv_JNI_CallObjectMethod(JNIEnv *env, jobject obj, jmethodID methodID,
1704                                                                  ...)
1705 {
1706         java_handle_t *o;
1707         methodinfo    *m;
1708         java_handle_t *ret;
1709         va_list        ap;
1710
1711         o = (java_handle_t *) obj;
1712         m = (methodinfo *) methodID;
1713
1714         va_start(ap, methodID);
1715         ret = _Jv_jni_CallObjectMethod(o, LLNI_vftbl_direct(o), m, ap);
1716         va_end(ap);
1717
1718         return jni_NewLocalRef(env, (jobject) ret);
1719 }
1720
1721
1722 jobject _Jv_JNI_CallObjectMethodV(JNIEnv *env, jobject obj, jmethodID methodID,
1723                                                                   va_list args)
1724 {
1725         java_handle_t *o;
1726         methodinfo    *m;
1727         java_handle_t *ret;
1728
1729         o = (java_handle_t *) obj;
1730         m = (methodinfo *) methodID;
1731
1732         ret = _Jv_jni_CallObjectMethod(o, LLNI_vftbl_direct(o), m, args);
1733
1734         return jni_NewLocalRef(env, (jobject) ret);
1735 }
1736
1737
1738 jobject _Jv_JNI_CallObjectMethodA(JNIEnv *env, jobject obj, jmethodID methodID,
1739                                                                   const jvalue *args)
1740 {
1741         java_handle_t *o;
1742         methodinfo    *m;
1743         java_handle_t *ret;
1744
1745         o = (java_handle_t *) obj;
1746         m = (methodinfo *) methodID;
1747
1748         ret = _Jv_jni_CallObjectMethodA(o, LLNI_vftbl_direct(o), m, args);
1749
1750         return jni_NewLocalRef(env, (jobject) ret);
1751 }
1752
1753
1754
1755 void _Jv_JNI_CallVoidMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
1756 {
1757         java_handle_t *o;
1758         methodinfo    *m;
1759         va_list        ap;
1760
1761         o = (java_handle_t *) obj;
1762         m = (methodinfo *) methodID;
1763
1764         va_start(ap, methodID);
1765         _Jv_jni_CallVoidMethod(o, LLNI_vftbl_direct(o), m, ap);
1766         va_end(ap);
1767 }
1768
1769
1770 void _Jv_JNI_CallVoidMethodV(JNIEnv *env, jobject obj, jmethodID methodID,
1771                                                          va_list args)
1772 {
1773         java_handle_t *o;
1774         methodinfo    *m;
1775
1776         o = (java_handle_t *) obj;
1777         m = (methodinfo *) methodID;
1778
1779         _Jv_jni_CallVoidMethod(o, LLNI_vftbl_direct(o), m, args);
1780 }
1781
1782
1783 void _Jv_JNI_CallVoidMethodA(JNIEnv *env, jobject obj, jmethodID methodID,
1784                                                          const jvalue *args)
1785 {
1786         java_handle_t *o;
1787         methodinfo    *m;
1788
1789         o = (java_handle_t *) obj;
1790         m = (methodinfo *) methodID;
1791
1792         _Jv_jni_CallVoidMethodA(o, LLNI_vftbl_direct(o), m, args);
1793 }
1794
1795
1796
1797 #define JNI_CALL_NONVIRTUAL_METHOD(name, type, intern)                      \
1798 type _Jv_JNI_CallNonvirtual##name##Method(JNIEnv *env, jobject obj,         \
1799                                                                                   jclass clazz, jmethodID methodID, \
1800                                                                                   ...)                              \
1801 {                                                                           \
1802         java_handle_t *o;                                                       \
1803         classinfo     *c;                                                       \
1804         methodinfo    *m;                                                       \
1805         va_list        ap;                                                      \
1806         type           ret;                                                     \
1807                                                                             \
1808         o = (java_handle_t *) obj;                                              \
1809         c = LLNI_classinfo_unwrap(clazz);                                       \
1810         m = (methodinfo *) methodID;                                            \
1811                                                                             \
1812         va_start(ap, methodID);                                                 \
1813         ret = _Jv_jni_Call##intern##Method(o, c->vftbl, m, ap);                 \
1814         va_end(ap);                                                             \
1815                                                                             \
1816         return ret;                                                             \
1817 }
1818
1819 JNI_CALL_NONVIRTUAL_METHOD(Boolean, jboolean, Int)
1820 JNI_CALL_NONVIRTUAL_METHOD(Byte,    jbyte,    Int)
1821 JNI_CALL_NONVIRTUAL_METHOD(Char,    jchar,    Int)
1822 JNI_CALL_NONVIRTUAL_METHOD(Short,   jshort,   Int)
1823 JNI_CALL_NONVIRTUAL_METHOD(Int,     jint,     Int)
1824 JNI_CALL_NONVIRTUAL_METHOD(Long,    jlong,    Long)
1825 JNI_CALL_NONVIRTUAL_METHOD(Float,   jfloat,   Float)
1826 JNI_CALL_NONVIRTUAL_METHOD(Double,  jdouble,  Double)
1827
1828
1829 #define JNI_CALL_NONVIRTUAL_METHOD_V(name, type, intern)                     \
1830 type _Jv_JNI_CallNonvirtual##name##MethodV(JNIEnv *env, jobject obj,         \
1831                                                                                    jclass clazz, jmethodID methodID, \
1832                                                                                    va_list args)                     \
1833 {                                                                            \
1834         java_handle_t *o;                                                        \
1835         classinfo     *c;                                                        \
1836         methodinfo    *m;                                                        \
1837         type           ret;                                                      \
1838                                                                              \
1839         o = (java_handle_t *) obj;                                               \
1840         c = LLNI_classinfo_unwrap(clazz);                                        \
1841         m = (methodinfo *) methodID;                                             \
1842                                                                              \
1843         ret = _Jv_jni_CallIntMethod(o, c->vftbl, m, args);                       \
1844                                                                              \
1845         return ret;                                                              \
1846 }
1847
1848 JNI_CALL_NONVIRTUAL_METHOD_V(Boolean, jboolean, Int)
1849 JNI_CALL_NONVIRTUAL_METHOD_V(Byte,    jbyte,    Int)
1850 JNI_CALL_NONVIRTUAL_METHOD_V(Char,    jchar,    Int)
1851 JNI_CALL_NONVIRTUAL_METHOD_V(Short,   jshort,   Int)
1852 JNI_CALL_NONVIRTUAL_METHOD_V(Int,     jint,     Int)
1853 JNI_CALL_NONVIRTUAL_METHOD_V(Long,    jlong,    Long)
1854 JNI_CALL_NONVIRTUAL_METHOD_V(Float,   jfloat,   Float)
1855 JNI_CALL_NONVIRTUAL_METHOD_V(Double,  jdouble,  Double)
1856
1857
1858 #define JNI_CALL_NONVIRTUAL_METHOD_A(name, type, intern)                     \
1859 type _Jv_JNI_CallNonvirtual##name##MethodA(JNIEnv *env, jobject obj,         \
1860                                                                                    jclass clazz, jmethodID methodID, \
1861                                                                                    const jvalue *args)               \
1862 {                                                                            \
1863         log_text("JNI-Call: CallNonvirtual##name##MethodA: IMPLEMENT ME!");      \
1864                                                                              \
1865         return 0;                                                                \
1866 }
1867
1868 JNI_CALL_NONVIRTUAL_METHOD_A(Boolean, jboolean, Int)
1869 JNI_CALL_NONVIRTUAL_METHOD_A(Byte,    jbyte,    Int)
1870 JNI_CALL_NONVIRTUAL_METHOD_A(Char,    jchar,    Int)
1871 JNI_CALL_NONVIRTUAL_METHOD_A(Short,   jshort,   Int)
1872 JNI_CALL_NONVIRTUAL_METHOD_A(Int,     jint,     Int)
1873 JNI_CALL_NONVIRTUAL_METHOD_A(Long,    jlong,    Long)
1874 JNI_CALL_NONVIRTUAL_METHOD_A(Float,   jfloat,   Float)
1875 JNI_CALL_NONVIRTUAL_METHOD_A(Double,  jdouble,  Double)
1876
1877 jobject _Jv_JNI_CallNonvirtualObjectMethod(JNIEnv *env, jobject obj,
1878                                                                                    jclass clazz, jmethodID methodID,
1879                                                                                    ...)
1880 {
1881         java_handle_t *o;
1882         classinfo     *c;
1883         methodinfo    *m;
1884         java_handle_t *r;
1885         va_list        ap;
1886
1887         o = (java_handle_t *) obj;
1888         c = LLNI_classinfo_unwrap(clazz);
1889         m = (methodinfo *) methodID;
1890
1891         va_start(ap, methodID);
1892         r = _Jv_jni_CallObjectMethod(o, c->vftbl, m, ap);
1893         va_end(ap);
1894
1895         return jni_NewLocalRef(env, (jobject) r);
1896 }
1897
1898
1899 jobject _Jv_JNI_CallNonvirtualObjectMethodV(JNIEnv *env, jobject obj,
1900                                                                                         jclass clazz, jmethodID methodID,
1901                                                                                         va_list args)
1902 {
1903         java_handle_t *o;
1904         classinfo     *c;
1905         methodinfo    *m;
1906         java_handle_t *r;
1907
1908         o = (java_handle_t *) obj;
1909         c = LLNI_classinfo_unwrap(clazz);
1910         m = (methodinfo *) methodID;
1911
1912         r = _Jv_jni_CallObjectMethod(o, c->vftbl, m, args);
1913
1914         return jni_NewLocalRef(env, (jobject) r);
1915 }
1916
1917
1918 jobject _Jv_JNI_CallNonvirtualObjectMethodA(JNIEnv *env, jobject obj,
1919                                                                                         jclass clazz, jmethodID methodID,
1920                                                                                         const jvalue *args)
1921 {
1922         log_text("JNI-Call: CallNonvirtualObjectMethodA: IMPLEMENT ME!");
1923
1924         return jni_NewLocalRef(env, NULL);
1925 }
1926
1927
1928 void _Jv_JNI_CallNonvirtualVoidMethod(JNIEnv *env, jobject obj, jclass clazz,
1929                                                                           jmethodID methodID, ...)
1930 {
1931         java_handle_t *o;
1932         classinfo     *c;
1933         methodinfo    *m;
1934         va_list        ap;
1935
1936         o = (java_handle_t *) obj;
1937         c = LLNI_classinfo_unwrap(clazz);
1938         m = (methodinfo *) methodID;
1939
1940         va_start(ap, methodID);
1941         _Jv_jni_CallVoidMethod(o, c->vftbl, m, ap);
1942         va_end(ap);
1943 }
1944
1945
1946 void _Jv_JNI_CallNonvirtualVoidMethodV(JNIEnv *env, jobject obj, jclass clazz,
1947                                                                            jmethodID methodID, va_list args)
1948 {
1949         java_handle_t *o;
1950         classinfo     *c;
1951         methodinfo    *m;
1952
1953         o = (java_handle_t *) obj;
1954         c = LLNI_classinfo_unwrap(clazz);
1955         m = (methodinfo *) methodID;
1956
1957         _Jv_jni_CallVoidMethod(o, c->vftbl, m, args);
1958 }
1959
1960
1961 void _Jv_JNI_CallNonvirtualVoidMethodA(JNIEnv *env, jobject obj, jclass clazz,
1962                                                                            jmethodID methodID, const jvalue * args)
1963 {       
1964         java_handle_t *o;
1965         classinfo     *c;
1966         methodinfo    *m;
1967
1968         o = (java_handle_t *) obj;
1969         c = LLNI_classinfo_unwrap(clazz);
1970         m = (methodinfo *) methodID;
1971
1972         _Jv_jni_CallVoidMethodA(o, c->vftbl, m, args);
1973 }
1974
1975
1976 /* Accessing Fields of Objects ************************************************/
1977
1978 /* GetFieldID ******************************************************************
1979
1980    Returns the field ID for an instance (nonstatic) field of a
1981    class. The field is specified by its name and signature. The
1982    Get<type>Field and Set<type>Field families of accessor functions
1983    use field IDs to retrieve object fields.
1984
1985 *******************************************************************************/
1986
1987 jfieldID _Jv_JNI_GetFieldID(JNIEnv *env, jclass clazz, const char *name,
1988                                                         const char *sig)
1989 {
1990         classinfo *c;
1991         fieldinfo *f;
1992         utf       *uname;
1993         utf       *udesc;
1994
1995         STATISTICS(jniinvokation());
1996
1997         c = LLNI_classinfo_unwrap(clazz);
1998
1999         /* XXX NPE check? */
2000
2001         uname = utf_new_char((char *) name);
2002         udesc = utf_new_char((char *) sig);
2003
2004         f = class_findfield(c, uname, udesc); 
2005         
2006         if (f == NULL)
2007                 exceptions_throw_nosuchfielderror(c, uname);  
2008
2009         return (jfieldID) f;
2010 }
2011
2012
2013 /* Get<type>Field Routines *****************************************************
2014
2015    This family of accessor routines returns the value of an instance
2016    (nonstatic) field of an object. The field to access is specified by
2017    a field ID obtained by calling GetFieldID().
2018
2019 *******************************************************************************/
2020
2021 #define GET_FIELD(o,type,f) \
2022     *((type *) (((intptr_t) (o)) + ((intptr_t) ((fieldinfo *) (f))->offset)))
2023
2024 #define JNI_GET_FIELD(name, type, intern)                                 \
2025 type _Jv_JNI_Get##name##Field(JNIEnv *env, jobject obj, jfieldID fieldID) \
2026 {                                                                         \
2027         intern ret;                                                           \
2028                                                                           \
2029         TRACEJNICALLS(("_Jv_JNI_Get" STR(name) "Field(env=%p, obj=%p, fieldId=%p)", env, obj, fieldID)); \
2030                                                                           \
2031         LLNI_CRITICAL_START;                                                  \
2032                                                                           \
2033         ret = GET_FIELD(LLNI_DIRECT((java_handle_t *) obj), intern, fieldID); \
2034                                                                           \
2035         LLNI_CRITICAL_END;                                                    \
2036                                                                           \
2037         return (type) ret;                                                    \
2038 }
2039
2040 JNI_GET_FIELD(Boolean, jboolean, s4)
2041 JNI_GET_FIELD(Byte,    jbyte,    s4)
2042 JNI_GET_FIELD(Char,    jchar,    s4)
2043 JNI_GET_FIELD(Short,   jshort,   s4)
2044 JNI_GET_FIELD(Int,     jint,     s4)
2045 JNI_GET_FIELD(Long,    jlong,    s8)
2046 JNI_GET_FIELD(Float,   jfloat,   float)
2047 JNI_GET_FIELD(Double,  jdouble,  double)
2048
2049
2050 jobject _Jv_JNI_GetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID)
2051 {
2052         java_handle_t *o;
2053
2054         TRACEJNICALLS(("_Jv_JNI_GetObjectField(env=%p, obj=%p, fieldId=%p)", env, obj, fieldID));
2055
2056         LLNI_CRITICAL_START;
2057
2058         o = LLNI_WRAP(GET_FIELD(LLNI_DIRECT((java_handle_t *) obj), java_object_t*, fieldID));
2059
2060         LLNI_CRITICAL_END;
2061
2062         return jni_NewLocalRef(env, (jobject) o);
2063 }
2064
2065
2066 /* Set<type>Field Routines *****************************************************
2067
2068    This family of accessor routines sets the value of an instance
2069    (nonstatic) field of an object. The field to access is specified by
2070    a field ID obtained by calling GetFieldID().
2071
2072 *******************************************************************************/
2073
2074 #define SET_FIELD(o,type,f,value) \
2075     *((type *) (((intptr_t) (o)) + ((intptr_t) ((fieldinfo *) (f))->offset))) = (type) (value)
2076
2077 #define JNI_SET_FIELD(name, type, intern)                                  \
2078 void _Jv_JNI_Set##name##Field(JNIEnv *env, jobject obj, jfieldID fieldID,  \
2079                                                           type value)                                  \
2080 {                                                                          \
2081         TRACEJNICALLS(("_Jv_JNI_Set" STR(name) "Field(env=%p, obj=%p, fieldId=%p, value=%p)", env, obj, fieldID, value)); \
2082                                                                            \
2083         LLNI_CRITICAL_START;                                                   \
2084                                                                            \
2085         SET_FIELD(LLNI_DIRECT((java_handle_t *) obj), intern, fieldID, value); \
2086                                                                                \
2087         LLNI_CRITICAL_START;                                                   \
2088 }
2089
2090 JNI_SET_FIELD(Boolean, jboolean, s4)
2091 JNI_SET_FIELD(Byte,    jbyte,    s4)
2092 JNI_SET_FIELD(Char,    jchar,    s4)
2093 JNI_SET_FIELD(Short,   jshort,   s4)
2094 JNI_SET_FIELD(Int,     jint,     s4)
2095 JNI_SET_FIELD(Long,    jlong,    s8)
2096 JNI_SET_FIELD(Float,   jfloat,   float)
2097 JNI_SET_FIELD(Double,  jdouble,  double)
2098
2099
2100 void _Jv_JNI_SetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID,
2101                                                         jobject value)
2102 {
2103         TRACEJNICALLS(("_Jv_JNI_SetObjectField(env=%p, obj=%p, fieldId=%p, value=%p)", env, obj, fieldID, value));
2104
2105         LLNI_CRITICAL_START;
2106
2107         SET_FIELD(obj, java_handle_t*, fieldID, LLNI_UNWRAP((java_handle_t*) value));
2108
2109         LLNI_CRITICAL_END;
2110 }
2111
2112
2113 /* Calling Static Methods *****************************************************/
2114
2115 /* GetStaticMethodID ***********************************************************
2116
2117    Returns the method ID for a static method of a class. The method is
2118    specified by its name and signature.
2119
2120    GetStaticMethodID() causes an uninitialized class to be
2121    initialized.
2122
2123 *******************************************************************************/
2124
2125 jmethodID _Jv_JNI_GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name,
2126                                                                         const char *sig)
2127 {
2128         classinfo  *c;
2129         utf        *uname;
2130         utf        *udesc;
2131         methodinfo *m;
2132
2133         TRACEJNICALLS(("_Jv_JNI_GetStaticMethodID(env=%p, clazz=%p, name=%s, sig=%s)", env, clazz, name, sig));
2134
2135         c = LLNI_classinfo_unwrap(clazz);
2136
2137         if (c == NULL)
2138                 return NULL;
2139
2140         if (!(c->state & CLASS_INITIALIZED))
2141                 if (!initialize_class(c))
2142                         return NULL;
2143
2144         /* try to get the static method of the class */
2145
2146         uname = utf_new_char((char *) name);
2147         udesc = utf_new_char((char *) sig);
2148
2149         m = class_resolvemethod(c, uname, udesc);
2150
2151         if ((m == NULL) || !(m->flags & ACC_STATIC)) {
2152                 exceptions_throw_nosuchmethoderror(c, uname, udesc);
2153
2154                 return NULL;
2155         }
2156
2157         return (jmethodID) m;
2158 }
2159
2160
2161 #define JNI_CALL_STATIC_METHOD(name, type, intern)               \
2162 type _Jv_JNI_CallStatic##name##Method(JNIEnv *env, jclass clazz, \
2163                                                                           jmethodID methodID, ...)   \
2164 {                                                                \
2165         methodinfo *m;                                               \
2166         va_list     ap;                                              \
2167         type        res;                                             \
2168                                                                  \
2169         m = (methodinfo *) methodID;                                 \
2170                                                                  \
2171         va_start(ap, methodID);                                      \
2172         res = _Jv_jni_Call##intern##Method(NULL, NULL, m, ap);       \
2173         va_end(ap);                                                  \
2174                                                                  \
2175         return res;                                                  \
2176 }
2177
2178 JNI_CALL_STATIC_METHOD(Boolean, jboolean, Int)
2179 JNI_CALL_STATIC_METHOD(Byte,    jbyte,    Int)
2180 JNI_CALL_STATIC_METHOD(Char,    jchar,    Int)
2181 JNI_CALL_STATIC_METHOD(Short,   jshort,   Int)
2182 JNI_CALL_STATIC_METHOD(Int,     jint,     Int)
2183 JNI_CALL_STATIC_METHOD(Long,    jlong,    Long)
2184 JNI_CALL_STATIC_METHOD(Float,   jfloat,   Float)
2185 JNI_CALL_STATIC_METHOD(Double,  jdouble,  Double)
2186
2187
2188 #define JNI_CALL_STATIC_METHOD_V(name, type, intern)                     \
2189 type _Jv_JNI_CallStatic##name##MethodV(JNIEnv *env, jclass clazz,        \
2190                                                                            jmethodID methodID, va_list args) \
2191 {                                                                        \
2192         methodinfo *m;                                                       \
2193         type        res;                                                     \
2194                                                                          \
2195         m = (methodinfo *) methodID;                                         \
2196                                                                          \
2197         res = _Jv_jni_Call##intern##Method(NULL, NULL, m, args);             \
2198                                                                          \
2199         return res;                                                          \
2200 }
2201
2202 JNI_CALL_STATIC_METHOD_V(Boolean, jboolean, Int)
2203 JNI_CALL_STATIC_METHOD_V(Byte,    jbyte,    Int)
2204 JNI_CALL_STATIC_METHOD_V(Char,    jchar,    Int)
2205 JNI_CALL_STATIC_METHOD_V(Short,   jshort,   Int)
2206 JNI_CALL_STATIC_METHOD_V(Int,     jint,     Int)
2207 JNI_CALL_STATIC_METHOD_V(Long,    jlong,    Long)
2208 JNI_CALL_STATIC_METHOD_V(Float,   jfloat,   Float)
2209 JNI_CALL_STATIC_METHOD_V(Double,  jdouble,  Double)
2210
2211
2212 #define JNI_CALL_STATIC_METHOD_A(name, type, intern)                           \
2213 type _Jv_JNI_CallStatic##name##MethodA(JNIEnv *env, jclass clazz,              \
2214                                                                            jmethodID methodID, const jvalue *args) \
2215 {                                                                              \
2216         methodinfo *m;                                                             \
2217         type        res;                                                           \
2218                                                                                \
2219         m = (methodinfo *) methodID;                                               \
2220                                                                                \
2221         res = _Jv_jni_Call##intern##MethodA(NULL, NULL, m, args);                  \
2222                                                                                \
2223         return res;                                                                \
2224 }
2225
2226 JNI_CALL_STATIC_METHOD_A(Boolean, jboolean, Int)
2227 JNI_CALL_STATIC_METHOD_A(Byte,    jbyte,    Int)
2228 JNI_CALL_STATIC_METHOD_A(Char,    jchar,    Int)
2229 JNI_CALL_STATIC_METHOD_A(Short,   jshort,   Int)
2230 JNI_CALL_STATIC_METHOD_A(Int,     jint,     Int)
2231 JNI_CALL_STATIC_METHOD_A(Long,    jlong,    Long)
2232 JNI_CALL_STATIC_METHOD_A(Float,   jfloat,   Float)
2233 JNI_CALL_STATIC_METHOD_A(Double,  jdouble,  Double)
2234
2235
2236 jobject _Jv_JNI_CallStaticObjectMethod(JNIEnv *env, jclass clazz,
2237                                                                            jmethodID methodID, ...)
2238 {
2239         methodinfo    *m;
2240         java_handle_t *o;
2241         va_list        ap;
2242
2243         TRACEJNICALLS(("_Jv_JNI_CallStaticObjectMethod(env=%p, clazz=%p, methodID=%p, ...)", env, clazz, methodID));
2244
2245         m = (methodinfo *) methodID;
2246
2247         va_start(ap, methodID);
2248         o = _Jv_jni_CallObjectMethod(NULL, NULL, m, ap);
2249         va_end(ap);
2250
2251         return jni_NewLocalRef(env, (jobject) o);
2252 }
2253
2254
2255 jobject _Jv_JNI_CallStaticObjectMethodV(JNIEnv *env, jclass clazz,
2256                                                                                 jmethodID methodID, va_list args)
2257 {
2258         methodinfo    *m;
2259         java_handle_t *o;
2260
2261         TRACEJNICALLS(("_Jv_JNI_CallStaticObjectMethodV(env=%p, clazz=%p, methodID=%p, args=%p)", env, clazz, methodID, args));
2262
2263         m = (methodinfo *) methodID;
2264
2265         o = _Jv_jni_CallObjectMethod(NULL, NULL, m, args);
2266
2267         return jni_NewLocalRef(env, (jobject) o);
2268 }
2269
2270
2271 jobject _Jv_JNI_CallStaticObjectMethodA(JNIEnv *env, jclass clazz,
2272                                                                                 jmethodID methodID, const jvalue *args)
2273 {
2274         methodinfo    *m;
2275         java_handle_t *o;
2276
2277         TRACEJNICALLS(("_Jv_JNI_CallStaticObjectMethodA(env=%p, clazz=%p, methodID=%p, args=%p)", env, clazz, methodID, args));
2278
2279         m = (methodinfo *) methodID;
2280
2281         o = _Jv_jni_CallObjectMethodA(NULL, NULL, m, args);
2282
2283         return jni_NewLocalRef(env, (jobject) o);
2284 }
2285
2286
2287 void _Jv_JNI_CallStaticVoidMethod(JNIEnv *env, jclass clazz,
2288                                                                   jmethodID methodID, ...)
2289 {
2290         methodinfo *m;
2291         va_list     ap;
2292
2293         TRACEJNICALLS(("_Jv_JNI_CallStaticVoidMethod(env=%p, clazz=%p, methodID=%p, ...)", env, clazz, methodID));
2294
2295         m = (methodinfo *) methodID;
2296
2297         va_start(ap, methodID);
2298         _Jv_jni_CallVoidMethod(NULL, NULL, m, ap);
2299         va_end(ap);
2300 }
2301
2302
2303 void _Jv_JNI_CallStaticVoidMethodV(JNIEnv *env, jclass clazz,
2304                                                                    jmethodID methodID, va_list args)
2305 {
2306         methodinfo *m;
2307
2308         TRACEJNICALLS(("_Jv_JNI_CallStaticVoidMethodV(env=%p, clazz=%p, methodID=%p, args=%p)", env, clazz, methodID, args));
2309
2310         m = (methodinfo *) methodID;
2311
2312         _Jv_jni_CallVoidMethod(NULL, NULL, m, args);
2313 }
2314
2315
2316 void _Jv_JNI_CallStaticVoidMethodA(JNIEnv *env, jclass clazz,
2317                                                                    jmethodID methodID, const jvalue * args)
2318 {
2319         methodinfo *m;
2320
2321         TRACEJNICALLS(("_Jv_JNI_CallStaticVoidMethodA(env=%p, clazz=%p, methodID=%p, args=%p)", env, clazz, methodID, args));
2322
2323         m = (methodinfo *) methodID;
2324
2325         _Jv_jni_CallVoidMethodA(NULL, NULL, m, args);
2326 }
2327
2328
2329 /* Accessing Static Fields ****************************************************/
2330
2331 /* GetStaticFieldID ************************************************************
2332
2333    Returns the field ID for a static field of a class. The field is
2334    specified by its name and signature. The GetStatic<type>Field and
2335    SetStatic<type>Field families of accessor functions use field IDs
2336    to retrieve static fields.
2337
2338 *******************************************************************************/
2339
2340 jfieldID _Jv_JNI_GetStaticFieldID(JNIEnv *env, jclass clazz, const char *name,
2341                                                                   const char *sig)
2342 {
2343         classinfo *c;
2344         fieldinfo *f;
2345         utf       *uname;
2346         utf       *usig;
2347
2348         STATISTICS(jniinvokation());
2349
2350         c = LLNI_classinfo_unwrap(clazz);
2351
2352         uname = utf_new_char((char *) name);
2353         usig  = utf_new_char((char *) sig);
2354
2355         f = class_findfield(c, uname, usig);
2356         
2357         if (f == NULL)
2358                 exceptions_throw_nosuchfielderror(c, uname);
2359
2360         return (jfieldID) f;
2361 }
2362
2363
2364 /* GetStatic<type>Field ********************************************************
2365
2366    This family of accessor routines returns the value of a static
2367    field of an object.
2368
2369 *******************************************************************************/
2370
2371 #define JNI_GET_STATIC_FIELD(name, type, field)                \
2372 type _Jv_JNI_GetStatic##name##Field(JNIEnv *env, jclass clazz, \
2373                                                                         jfieldID fieldID)          \
2374 {                                                              \
2375         classinfo *c;                                              \
2376         fieldinfo *f;                                              \
2377                                                                \
2378         STATISTICS(jniinvokation());                               \
2379                                                                \
2380         c = LLNI_classinfo_unwrap(clazz);                          \
2381         f = (fieldinfo *) fieldID;                                 \
2382                                                                \
2383         if (!(c->state & CLASS_INITIALIZED))                       \
2384                 if (!initialize_class(c))                              \
2385                         return 0;                                          \
2386                                                                \
2387         return f->value->field;                                    \
2388 }
2389
2390 JNI_GET_STATIC_FIELD(Boolean, jboolean, i)
2391 JNI_GET_STATIC_FIELD(Byte,    jbyte,    i)
2392 JNI_GET_STATIC_FIELD(Char,    jchar,    i)
2393 JNI_GET_STATIC_FIELD(Short,   jshort,   i)
2394 JNI_GET_STATIC_FIELD(Int,     jint,     i)
2395 JNI_GET_STATIC_FIELD(Long,    jlong,    l)
2396 JNI_GET_STATIC_FIELD(Float,   jfloat,   f)
2397 JNI_GET_STATIC_FIELD(Double,  jdouble,  d)
2398
2399
2400 jobject _Jv_JNI_GetStaticObjectField(JNIEnv *env, jclass clazz,
2401                                                                          jfieldID fieldID)
2402 {
2403         classinfo     *c;
2404         fieldinfo     *f;
2405         java_handle_t *h;
2406
2407         STATISTICS(jniinvokation());
2408
2409         c = LLNI_classinfo_unwrap(clazz);
2410         f = (fieldinfo *) fieldID;
2411
2412         if (!(c->state & CLASS_INITIALIZED))
2413                 if (!initialize_class(c))
2414                         return NULL;
2415
2416         h = (java_handle_t*) LLNI_WRAP(f->value->a);
2417
2418         return jni_NewLocalRef(env, (jobject) h);
2419 }
2420
2421
2422 /*  SetStatic<type>Field *******************************************************
2423
2424         This family of accessor routines sets the value of a static field
2425         of an object.
2426
2427 *******************************************************************************/
2428
2429 #define JNI_SET_STATIC_FIELD(name, type, field)                \
2430 void _Jv_JNI_SetStatic##name##Field(JNIEnv *env, jclass clazz, \
2431                                                                         jfieldID fieldID,          \
2432                                                                         type value)                \
2433 {                                                              \
2434         classinfo *c;                                              \
2435         fieldinfo *f;                                              \
2436                                                                \
2437         STATISTICS(jniinvokation());                               \
2438                                                                \
2439         c = LLNI_classinfo_unwrap(clazz);                          \
2440         f = (fieldinfo *) fieldID;                                 \
2441                                                                \
2442         if (!(c->state & CLASS_INITIALIZED))                       \
2443                 if (!initialize_class(c))                              \
2444                         return;                                            \
2445                                                                \
2446         f->value->field = value;                                   \
2447 }
2448
2449 JNI_SET_STATIC_FIELD(Boolean, jboolean, i)
2450 JNI_SET_STATIC_FIELD(Byte,    jbyte,    i)
2451 JNI_SET_STATIC_FIELD(Char,    jchar,    i)
2452 JNI_SET_STATIC_FIELD(Short,   jshort,   i)
2453 JNI_SET_STATIC_FIELD(Int,     jint,     i)
2454 JNI_SET_STATIC_FIELD(Long,    jlong,    l)
2455 JNI_SET_STATIC_FIELD(Float,   jfloat,   f)
2456 JNI_SET_STATIC_FIELD(Double,  jdouble,  d)
2457
2458
2459 void _Jv_JNI_SetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldID,
2460                                                                   jobject value)
2461 {
2462         classinfo *c;
2463         fieldinfo *f;
2464
2465         STATISTICS(jniinvokation());
2466
2467         c = LLNI_classinfo_unwrap(clazz);
2468         f = (fieldinfo *) fieldID;
2469
2470         if (!(c->state & CLASS_INITIALIZED))
2471                 if (!initialize_class(c))
2472                         return;
2473
2474         f->value->a = LLNI_UNWRAP((java_handle_t *) value);
2475 }
2476
2477
2478 /* String Operations **********************************************************/
2479
2480 /* NewString *******************************************************************
2481
2482    Create new java.lang.String object from an array of Unicode
2483    characters.
2484
2485 *******************************************************************************/
2486
2487 jstring jni_NewString(JNIEnv *env, const jchar *buf, jsize len)
2488 {
2489         TRACEJNICALLS(("jni_NewString(env=%p, buf=%p, len=%d)", env, buf, len));
2490         
2491         java_handle_chararray_t* a = builtin_newarray_char(len);
2492
2493         if (a == NULL)
2494                 return NULL;
2495
2496         /* copy text */
2497         for (jsize i = 0; i < len; i++)
2498                 LLNI_array_direct(a, i) = buf[i];
2499
2500         java_handle_t* h = builtin_new(class_java_lang_String);
2501
2502         if (h == NULL)
2503                 return NULL;
2504
2505         java_lang_String s(h, a, len, 0);
2506
2507         return (jstring) jni_NewLocalRef(env, (jobject) s.get_handle());
2508 }
2509
2510
2511 static jchar emptyStringJ[]={0,0};
2512
2513 /* GetStringLength *************************************************************
2514
2515    Returns the length (the count of Unicode characters) of a Java
2516    string.
2517
2518 *******************************************************************************/
2519
2520 jsize jni_GetStringLength(JNIEnv *env, jstring str)
2521 {
2522         TRACEJNICALLSENTER(("jni_GetStringLength(env=%p, str=%p)", env, str));
2523
2524         java_lang_String s(str);
2525         jsize count = s.get_count();
2526
2527         TRACEJNICALLSEXIT(("->%d)", count));
2528
2529         return count;
2530 }
2531
2532
2533 /* GetStringChars **************************************************************
2534
2535    Returns a pointer to the array of Unicode characters of the
2536    string. This pointer is valid until ReleaseStringChars() is called.
2537
2538 *******************************************************************************/
2539
2540 const jchar* jni_GetStringChars(JNIEnv *env, jstring str, jboolean *isCopy)
2541 {       
2542         u2      *stringbuffer;
2543         int32_t  i;
2544
2545         TRACEJNICALLS(("jni_GetStringChars(env=%p, str=%p, isCopy=%p)", env, str, isCopy));
2546
2547         if (str == NULL)
2548                 // FIXME This is really ugly.
2549                 return emptyStringJ;
2550
2551         java_lang_String s(str);
2552
2553         java_handle_chararray_t* ca     = s.get_value();
2554         int32_t                  count  = s.get_count();
2555         int32_t                  offset = s.get_offset();
2556         
2557         if (ca == NULL)
2558                 return NULL;
2559
2560         /* allocate memory */
2561
2562         stringbuffer = MNEW(u2, count + 1);
2563
2564         /* copy text */
2565
2566         for (i = 0; i < count; i++)
2567                 stringbuffer[i] = LLNI_array_direct(ca, offset + i);
2568         
2569         /* terminate string */
2570
2571         stringbuffer[i] = '\0';
2572
2573         if (isCopy)
2574                 *isCopy = JNI_TRUE;
2575
2576         return (jchar*) stringbuffer;
2577 }
2578
2579
2580 /* ReleaseStringChars **********************************************************
2581
2582    Informs the VM that the native code no longer needs access to
2583    chars. The chars argument is a pointer obtained from string using
2584    GetStringChars().
2585
2586 *******************************************************************************/
2587
2588 void _Jv_JNI_ReleaseStringChars(JNIEnv *env, jstring str, const jchar *chars)
2589 {
2590         TRACEJNICALLS(("jni_ReleaseStringChars(env=%p, str=%p, chars=%p)", env, str, chars));
2591
2592         // FIXME
2593         if (chars == emptyStringJ)
2594                 return;
2595
2596         java_lang_String s(str);
2597         int32_t count = s.get_count();
2598
2599         MFREE(((jchar*) chars), jchar, count + 1);
2600 }
2601
2602
2603 /* NewStringUTF ****************************************************************
2604
2605    Constructs a new java.lang.String object from an array of UTF-8
2606    characters.
2607
2608 *******************************************************************************/
2609
2610 jstring jni_NewStringUTF(JNIEnv *env, const char *bytes)
2611 {
2612         TRACEJNICALLS(("jni_NewStringUTF(env=%p, bytes=%s)", env, bytes));
2613
2614         java_handle_t *h = javastring_safe_new_from_utf8(bytes);
2615
2616     return (jstring) jni_NewLocalRef(env, (jobject) h);
2617 }
2618
2619
2620 /****************** returns the utf8 length in bytes of a string *******************/
2621
2622 jsize jni_GetStringUTFLength(JNIEnv *env, jstring string)
2623 {   
2624         TRACEJNICALLS(("jni_GetStringUTFLength(env=%p, string=%p)", env, string));
2625
2626         java_lang_String s(string);
2627         java_handle_chararray_t* ca     = s.get_value();
2628         int32_t                  count  = s.get_count();
2629
2630         // FIXME GC critical section!
2631         int32_t length = u2_utflength(ca->data, count);
2632
2633         return length;
2634 }
2635
2636
2637 /* GetStringUTFChars ***********************************************************
2638
2639    Returns a pointer to an array of UTF-8 characters of the
2640    string. This array is valid until it is released by
2641    ReleaseStringUTFChars().
2642
2643 *******************************************************************************/
2644
2645 const char *_Jv_JNI_GetStringUTFChars(JNIEnv *env, jstring string,
2646                                                                           jboolean *isCopy)
2647 {
2648         utf *u;
2649
2650         STATISTICS(jniinvokation());
2651
2652         if (string == NULL)
2653                 return "";
2654
2655         if (isCopy)
2656                 *isCopy = JNI_TRUE;
2657         
2658         u = javastring_toutf((java_handle_t *) string, false);
2659
2660         if (u != NULL)
2661                 return u->text;
2662
2663         return "";
2664 }
2665
2666
2667 /* ReleaseStringUTFChars *******************************************************
2668
2669    Informs the VM that the native code no longer needs access to
2670    utf. The utf argument is a pointer derived from string using
2671    GetStringUTFChars().
2672
2673 *******************************************************************************/
2674
2675 void _Jv_JNI_ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *utf)
2676 {
2677         STATISTICS(jniinvokation());
2678
2679     /* XXX we don't release utf chars right now, perhaps that should be done 
2680            later. Since there is always one reference the garbage collector will
2681            never get them */
2682 }
2683
2684
2685 /* Array Operations ***********************************************************/
2686
2687 /* GetArrayLength **************************************************************
2688
2689    Returns the number of elements in the array.
2690
2691 *******************************************************************************/
2692
2693 jsize _Jv_JNI_GetArrayLength(JNIEnv *env, jarray array)
2694 {
2695         java_handle_t *a;
2696         jsize          size;
2697
2698         TRACEJNICALLS(("_Jv_JNI_GetArrayLength(env=%p, array=%p)", env, array));
2699
2700         a = (java_handle_t *) array;
2701
2702         size = LLNI_array_size(a);
2703
2704         return size;
2705 }
2706
2707
2708 /* NewObjectArray **************************************************************
2709
2710    Constructs a new array holding objects in class elementClass. All
2711    elements are initially set to initialElement.
2712
2713 *******************************************************************************/
2714
2715 jobjectArray _Jv_JNI_NewObjectArray(JNIEnv *env, jsize length,
2716                                                                         jclass elementClass, jobject initialElement)
2717 {
2718         classinfo                 *c;
2719         java_handle_t             *o;
2720         java_handle_objectarray_t *oa;
2721         s4                         i;
2722
2723         STATISTICS(jniinvokation());
2724
2725         c = LLNI_classinfo_unwrap(elementClass);
2726         o = (java_handle_t *) initialElement;
2727
2728         if (length < 0) {
2729                 exceptions_throw_negativearraysizeexception();
2730                 return NULL;
2731         }
2732
2733     oa = builtin_anewarray(length, c);
2734
2735         if (oa == NULL)
2736                 return NULL;
2737
2738         /* set all elements to initialElement */
2739
2740         for (i = 0; i < length; i++)
2741                 array_objectarray_element_set(oa, i, o);
2742
2743         return (jobjectArray) jni_NewLocalRef(env, (jobject) oa);
2744 }
2745
2746
2747 jobject _Jv_JNI_GetObjectArrayElement(JNIEnv *env, jobjectArray array,
2748                                                                           jsize index)
2749 {
2750         java_handle_objectarray_t *oa;
2751         java_handle_t             *o;
2752
2753         STATISTICS(jniinvokation());
2754
2755         oa = (java_handle_objectarray_t *) array;
2756
2757         if (index >= LLNI_array_size(oa)) {
2758                 exceptions_throw_arrayindexoutofboundsexception();
2759                 return NULL;
2760         }
2761
2762         o = array_objectarray_element_get(oa, index);
2763
2764         return jni_NewLocalRef(env, (jobject) o);
2765 }
2766
2767
2768 void _Jv_JNI_SetObjectArrayElement(JNIEnv *env, jobjectArray array,
2769                                                                    jsize index, jobject val)
2770 {
2771         java_handle_objectarray_t *oa;
2772         java_handle_t             *o;
2773
2774         STATISTICS(jniinvokation());
2775
2776         oa = (java_handle_objectarray_t *) array;
2777         o  = (java_handle_t *) val;
2778
2779         if (index >= LLNI_array_size(oa)) {
2780                 exceptions_throw_arrayindexoutofboundsexception();
2781                 return;
2782         }
2783
2784         /* check if the class of value is a subclass of the element class
2785            of the array */
2786
2787         if (!builtin_canstore(oa, o))
2788                 return;
2789
2790         array_objectarray_element_set(oa, index, o);
2791 }
2792
2793
2794 #define JNI_NEW_ARRAY(name, type, intern)                \
2795 type _Jv_JNI_New##name##Array(JNIEnv *env, jsize len)    \
2796 {                                                        \
2797         java_handle_##intern##array_t *a;                    \
2798                                                          \
2799         STATISTICS(jniinvokation());                         \
2800                                                          \
2801         if (len < 0) {                                       \
2802                 exceptions_throw_negativearraysizeexception();   \
2803                 return NULL;                                     \
2804         }                                                    \
2805                                                          \
2806         a = builtin_newarray_##intern(len);                  \
2807                                                          \
2808         return (type) jni_NewLocalRef(env, (jobject) a); \
2809 }
2810
2811 JNI_NEW_ARRAY(Boolean, jbooleanArray, boolean)
2812 JNI_NEW_ARRAY(Byte,    jbyteArray,    byte)
2813 JNI_NEW_ARRAY(Char,    jcharArray,    char)
2814 JNI_NEW_ARRAY(Short,   jshortArray,   short)
2815 JNI_NEW_ARRAY(Int,     jintArray,     int)
2816 JNI_NEW_ARRAY(Long,    jlongArray,    long)
2817 JNI_NEW_ARRAY(Float,   jfloatArray,   float)
2818 JNI_NEW_ARRAY(Double,  jdoubleArray,  double)
2819
2820
2821 /* Get<PrimitiveType>ArrayElements *********************************************
2822
2823    A family of functions that returns the body of the primitive array.
2824
2825 *******************************************************************************/
2826
2827 #define JNI_GET_ARRAY_ELEMENTS(name, type, intern)                     \
2828 type *_Jv_JNI_Get##name##ArrayElements(JNIEnv *env, type##Array array, \
2829                                                                                  jboolean *isCopy)             \
2830 {                                                                      \
2831         java_handle_##intern##array_t *a;                                  \
2832                                                                        \
2833         TRACEJNICALLS(("_Jv_JNI_Get" STR(name) "ArrayElements(env=%p, array=%p, isCopy=%d)", env, array, isCopy)); \
2834                                                                        \
2835         a = (java_handle_##intern##array_t *) array;                       \
2836                                                                        \
2837         if (isCopy)                                                        \
2838                 *isCopy = JNI_FALSE;                                           \
2839                                                                        \
2840         return (type *) LLNI_array_data(a);                                \
2841 }
2842
2843 JNI_GET_ARRAY_ELEMENTS(Boolean, jboolean, boolean)
2844 JNI_GET_ARRAY_ELEMENTS(Byte,    jbyte,    byte)
2845 JNI_GET_ARRAY_ELEMENTS(Char,    jchar,    char)
2846 JNI_GET_ARRAY_ELEMENTS(Short,   jshort,   short)
2847 JNI_GET_ARRAY_ELEMENTS(Int,     jint,     int)
2848 JNI_GET_ARRAY_ELEMENTS(Long,    jlong,    long)
2849 JNI_GET_ARRAY_ELEMENTS(Float,   jfloat,   float)
2850 JNI_GET_ARRAY_ELEMENTS(Double,  jdouble,  double)
2851
2852
2853 /* Release<PrimitiveType>ArrayElements *****************************************
2854
2855    A family of functions that informs the VM that the native code no
2856    longer needs access to elems. The elems argument is a pointer
2857    derived from array using the corresponding
2858    Get<PrimitiveType>ArrayElements() function. If necessary, this
2859    function copies back all changes made to elems to the original
2860    array.
2861
2862 *******************************************************************************/
2863
2864 #define JNI_RELEASE_ARRAY_ELEMENTS(name, type, intern, intern2)            \
2865 void _Jv_JNI_Release##name##ArrayElements(JNIEnv *env, type##Array array,  \
2866                                                                                   type *elems, jint mode)          \
2867 {                                                                          \
2868         java_handle_##intern##array_t *a;                                      \
2869                                                                            \
2870         STATISTICS(jniinvokation());                                           \
2871                                                                            \
2872         a = (java_handle_##intern##array_t *) array;                           \
2873                                                                            \
2874         if (elems != (type *) LLNI_array_data(a)) {                            \
2875                 switch (mode) {                                                    \
2876                 case JNI_COMMIT:                                                   \
2877                         MCOPY(LLNI_array_data(a), elems, intern2, LLNI_array_size(a)); \
2878                         break;                                                         \
2879                 case 0:                                                            \
2880                         MCOPY(LLNI_array_data(a), elems, intern2, LLNI_array_size(a)); \
2881                         /* XXX TWISTI how should it be freed? */                       \
2882                         break;                                                         \
2883                 case JNI_ABORT:                                                    \
2884                         /* XXX TWISTI how should it be freed? */                       \
2885                         break;                                                         \
2886                 }                                                                  \
2887         }                                                                      \
2888 }
2889
2890 JNI_RELEASE_ARRAY_ELEMENTS(Boolean, jboolean, boolean, u1)
2891 JNI_RELEASE_ARRAY_ELEMENTS(Byte,    jbyte,    byte,    s1)
2892 JNI_RELEASE_ARRAY_ELEMENTS(Char,    jchar,    char,    u2)
2893 JNI_RELEASE_ARRAY_ELEMENTS(Short,   jshort,   short,   s2)
2894 JNI_RELEASE_ARRAY_ELEMENTS(Int,     jint,     int,     s4)
2895 JNI_RELEASE_ARRAY_ELEMENTS(Long,    jlong,    long,    s8)
2896 JNI_RELEASE_ARRAY_ELEMENTS(Float,   jfloat,   float,   float)
2897 JNI_RELEASE_ARRAY_ELEMENTS(Double,  jdouble,  double,  double)
2898
2899
2900 /*  Get<PrimitiveType>ArrayRegion **********************************************
2901
2902         A family of functions that copies a region of a primitive array
2903         into a buffer.
2904
2905 *******************************************************************************/
2906
2907 #define JNI_GET_ARRAY_REGION(name, type, intern, intern2)               \
2908 void _Jv_JNI_Get##name##ArrayRegion(JNIEnv *env, type##Array array,     \
2909                                                                         jsize start, jsize len, type *buf)  \
2910 {                                                                       \
2911         java_handle_##intern##array_t *a;                                   \
2912                                                                         \
2913         TRACEJNICALLS(("_Jv_JNI_Get" STR(name) "ArrayRegion(env=%p, array=%p, start=%d, len=%d, buf=%p)", env, array, start, len, buf)); \
2914                                                                         \
2915         a = (java_handle_##intern##array_t *) array;                        \
2916                                                                         \
2917         if ((start < 0) || (len < 0) || (start + len > LLNI_array_size(a))) \
2918                 exceptions_throw_arrayindexoutofboundsexception();              \
2919         else                                                                \
2920                 MCOPY(buf, &LLNI_array_direct(a, start), intern2, len);         \
2921 }
2922
2923 JNI_GET_ARRAY_REGION(Boolean, jboolean, boolean, u1)
2924 JNI_GET_ARRAY_REGION(Byte,    jbyte,    byte,    s1)
2925 JNI_GET_ARRAY_REGION(Char,    jchar,    char,    u2)
2926 JNI_GET_ARRAY_REGION(Short,   jshort,   short,   s2)
2927 JNI_GET_ARRAY_REGION(Int,     jint,     int,     s4)
2928 JNI_GET_ARRAY_REGION(Long,    jlong,    long,    s8)
2929 JNI_GET_ARRAY_REGION(Float,   jfloat,   float,   float)
2930 JNI_GET_ARRAY_REGION(Double,  jdouble,  double,  double)
2931
2932
2933 /*  Set<PrimitiveType>ArrayRegion **********************************************
2934
2935         A family of functions that copies back a region of a primitive
2936         array from a buffer.
2937
2938 *******************************************************************************/
2939
2940 #define JNI_SET_ARRAY_REGION(name, type, intern, intern2)                    \
2941 void _Jv_JNI_Set##name##ArrayRegion(JNIEnv *env, type##Array array,          \
2942                                                                         jsize start, jsize len, const type *buf) \
2943 {                                                                            \
2944         java_handle_##intern##array_t *a;                                        \
2945                                                                              \
2946         STATISTICS(jniinvokation());                                             \
2947                                                                              \
2948         a = (java_handle_##intern##array_t *) array;                             \
2949                                                                              \
2950         if ((start < 0) || (len < 0) || (start + len > LLNI_array_size(a)))      \
2951                 exceptions_throw_arrayindexoutofboundsexception();                   \
2952         else                                                                     \
2953                 MCOPY(&LLNI_array_direct(a, start), buf, intern2, len);              \
2954 }
2955
2956 JNI_SET_ARRAY_REGION(Boolean, jboolean, boolean, u1)
2957 JNI_SET_ARRAY_REGION(Byte,    jbyte,    byte,    s1)
2958 JNI_SET_ARRAY_REGION(Char,    jchar,    char,    u2)
2959 JNI_SET_ARRAY_REGION(Short,   jshort,   short,   s2)
2960 JNI_SET_ARRAY_REGION(Int,     jint,     int,     s4)
2961 JNI_SET_ARRAY_REGION(Long,    jlong,    long,    s8)
2962 JNI_SET_ARRAY_REGION(Float,   jfloat,   float,   float)
2963 JNI_SET_ARRAY_REGION(Double,  jdouble,  double,  double)
2964
2965
2966 /* Registering Native Methods *************************************************/
2967
2968 /* RegisterNatives *************************************************************
2969
2970    Registers native methods with the class specified by the clazz
2971    argument. The methods parameter specifies an array of
2972    JNINativeMethod structures that contain the names, signatures, and
2973    function pointers of the native methods. The nMethods parameter
2974    specifies the number of native methods in the array.
2975
2976 *******************************************************************************/
2977
2978 jint _Jv_JNI_RegisterNatives(JNIEnv *env, jclass clazz,
2979                                                          const JNINativeMethod *methods, jint nMethods)
2980 {
2981         classinfo *c;
2982
2983         STATISTICS(jniinvokation());
2984
2985         c = LLNI_classinfo_unwrap(clazz);
2986
2987         /* XXX: if implemented this needs a call to jvmti_NativeMethodBind
2988         if (jvmti) jvmti_NativeMethodBind(method, address,  new_address_ptr);
2989         */
2990
2991         native_method_register(c->name, methods, nMethods);
2992
2993     return 0;
2994 }
2995
2996
2997 /* UnregisterNatives ***********************************************************
2998
2999    Unregisters native methods of a class. The class goes back to the
3000    state before it was linked or registered with its native method
3001    functions.
3002
3003    This function should not be used in normal native code. Instead, it
3004    provides special programs a way to reload and relink native
3005    libraries.
3006
3007 *******************************************************************************/
3008
3009 jint _Jv_JNI_UnregisterNatives(JNIEnv *env, jclass clazz)
3010 {
3011         STATISTICS(jniinvokation());
3012
3013         /* XXX TWISTI hmm, maybe we should not support that (like kaffe) */
3014
3015     log_text("JNI-Call: UnregisterNatives: IMPLEMENT ME!!!");
3016
3017     return 0;
3018 }
3019
3020
3021 /* Monitor Operations *********************************************************/
3022
3023 /* MonitorEnter ****************************************************************
3024
3025    Enters the monitor associated with the underlying Java object
3026    referred to by obj.
3027
3028 *******************************************************************************/
3029
3030 jint _Jv_JNI_MonitorEnter(JNIEnv *env, jobject obj)
3031 {
3032         STATISTICS(jniinvokation());
3033
3034         if (obj == NULL) {
3035                 exceptions_throw_nullpointerexception();
3036                 return JNI_ERR;
3037         }
3038
3039         LOCK_MONITOR_ENTER(obj);
3040
3041         return JNI_OK;
3042 }
3043
3044
3045 /* MonitorExit *****************************************************************
3046
3047    The current thread must be the owner of the monitor associated with
3048    the underlying Java object referred to by obj. The thread
3049    decrements the counter indicating the number of times it has
3050    entered this monitor. If the value of the counter becomes zero, the
3051    current thread releases the monitor.
3052
3053 *******************************************************************************/
3054
3055 jint _Jv_JNI_MonitorExit(JNIEnv *env, jobject obj)
3056 {
3057         STATISTICS(jniinvokation());
3058
3059         if (obj == NULL) {
3060                 exceptions_throw_nullpointerexception();
3061                 return JNI_ERR;
3062         }
3063
3064         LOCK_MONITOR_EXIT(obj);
3065
3066         return JNI_OK;
3067 }
3068
3069
3070 /* JavaVM Interface ***********************************************************/
3071
3072 /* GetJavaVM *******************************************************************
3073
3074    Returns the Java VM interface (used in the Invocation API)
3075    associated with the current thread. The result is placed at the
3076    location pointed to by the second argument, vm.
3077
3078 *******************************************************************************/
3079
3080 jint _Jv_JNI_GetJavaVM(JNIEnv *env, JavaVM **javavm)
3081 {
3082         STATISTICS(jniinvokation());
3083
3084     *javavm = vm->get_javavm();
3085
3086         return 0;
3087 }
3088
3089
3090 /* GetStringRegion *************************************************************
3091
3092    Copies len number of Unicode characters beginning at offset start
3093    to the given buffer buf.
3094
3095    Throws StringIndexOutOfBoundsException on index overflow.
3096
3097 *******************************************************************************/
3098
3099 void jni_GetStringRegion(JNIEnv* env, jstring str, jsize start, jsize len, jchar *buf)
3100 {
3101         java_lang_String s(str);
3102         java_handle_chararray_t* ca    = s.get_value();
3103         int32_t                  count = s.get_count();
3104
3105         if ((start < 0) || (len < 0) || (start > count) || (start + len > count)) {
3106                 exceptions_throw_stringindexoutofboundsexception();
3107                 return;
3108         }
3109
3110         MCOPY(buf, &LLNI_array_direct(ca, start), u2, len);
3111 }
3112
3113
3114 /* GetStringUTFRegion **********************************************************
3115
3116     Translates len number of Unicode characters beginning at offset
3117     start into UTF-8 format and place the result in the given buffer
3118     buf.
3119
3120     Throws StringIndexOutOfBoundsException on index overflow. 
3121
3122 *******************************************************************************/
3123
3124 void jni_GetStringUTFRegion(JNIEnv* env, jstring str, jsize start, jsize len, char *buf)
3125 {
3126         TRACEJNICALLS(("jni_GetStringUTFRegion(env=%p, str=%p, start=%d, len=%d, buf=%p)", env, str, start, len, buf));
3127
3128         java_lang_String s(str);
3129         java_handle_chararray_t* ca     = s.get_value();
3130         int32_t                  count  = s.get_count();
3131         int32_t                  offset = s.get_offset();
3132
3133         if ((start < 0) || (len < 0) || (start > count) || (start + len > count)) {
3134                 exceptions_throw_stringindexoutofboundsexception();
3135                 return;
3136         }
3137
3138         int32_t i;
3139
3140         for (i = 0; i < len; i++)
3141                 buf[i] = LLNI_array_direct(ca, offset + start + i);
3142
3143         buf[i] = '\0';
3144 }
3145
3146
3147 /* GetPrimitiveArrayCritical ***************************************************
3148
3149    Obtain a direct pointer to array elements.
3150
3151    ATTENTION: Critical section keeps open when this function returns!
3152    See ReleasePrimitiveArrayCritical.
3153
3154 *******************************************************************************/
3155
3156 void* jni_GetPrimitiveArrayCritical(JNIEnv *env, jarray array, jboolean *isCopy)
3157 {
3158         java_handle_t*   h;
3159         java_array_t*    a;
3160         arraydescriptor* ad;
3161         void*            data;
3162
3163         TRACEJNICALLS(("jni_GetPrimitiveArrayCritical(env=%p, array=%p, isCopy=%d)", env, array, isCopy));
3164
3165         if (isCopy != NULL) {
3166                 *isCopy = JNI_FALSE;
3167         }
3168
3169         LLNI_CRITICAL_START;
3170
3171         h  = (java_handle_t*) array;
3172         a  = (java_array_t*) LLNI_UNWRAP(h);
3173         ad = a->objheader.vftbl->arraydesc;
3174
3175         /* Sanity check. */
3176
3177         assert(ad != NULL);
3178
3179         data = (void*) (((intptr_t) a) + ad->dataoffset);
3180
3181         return data;
3182 }
3183
3184
3185 /* ReleasePrimitiveArrayCritical ***********************************************
3186
3187    No specific documentation.
3188
3189    ATTENTION: This function closes the critical section opened in
3190    GetPrimitiveArrayCritical!
3191
3192 *******************************************************************************/
3193
3194 void jni_ReleasePrimitiveArrayCritical(JNIEnv *env, jarray array, void *carray, jint mode)
3195 {
3196         TRACEJNICALLS(("jni_ReleasePrimitiveArrayCritical(env=%p, array=%p, carray=%p, mode=%d)", env, array, carray, mode));
3197
3198         LLNI_CRITICAL_END;
3199 }
3200
3201
3202 /* GetStringCritical ***********************************************************
3203
3204    The semantics of these two functions are similar to the existing
3205    Get/ReleaseStringChars functions.
3206
3207 *******************************************************************************/
3208
3209 const jchar *_Jv_JNI_GetStringCritical(JNIEnv *env, jstring string,
3210                                                                            jboolean *isCopy)
3211 {
3212         STATISTICS(jniinvokation());
3213
3214         return jni_GetStringChars(env, string, isCopy);
3215 }
3216
3217
3218 void _Jv_JNI_ReleaseStringCritical(JNIEnv *env, jstring string,
3219                                                                    const jchar *cstring)
3220 {
3221         STATISTICS(jniinvokation());
3222
3223         _Jv_JNI_ReleaseStringChars(env, string, cstring);
3224 }
3225
3226
3227 jweak _Jv_JNI_NewWeakGlobalRef(JNIEnv* env, jobject obj)
3228 {
3229         TRACEJNICALLS(("_Jv_JNI_NewWeakGlobalRef(env=%p, obj=%p): IMPLEMENT ME!", env, obj));
3230
3231         return (jweak) obj;
3232 }
3233
3234
3235 void _Jv_JNI_DeleteWeakGlobalRef(JNIEnv* env, jweak ref)
3236 {
3237         TRACEJNICALLS(("_Jv_JNI_DeleteWeakGlobalRef(env=%p, ref=%p): IMPLEMENT ME", env, ref));
3238 }
3239
3240
3241 /* NewGlobalRef ****************************************************************
3242
3243    Creates a new global reference to the object referred to by the obj
3244    argument.
3245
3246 *******************************************************************************/
3247     
3248 jobject jni_NewGlobalRef(JNIEnv* env, jobject obj)
3249 {
3250         hashtable_global_ref_entry *gre;
3251         u4   key;                           /* hashkey                            */
3252         u4   slot;                          /* slot in hashtable                  */
3253         java_handle_t *o;
3254
3255         TRACEJNICALLS(("jni_NewGlobalRef(env=%p, obj=%p)", env, obj));
3256
3257         o = (java_handle_t *) obj;
3258
3259         LOCK_MONITOR_ENTER(hashtable_global_ref->header);
3260
3261         LLNI_CRITICAL_START;
3262
3263         /* normally addresses are aligned to 4, 8 or 16 bytes */
3264
3265         key  = heap_hashcode(LLNI_DIRECT(o)) >> 4; /* align to 16-byte boundaries */
3266         slot = key & (hashtable_global_ref->size - 1);
3267         gre  = (hashtable_global_ref_entry*) hashtable_global_ref->ptr[slot];
3268         
3269         /* search external hash chain for the entry */
3270
3271         while (gre) {
3272                 if (gre->o == LLNI_DIRECT(o)) {
3273                         /* global object found, increment the reference */
3274
3275                         gre->refs++;
3276
3277                         break;
3278                 }
3279
3280                 gre = gre->hashlink;                /* next element in external chain */
3281         }
3282
3283         LLNI_CRITICAL_END;
3284
3285         /* global ref not found, create a new one */
3286
3287         if (gre == NULL) {
3288                 gre = (hashtable_global_ref_entry*) heap_alloc_uncollectable(sizeof(hashtable_global_ref_entry));
3289
3290 #if defined(ENABLE_GC_CACAO)
3291                 /* register global ref with the GC */
3292
3293                 gc_reference_register(&(gre->o), GC_REFTYPE_JNI_GLOBALREF);
3294 #endif
3295
3296                 LLNI_CRITICAL_START;
3297
3298                 gre->o    = LLNI_DIRECT(o);
3299                 gre->refs = 1;
3300
3301                 LLNI_CRITICAL_END;
3302
3303                 /* insert entry into hashtable */
3304
3305                 gre->hashlink = (hashtable_global_ref_entry*) hashtable_global_ref->ptr[slot];
3306
3307                 hashtable_global_ref->ptr[slot] = gre;
3308
3309                 /* update number of hashtable-entries */
3310
3311                 hashtable_global_ref->entries++;
3312         }
3313
3314         LOCK_MONITOR_EXIT(hashtable_global_ref->header);
3315
3316 #if defined(ENABLE_HANDLES)
3317         return gre;
3318 #else
3319         return obj;
3320 #endif
3321 }
3322
3323
3324 /* DeleteGlobalRef *************************************************************
3325
3326    Deletes the global reference pointed to by globalRef.
3327
3328 *******************************************************************************/
3329
3330 void jni_DeleteGlobalRef(JNIEnv* env, jobject globalRef)
3331 {
3332         hashtable_global_ref_entry *gre;
3333         hashtable_global_ref_entry *prevgre;
3334         u4   key;                           /* hashkey                            */
3335         u4   slot;                          /* slot in hashtable                  */
3336         java_handle_t              *o;
3337
3338         TRACEJNICALLS(("jni_DeleteGlobalRef(env=%p, globalRef=%p)", env, globalRef));
3339
3340         o = (java_handle_t *) globalRef;
3341
3342         LOCK_MONITOR_ENTER(hashtable_global_ref->header);
3343
3344         LLNI_CRITICAL_START;
3345
3346         /* normally addresses are aligned to 4, 8 or 16 bytes */
3347
3348         key  = heap_hashcode(LLNI_DIRECT(o)) >> 4; /* align to 16-byte boundaries */
3349         slot = key & (hashtable_global_ref->size - 1);
3350         gre  = (hashtable_global_ref_entry*) hashtable_global_ref->ptr[slot];
3351
3352         /* initialize prevgre */
3353
3354         prevgre = NULL;
3355
3356         /* search external hash chain for the entry */
3357
3358         while (gre) {
3359                 if (gre->o == LLNI_DIRECT(o)) {
3360                         /* global object found, decrement the reference count */
3361
3362                         gre->refs--;
3363
3364                         /* if reference count is 0, remove the entry */
3365
3366                         if (gre->refs == 0) {
3367                                 /* special handling if it's the first in the chain */
3368
3369                                 if (prevgre == NULL)
3370                                         hashtable_global_ref->ptr[slot] = gre->hashlink;
3371                                 else
3372                                         prevgre->hashlink = gre->hashlink;
3373
3374 #if defined(ENABLE_GC_CACAO)
3375                                 /* unregister global ref with the GC */
3376
3377                                 gc_reference_unregister(&(gre->o));
3378 #endif
3379
3380                                 heap_free(gre);
3381                         }
3382
3383                         LLNI_CRITICAL_END;
3384
3385                         LOCK_MONITOR_EXIT(hashtable_global_ref->header);
3386
3387                         return;
3388                 }
3389
3390                 prevgre = gre;                    /* save current pointer for removal */
3391                 gre     = gre->hashlink;            /* next element in external chain */
3392         }
3393
3394         log_println("jni_DeleteGlobalRef: Global reference not found.");
3395
3396         LLNI_CRITICAL_END;
3397
3398         LOCK_MONITOR_EXIT(hashtable_global_ref->header);
3399 }
3400
3401
3402 /* ExceptionCheck **************************************************************
3403
3404    Returns JNI_TRUE when there is a pending exception; otherwise,
3405    returns JNI_FALSE.
3406
3407 *******************************************************************************/
3408
3409 jboolean _Jv_JNI_ExceptionCheck(JNIEnv *env)
3410 {
3411         java_handle_t *o;
3412
3413         STATISTICS(jniinvokation());
3414
3415         o = exceptions_get_exception();
3416
3417         return (o != NULL) ? JNI_TRUE : JNI_FALSE;
3418 }
3419
3420
3421 /* New JNI 1.4 functions ******************************************************/
3422
3423 /* NewDirectByteBuffer *********************************************************
3424
3425    Allocates and returns a direct java.nio.ByteBuffer referring to the
3426    block of memory starting at the memory address address and
3427    extending capacity bytes.
3428
3429 *******************************************************************************/
3430
3431 jobject jni_NewDirectByteBuffer(JNIEnv *env, void *address, jlong capacity)
3432 {
3433 #if defined(ENABLE_JAVASE)
3434 # if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
3435         TRACEJNICALLSENTER(("jni_NewDirectByteBuffer(env=%p, address=%p, capacity=%ld)", env, address, capacity));
3436
3437         // Allocate a gnu.classpath.Pointer{32,64} object.
3438
3439 # if SIZEOF_VOID_P == 8
3440         java_handle_t* h = builtin_new(class_gnu_classpath_Pointer64);
3441 # else
3442         java_handle_t* h = builtin_new(class_gnu_classpath_Pointer32);
3443 # endif
3444
3445         if (h == NULL)
3446                 return NULL;
3447
3448         gnu_classpath_Pointer p(h, address);
3449
3450         // Create a java.nio.DirectByteBufferImpl$ReadWrite object.
3451
3452         java_handle_t* nbuf =
3453                 (java_handle_t*) jni_NewObject(env, (jclass) class_java_nio_DirectByteBufferImpl_ReadWrite,
3454                                                                            (jmethodID) dbbirw_init, NULL, p.get_handle(),
3455                                                                            (jint) capacity, (jint) capacity, (jint) 0);
3456
3457         // Add a local reference and return the value.
3458
3459         TRACEJNICALLSEXIT(("->%p", nbuf));
3460
3461         return jni_NewLocalRef(env, (jobject) nbuf);
3462
3463 # elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
3464
3465         jobject o;
3466         int64_t addr;
3467         int32_t cap;
3468
3469         TRACEJNICALLSENTER(("jni_NewDirectByteBuffer(env=%p, address=%p, capacity=%ld)", env, address, capacity));
3470
3471         /* Be paranoid about address sign-extension. */
3472
3473         addr = (int64_t) ((uintptr_t) address);
3474         cap  = (int32_t) capacity;
3475
3476         o = jni_NewObject(env, (jclass) class_java_nio_DirectByteBuffer,
3477                                           (jmethodID) dbb_init, addr, cap);
3478
3479         /* Add local reference and return the value. */
3480
3481         TRACEJNICALLSEXIT(("->%p", o));
3482
3483         return jni_NewLocalRef(env, o);
3484
3485 # else
3486 #  error unknown classpath configuration
3487 # endif
3488
3489 #else
3490         vm_abort("jni_NewDirectByteBuffer: Not implemented in this configuration.");
3491
3492         /* keep compiler happy */
3493
3494         return NULL;
3495 #endif
3496 }
3497
3498
3499 /* GetDirectBufferAddress ******************************************************
3500
3501    Fetches and returns the starting address of the memory region
3502    referenced by the given direct java.nio.Buffer.
3503
3504 *******************************************************************************/
3505
3506 void* jni_GetDirectBufferAddress(JNIEnv *env, jobject buf)
3507 {
3508 #if defined(ENABLE_JAVASE)
3509 # if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
3510
3511         TRACEJNICALLSENTER(("jni_GetDirectBufferAddress(env=%p, buf=%p)", env, buf));
3512
3513         /* Prevent compiler warning. */
3514
3515         java_handle_t* h = (java_handle_t *) buf;
3516
3517         if ((h != NULL) && !builtin_instanceof(h, class_java_nio_Buffer))
3518                 return NULL;
3519
3520         java_nio_DirectByteBufferImpl dbb(buf);
3521         java_handle_t* address = dbb.get_address();
3522
3523         if (address == NULL) {
3524                 TRACEJNICALLSEXIT(("->%p", NULL));
3525                 return NULL;
3526         }
3527
3528         gnu_classpath_Pointer p(address);
3529         void* data = p.get_data();
3530
3531         TRACEJNICALLSEXIT(("->%p", data));
3532
3533         return data;
3534
3535 # elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
3536
3537         TRACEJNICALLS(("jni_GetDirectBufferAddress(env=%p, buf=%p)", env, buf));
3538
3539         java_nio_Buffer jnb(buf);
3540
3541         if (jnb.is_non_null() && !builtin_instanceof(jnb.get_handle(), class_sun_nio_ch_DirectBuffer))
3542                 return NULL;
3543
3544         void* address = jnb.get_address();
3545
3546         return address;
3547
3548 # else
3549 #  error unknown classpath configuration
3550 # endif
3551
3552 #else
3553
3554         vm_abort("jni_GetDirectBufferAddress: Not implemented in this configuration.");
3555
3556         // Keep compiler happy.
3557         return NULL;
3558
3559 #endif
3560 }
3561
3562
3563 /* GetDirectBufferCapacity *****************************************************
3564
3565    Fetches and returns the capacity in bytes of the memory region
3566    referenced by the given direct java.nio.Buffer.
3567
3568 *******************************************************************************/
3569
3570 jlong jni_GetDirectBufferCapacity(JNIEnv* env, jobject buf)
3571 {
3572 #if defined(ENABLE_JAVASE) && defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
3573         TRACEJNICALLS(("jni_GetDirectBufferCapacity(env=%p, buf=%p)", env, buf));
3574
3575         java_handle_t* h = (java_handle_t *) buf;
3576
3577         if (!builtin_instanceof(h, class_java_nio_DirectByteBufferImpl))
3578                 return -1;
3579
3580         java_nio_Buffer b(h);
3581         jlong capacity = b.get_cap();
3582
3583         return capacity;
3584 #else
3585         vm_abort("jni_GetDirectBufferCapacity: not implemented in this configuration");
3586
3587         // Keep compiler happy.
3588
3589         return 0;
3590 #endif
3591 }
3592
3593
3594 /* GetObjectRefType ************************************************************
3595
3596    Returns the type of the object referred to by the obj argument. The
3597    argument obj can either be a local, global or weak global
3598    reference.
3599
3600 *******************************************************************************/
3601
3602 jobjectRefType jni_GetObjectRefType(JNIEnv *env, jobject obj)
3603 {
3604         log_println("jni_GetObjectRefType: IMPLEMENT ME!");
3605
3606         return (jobjectRefType) NULL;
3607 }
3608
3609
3610 /* DestroyJavaVM ***************************************************************
3611
3612    Unloads a Java VM and reclaims its resources. Only the main thread
3613    can unload the VM. The system waits until the main thread is only
3614    remaining user thread before it destroys the VM.
3615
3616 *******************************************************************************/
3617
3618 jint _Jv_JNI_DestroyJavaVM(JavaVM *javavm)
3619 {
3620         int status;
3621
3622         TRACEJNICALLS(("_Jv_JNI_DestroyJavaVM(javavm=%p)", javavm));
3623
3624         if (vm->is_created() == false)
3625                 return JNI_ERR;
3626
3627     status = vm_destroy(javavm);
3628
3629         return status;
3630 }
3631
3632
3633 /* AttachCurrentThread *********************************************************
3634
3635    Attaches the current thread to a Java VM. Returns a JNI interface
3636    pointer in the JNIEnv argument.
3637
3638    Trying to attach a thread that is already attached is a no-op.
3639
3640    A native thread cannot be attached simultaneously to two Java VMs.
3641
3642    When a thread is attached to the VM, the context class loader is
3643    the bootstrap loader.
3644
3645 *******************************************************************************/
3646
3647 static int jni_attach_current_thread(void **p_env, void *thr_args, bool isdaemon)
3648 {
3649 #if defined(ENABLE_THREADS)
3650         JavaVMAttachArgs *vm_aargs;
3651         bool              result;
3652
3653     /* If the current thread has already been attached, this operation
3654            is a no-op. */
3655
3656         result = thread_current_is_attached();
3657
3658         if (result == true) {
3659                 *p_env = vm->get_jnienv();
3660                 return JNI_OK;
3661         }
3662
3663         vm_aargs = (JavaVMAttachArgs *) thr_args;
3664
3665         if (vm_aargs != NULL) {
3666                 if ((vm_aargs->version != JNI_VERSION_1_2) &&
3667                         (vm_aargs->version != JNI_VERSION_1_4))
3668                         return JNI_EVERSION;
3669         }
3670
3671         if (!thread_attach_current_external_thread(vm_aargs, false))
3672                 return JNI_ERR;
3673
3674         if (!localref_table_init())
3675                 return JNI_ERR;
3676 #endif
3677
3678         *p_env = vm->get_jnienv();
3679
3680         return JNI_OK;
3681 }
3682
3683
3684 jint jni_AttachCurrentThread(JavaVM *javavm, void **p_env, void *thr_args)
3685 {
3686         int result;
3687
3688         TRACEJNICALLS(("jni_AttachCurrentThread(javavm=%p, p_env=%p, thr_args=%p)", javavm, p_env, thr_args));
3689
3690         if (vm->is_created() == false)
3691                 return JNI_ERR;
3692
3693         result = jni_attach_current_thread(p_env, thr_args, false);
3694
3695         return result;
3696 }
3697
3698
3699 /* DetachCurrentThread *********************************************************
3700
3701    Detaches the current thread from a Java VM. All Java monitors held
3702    by this thread are released. All Java threads waiting for this
3703    thread to die are notified.
3704
3705    In JDK 1.1, the main thread cannot be detached from the VM. It must
3706    call DestroyJavaVM to unload the entire VM.
3707
3708    In the JDK, the main thread can be detached from the VM.
3709
3710    The main thread, which is the thread that created the Java VM,
3711    cannot be detached from the VM. Instead, the main thread must call
3712    JNI_DestroyJavaVM() to unload the entire VM.
3713
3714 *******************************************************************************/
3715
3716 jint jni_DetachCurrentThread(JavaVM *vm)
3717 {
3718 #if defined(ENABLE_THREADS)
3719         bool result;
3720
3721         TRACEJNICALLS(("jni_DetachCurrentThread(vm=%p)", vm));
3722
3723     /* If the current thread has already been detached, this operation
3724            is a no-op. */
3725
3726         result = thread_current_is_attached();
3727
3728         if (result == false)
3729                 return true;
3730
3731         /* We need to pop all frames before we can destroy the table. */
3732
3733         localref_frame_pop_all();
3734
3735         if (!localref_table_destroy())
3736                 return JNI_ERR;
3737
3738         if (!thread_detach_current_external_thread())
3739                 return JNI_ERR;
3740 #endif
3741
3742         return JNI_OK;
3743 }
3744
3745
3746 /* GetEnv **********************************************************************
3747
3748    If the current thread is not attached to the VM, sets *env to NULL,
3749    and returns JNI_EDETACHED. If the specified version is not
3750    supported, sets *env to NULL, and returns JNI_EVERSION. Otherwise,
3751    sets *env to the appropriate interface, and returns JNI_OK.
3752
3753 *******************************************************************************/
3754
3755 jint jni_GetEnv(JavaVM *javavm, void **env, jint version)
3756 {
3757         TRACEJNICALLS(("jni_GetEnv(javavm=%p, env=%p, version=%d)", javavm, env, version));
3758
3759         if (vm->is_created() == false) {
3760                 *env = NULL;
3761                 return JNI_EDETACHED;
3762         }
3763
3764 #if defined(ENABLE_THREADS)
3765         if (thread_get_current() == NULL) {
3766                 *env = NULL;
3767
3768                 return JNI_EDETACHED;
3769         }
3770 #endif
3771
3772         /* Check the JNI version. */
3773
3774         if (jni_version_check(version) == true) {
3775                 *env = vm->get_jnienv();
3776                 return JNI_OK;
3777         }
3778
3779 #if defined(ENABLE_JVMTI)
3780         if ((version & JVMTI_VERSION_MASK_INTERFACE_TYPE) 
3781                 == JVMTI_VERSION_INTERFACE_JVMTI) {
3782
3783                 *env = (void *) jvmti_new_environment();
3784
3785                 if (env != NULL)
3786                         return JNI_OK;
3787         }
3788 #endif
3789         
3790         *env = NULL;
3791
3792         return JNI_EVERSION;
3793 }
3794
3795
3796 /* AttachCurrentThreadAsDaemon *************************************************
3797
3798    Same semantics as AttachCurrentThread, but the newly-created
3799    java.lang.Thread instance is a daemon.
3800
3801    If the thread has already been attached via either
3802    AttachCurrentThread or AttachCurrentThreadAsDaemon, this routine
3803    simply sets the value pointed to by penv to the JNIEnv of the
3804    current thread. In this case neither AttachCurrentThread nor this
3805    routine have any effect on the daemon status of the thread.
3806
3807 *******************************************************************************/
3808
3809 jint jni_AttachCurrentThreadAsDaemon(JavaVM *javavm, void **penv, void *args)
3810 {
3811         int result;
3812
3813         TRACEJNICALLS(("jni_AttachCurrentThreadAsDaemon(javavm=%p, penv=%p, args=%p)", javavm, penv, args));
3814
3815         if (vm->is_created() == false)
3816                 return JNI_ERR;
3817
3818         result = jni_attach_current_thread(penv, args, true);
3819
3820         return result;
3821 }
3822
3823
3824 /* JNI invocation table *******************************************************/
3825
3826 const struct JNIInvokeInterface_ _Jv_JNIInvokeInterface = {
3827         NULL,
3828         NULL,
3829         NULL,
3830
3831         _Jv_JNI_DestroyJavaVM,
3832         jni_AttachCurrentThread,
3833         jni_DetachCurrentThread,
3834         jni_GetEnv,
3835         jni_AttachCurrentThreadAsDaemon
3836 };
3837
3838
3839 /* JNI function table *********************************************************/
3840
3841 struct JNINativeInterface_ _Jv_JNINativeInterface = {
3842         NULL,
3843         NULL,
3844         NULL,
3845         NULL,    
3846         _Jv_JNI_GetVersion,
3847
3848         jni_DefineClass,
3849         jni_FindClass,
3850         jni_FromReflectedMethod,
3851         jni_FromReflectedField,
3852         jni_ToReflectedMethod,
3853         jni_GetSuperclass,
3854         _Jv_JNI_IsAssignableFrom,
3855         _Jv_JNI_ToReflectedField,
3856
3857         _Jv_JNI_Throw,
3858         _Jv_JNI_ThrowNew,
3859         _Jv_JNI_ExceptionOccurred,
3860         jni_ExceptionDescribe,
3861         jni_ExceptionClear,
3862         _Jv_JNI_FatalError,
3863         jni_PushLocalFrame,
3864         jni_PopLocalFrame,
3865
3866         jni_NewGlobalRef,
3867         jni_DeleteGlobalRef,
3868         jni_DeleteLocalRef,
3869         _Jv_JNI_IsSameObject,
3870         jni_NewLocalRef,
3871         jni_EnsureLocalCapacity,
3872
3873         _Jv_JNI_AllocObject,
3874         jni_NewObject,
3875         _Jv_JNI_NewObjectV,
3876         _Jv_JNI_NewObjectA,
3877
3878         jni_GetObjectClass,
3879         _Jv_JNI_IsInstanceOf,
3880
3881         _Jv_JNI_GetMethodID,
3882
3883         _Jv_JNI_CallObjectMethod,
3884         _Jv_JNI_CallObjectMethodV,
3885         _Jv_JNI_CallObjectMethodA,
3886         _Jv_JNI_CallBooleanMethod,
3887         _Jv_JNI_CallBooleanMethodV,
3888         _Jv_JNI_CallBooleanMethodA,
3889         _Jv_JNI_CallByteMethod,
3890         _Jv_JNI_CallByteMethodV,
3891         _Jv_JNI_CallByteMethodA,
3892         _Jv_JNI_CallCharMethod,
3893         _Jv_JNI_CallCharMethodV,
3894         _Jv_JNI_CallCharMethodA,
3895         _Jv_JNI_CallShortMethod,
3896         _Jv_JNI_CallShortMethodV,
3897         _Jv_JNI_CallShortMethodA,
3898         _Jv_JNI_CallIntMethod,
3899         _Jv_JNI_CallIntMethodV,
3900         _Jv_JNI_CallIntMethodA,
3901         _Jv_JNI_CallLongMethod,
3902         _Jv_JNI_CallLongMethodV,
3903         _Jv_JNI_CallLongMethodA,
3904         _Jv_JNI_CallFloatMethod,
3905         _Jv_JNI_CallFloatMethodV,
3906         _Jv_JNI_CallFloatMethodA,
3907         _Jv_JNI_CallDoubleMethod,
3908         _Jv_JNI_CallDoubleMethodV,
3909         _Jv_JNI_CallDoubleMethodA,
3910         _Jv_JNI_CallVoidMethod,
3911         _Jv_JNI_CallVoidMethodV,
3912         _Jv_JNI_CallVoidMethodA,
3913
3914         _Jv_JNI_CallNonvirtualObjectMethod,
3915         _Jv_JNI_CallNonvirtualObjectMethodV,
3916         _Jv_JNI_CallNonvirtualObjectMethodA,
3917         _Jv_JNI_CallNonvirtualBooleanMethod,
3918         _Jv_JNI_CallNonvirtualBooleanMethodV,
3919         _Jv_JNI_CallNonvirtualBooleanMethodA,
3920         _Jv_JNI_CallNonvirtualByteMethod,
3921         _Jv_JNI_CallNonvirtualByteMethodV,
3922         _Jv_JNI_CallNonvirtualByteMethodA,
3923         _Jv_JNI_CallNonvirtualCharMethod,
3924         _Jv_JNI_CallNonvirtualCharMethodV,
3925         _Jv_JNI_CallNonvirtualCharMethodA,
3926         _Jv_JNI_CallNonvirtualShortMethod,
3927         _Jv_JNI_CallNonvirtualShortMethodV,
3928         _Jv_JNI_CallNonvirtualShortMethodA,
3929         _Jv_JNI_CallNonvirtualIntMethod,
3930         _Jv_JNI_CallNonvirtualIntMethodV,
3931         _Jv_JNI_CallNonvirtualIntMethodA,
3932         _Jv_JNI_CallNonvirtualLongMethod,
3933         _Jv_JNI_CallNonvirtualLongMethodV,
3934         _Jv_JNI_CallNonvirtualLongMethodA,
3935         _Jv_JNI_CallNonvirtualFloatMethod,
3936         _Jv_JNI_CallNonvirtualFloatMethodV,
3937         _Jv_JNI_CallNonvirtualFloatMethodA,
3938         _Jv_JNI_CallNonvirtualDoubleMethod,
3939         _Jv_JNI_CallNonvirtualDoubleMethodV,
3940         _Jv_JNI_CallNonvirtualDoubleMethodA,
3941         _Jv_JNI_CallNonvirtualVoidMethod,
3942         _Jv_JNI_CallNonvirtualVoidMethodV,
3943         _Jv_JNI_CallNonvirtualVoidMethodA,
3944
3945         _Jv_JNI_GetFieldID,
3946
3947         _Jv_JNI_GetObjectField,
3948         _Jv_JNI_GetBooleanField,
3949         _Jv_JNI_GetByteField,
3950         _Jv_JNI_GetCharField,
3951         _Jv_JNI_GetShortField,
3952         _Jv_JNI_GetIntField,
3953         _Jv_JNI_GetLongField,
3954         _Jv_JNI_GetFloatField,
3955         _Jv_JNI_GetDoubleField,
3956         _Jv_JNI_SetObjectField,
3957         _Jv_JNI_SetBooleanField,
3958         _Jv_JNI_SetByteField,
3959         _Jv_JNI_SetCharField,
3960         _Jv_JNI_SetShortField,
3961         _Jv_JNI_SetIntField,
3962         _Jv_JNI_SetLongField,
3963         _Jv_JNI_SetFloatField,
3964         _Jv_JNI_SetDoubleField,
3965
3966         _Jv_JNI_GetStaticMethodID,
3967
3968         _Jv_JNI_CallStaticObjectMethod,
3969         _Jv_JNI_CallStaticObjectMethodV,
3970         _Jv_JNI_CallStaticObjectMethodA,
3971         _Jv_JNI_CallStaticBooleanMethod,
3972         _Jv_JNI_CallStaticBooleanMethodV,
3973         _Jv_JNI_CallStaticBooleanMethodA,
3974         _Jv_JNI_CallStaticByteMethod,
3975         _Jv_JNI_CallStaticByteMethodV,
3976         _Jv_JNI_CallStaticByteMethodA,
3977         _Jv_JNI_CallStaticCharMethod,
3978         _Jv_JNI_CallStaticCharMethodV,
3979         _Jv_JNI_CallStaticCharMethodA,
3980         _Jv_JNI_CallStaticShortMethod,
3981         _Jv_JNI_CallStaticShortMethodV,
3982         _Jv_JNI_CallStaticShortMethodA,
3983         _Jv_JNI_CallStaticIntMethod,
3984         _Jv_JNI_CallStaticIntMethodV,
3985         _Jv_JNI_CallStaticIntMethodA,
3986         _Jv_JNI_CallStaticLongMethod,
3987         _Jv_JNI_CallStaticLongMethodV,
3988         _Jv_JNI_CallStaticLongMethodA,
3989         _Jv_JNI_CallStaticFloatMethod,
3990         _Jv_JNI_CallStaticFloatMethodV,
3991         _Jv_JNI_CallStaticFloatMethodA,
3992         _Jv_JNI_CallStaticDoubleMethod,
3993         _Jv_JNI_CallStaticDoubleMethodV,
3994         _Jv_JNI_CallStaticDoubleMethodA,
3995         _Jv_JNI_CallStaticVoidMethod,
3996         _Jv_JNI_CallStaticVoidMethodV,
3997         _Jv_JNI_CallStaticVoidMethodA,
3998
3999         _Jv_JNI_GetStaticFieldID,
4000
4001         _Jv_JNI_GetStaticObjectField,
4002         _Jv_JNI_GetStaticBooleanField,
4003         _Jv_JNI_GetStaticByteField,
4004         _Jv_JNI_GetStaticCharField,
4005         _Jv_JNI_GetStaticShortField,
4006         _Jv_JNI_GetStaticIntField,
4007         _Jv_JNI_GetStaticLongField,
4008         _Jv_JNI_GetStaticFloatField,
4009         _Jv_JNI_GetStaticDoubleField,
4010         _Jv_JNI_SetStaticObjectField,
4011         _Jv_JNI_SetStaticBooleanField,
4012         _Jv_JNI_SetStaticByteField,
4013         _Jv_JNI_SetStaticCharField,
4014         _Jv_JNI_SetStaticShortField,
4015         _Jv_JNI_SetStaticIntField,
4016         _Jv_JNI_SetStaticLongField,
4017         _Jv_JNI_SetStaticFloatField,
4018         _Jv_JNI_SetStaticDoubleField,
4019
4020         jni_NewString,
4021         jni_GetStringLength,
4022         jni_GetStringChars,
4023         _Jv_JNI_ReleaseStringChars,
4024
4025         jni_NewStringUTF,
4026         jni_GetStringUTFLength,
4027         _Jv_JNI_GetStringUTFChars,
4028         _Jv_JNI_ReleaseStringUTFChars,
4029
4030         _Jv_JNI_GetArrayLength,
4031
4032         _Jv_JNI_NewObjectArray,
4033         _Jv_JNI_GetObjectArrayElement,
4034         _Jv_JNI_SetObjectArrayElement,
4035
4036         _Jv_JNI_NewBooleanArray,
4037         _Jv_JNI_NewByteArray,
4038         _Jv_JNI_NewCharArray,
4039         _Jv_JNI_NewShortArray,
4040         _Jv_JNI_NewIntArray,
4041         _Jv_JNI_NewLongArray,
4042         _Jv_JNI_NewFloatArray,
4043         _Jv_JNI_NewDoubleArray,
4044
4045         _Jv_JNI_GetBooleanArrayElements,
4046         _Jv_JNI_GetByteArrayElements,
4047         _Jv_JNI_GetCharArrayElements,
4048         _Jv_JNI_GetShortArrayElements,
4049         _Jv_JNI_GetIntArrayElements,
4050         _Jv_JNI_GetLongArrayElements,
4051         _Jv_JNI_GetFloatArrayElements,
4052         _Jv_JNI_GetDoubleArrayElements,
4053
4054         _Jv_JNI_ReleaseBooleanArrayElements,
4055         _Jv_JNI_ReleaseByteArrayElements,
4056         _Jv_JNI_ReleaseCharArrayElements,
4057         _Jv_JNI_ReleaseShortArrayElements,
4058         _Jv_JNI_ReleaseIntArrayElements,
4059         _Jv_JNI_ReleaseLongArrayElements,
4060         _Jv_JNI_ReleaseFloatArrayElements,
4061         _Jv_JNI_ReleaseDoubleArrayElements,
4062
4063         _Jv_JNI_GetBooleanArrayRegion,
4064         _Jv_JNI_GetByteArrayRegion,
4065         _Jv_JNI_GetCharArrayRegion,
4066         _Jv_JNI_GetShortArrayRegion,
4067         _Jv_JNI_GetIntArrayRegion,
4068         _Jv_JNI_GetLongArrayRegion,
4069         _Jv_JNI_GetFloatArrayRegion,
4070         _Jv_JNI_GetDoubleArrayRegion,
4071         _Jv_JNI_SetBooleanArrayRegion,
4072         _Jv_JNI_SetByteArrayRegion,
4073         _Jv_JNI_SetCharArrayRegion,
4074         _Jv_JNI_SetShortArrayRegion,
4075         _Jv_JNI_SetIntArrayRegion,
4076         _Jv_JNI_SetLongArrayRegion,
4077         _Jv_JNI_SetFloatArrayRegion,
4078         _Jv_JNI_SetDoubleArrayRegion,
4079
4080         _Jv_JNI_RegisterNatives,
4081         _Jv_JNI_UnregisterNatives,
4082
4083         _Jv_JNI_MonitorEnter,
4084         _Jv_JNI_MonitorExit,
4085
4086         _Jv_JNI_GetJavaVM,
4087
4088         /* New JNI 1.2 functions. */
4089
4090         jni_GetStringRegion,
4091         jni_GetStringUTFRegion,
4092
4093         jni_GetPrimitiveArrayCritical,
4094         jni_ReleasePrimitiveArrayCritical,
4095
4096         _Jv_JNI_GetStringCritical,
4097         _Jv_JNI_ReleaseStringCritical,
4098
4099         _Jv_JNI_NewWeakGlobalRef,
4100         _Jv_JNI_DeleteWeakGlobalRef,
4101
4102         _Jv_JNI_ExceptionCheck,
4103
4104         /* New JNI 1.4 functions. */
4105
4106         jni_NewDirectByteBuffer,
4107         jni_GetDirectBufferAddress,
4108         jni_GetDirectBufferCapacity,
4109
4110         /* New JNI 1.6 functions. */
4111
4112         jni_GetObjectRefType
4113 };
4114
4115
4116 /* Invocation API Functions ***************************************************/
4117
4118 /* JNI_GetDefaultJavaVMInitArgs ************************************************
4119
4120    Returns a default configuration for the Java VM.
4121
4122 *******************************************************************************/
4123
4124 jint JNI_GetDefaultJavaVMInitArgs(void *vm_args)
4125 {
4126         JavaVMInitArgs *_vm_args;
4127
4128         _vm_args = (JavaVMInitArgs *) vm_args;
4129
4130         /* GNU classpath currently supports JNI 1.2 */
4131
4132         switch (_vm_args->version) {
4133     case JNI_VERSION_1_1:
4134                 _vm_args->version = JNI_VERSION_1_1;
4135                 break;
4136
4137     case JNI_VERSION_1_2:
4138     case JNI_VERSION_1_4:
4139                 _vm_args->ignoreUnrecognized = JNI_FALSE;
4140                 _vm_args->options = NULL;
4141                 _vm_args->nOptions = 0;
4142                 break;
4143
4144     default:
4145                 return -1;
4146         }
4147   
4148         return 0;
4149 }
4150
4151
4152 /* JNI_GetCreatedJavaVMs *******************************************************
4153
4154    Returns all Java VMs that have been created. Pointers to VMs are written in
4155    the buffer vmBuf in the order they are created. At most bufLen number of
4156    entries will be written. The total number of created VMs is returned in
4157    *nVMs.
4158
4159 *******************************************************************************/
4160
4161 jint JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize *nVMs)
4162 {
4163         TRACEJNICALLS(("JNI_GetCreatedJavaVMs(vmBuf=%p, jsize=%d, jsize=%p)", vmBuf, bufLen, nVMs));
4164
4165         if (bufLen <= 0)
4166                 return JNI_ERR;
4167
4168         // We currently only support 1 VM running.
4169
4170         vmBuf[0] = vm->get_javavm();
4171         *nVMs    = 1;
4172
4173     return JNI_OK;
4174 }
4175
4176
4177 /* JNI_CreateJavaVM ************************************************************
4178
4179    Loads and initializes a Java VM. The current thread becomes the main thread.
4180    Sets the env argument to the JNI interface pointer of the main thread.
4181
4182 *******************************************************************************/
4183
4184 jint JNI_CreateJavaVM(JavaVM **p_vm, void **p_env, void *vm_args)
4185 {
4186         TRACEJNICALLS(("JNI_CreateJavaVM(p_vm=%p, p_env=%p, vm_args=%p)", p_vm, p_env, vm_args));
4187
4188         /* actually create the JVM */
4189
4190         if (!VM_create(p_vm, p_env, vm_args))
4191                 return JNI_ERR;
4192
4193         return JNI_OK;
4194 }
4195
4196 } // extern "C"
4197
4198
4199 /*
4200  * These are local overrides for various environment variables in Emacs.
4201  * Please do not remove this and leave it at the end of the file, where
4202  * Emacs will automagically detect them.
4203  * ---------------------------------------------------------------------
4204  * Local variables:
4205  * mode: c++
4206  * indent-tabs-mode: t
4207  * c-basic-offset: 4
4208  * tab-width: 4
4209  * End:
4210  * vim:noexpandtab:sw=4:ts=4:
4211  */