OSDN Git Service

3944b0e0bea0e2f9386c95c725e49da68c845fe4
[pf3gnuchains/gcc-fork.git] / libjava / jni.cc
1 // jni.cc - JNI implementation, including the jump table.
2
3 /* Copyright (C) 1998, 1999, 2000, 2001  Free Software Foundation
4
5    This file is part of libgcj.
6
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
9 details.  */
10
11 #include <config.h>
12
13 #include <stddef.h>
14 #include <string.h>
15
16 // Define this before including jni.h.
17 #define __GCJ_JNI_IMPL__
18
19 #include <gcj/cni.h>
20 #include <jvm.h>
21 #include <java-assert.h>
22 #include <jni.h>
23 #ifdef ENABLE_JVMPI
24 #include <jvmpi.h>
25 #endif
26
27 #include <java/lang/Class.h>
28 #include <java/lang/ClassLoader.h>
29 #include <java/lang/Throwable.h>
30 #include <java/lang/ArrayIndexOutOfBoundsException.h>
31 #include <java/lang/StringIndexOutOfBoundsException.h>
32 #include <java/lang/AbstractMethodError.h>
33 #include <java/lang/InstantiationException.h>
34 #include <java/lang/NoSuchFieldError.h>
35 #include <java/lang/NoSuchMethodError.h>
36 #include <java/lang/reflect/Constructor.h>
37 #include <java/lang/reflect/Method.h>
38 #include <java/lang/reflect/Modifier.h>
39 #include <java/lang/OutOfMemoryError.h>
40 #include <java/util/Hashtable.h>
41 #include <java/lang/Integer.h>
42 #include <java/lang/ThreadGroup.h>
43 #include <java/lang/Thread.h>
44
45 #include <gcj/method.h>
46 #include <gcj/field.h>
47
48 #include <java-interp.h>
49 #include <java-threads.h>
50
51 // This enum is used to select different template instantiations in
52 // the invocation code.
53 enum invocation_type
54 {
55   normal,
56   nonvirtual,
57   static_type,
58   constructor
59 };
60
61 // Forward declarations.
62 extern struct JNINativeInterface _Jv_JNIFunctions;
63 extern struct JNIInvokeInterface _Jv_JNI_InvokeFunctions;
64
65 // Number of slots in the default frame.  The VM must allow at least
66 // 16.
67 #define FRAME_SIZE 32
68
69 // Mark value indicating this is an overflow frame.
70 #define MARK_NONE    0
71 // Mark value indicating this is a user frame.
72 #define MARK_USER    1
73 // Mark value indicating this is a system frame.
74 #define MARK_SYSTEM  2
75
76 // This structure is used to keep track of local references.
77 struct _Jv_JNI_LocalFrame
78 {
79   // This is true if this frame object represents a pushed frame (eg
80   // from PushLocalFrame).
81   int marker :  2;
82
83   // Number of elements in frame.
84   int size   : 30;
85
86   // Next frame in chain.
87   _Jv_JNI_LocalFrame *next;
88
89   // The elements.  These are allocated using the C "struct hack".
90   jobject vec[0];
91 };
92
93 // This holds a reference count for all local references.
94 static java::util::Hashtable *local_ref_table;
95 // This holds a reference count for all global references.
96 static java::util::Hashtable *global_ref_table;
97
98 // The only VM.
99 static JavaVM *the_vm;
100
101 #ifdef ENABLE_JVMPI
102 // The only JVMPI interface description.
103 static JVMPI_Interface _Jv_JVMPI_Interface;
104
105 static jint
106 jvmpiEnableEvent (jint event_type, void *)
107 {
108   switch (event_type)
109     {
110     case JVMPI_EVENT_OBJECT_ALLOC:
111       _Jv_JVMPI_Notify_OBJECT_ALLOC = _Jv_JVMPI_Interface.NotifyEvent;
112       break;
113       
114     case JVMPI_EVENT_THREAD_START:
115       _Jv_JVMPI_Notify_THREAD_START = _Jv_JVMPI_Interface.NotifyEvent;
116       break;
117       
118     case JVMPI_EVENT_THREAD_END:
119       _Jv_JVMPI_Notify_THREAD_END = _Jv_JVMPI_Interface.NotifyEvent;
120       break;
121       
122     default:
123       return JVMPI_NOT_AVAILABLE;
124     }
125   
126   return JVMPI_SUCCESS;
127 }
128
129 static jint
130 jvmpiDisableEvent (jint event_type, void *)
131 {
132   switch (event_type)
133     {
134     case JVMPI_EVENT_OBJECT_ALLOC:
135       _Jv_JVMPI_Notify_OBJECT_ALLOC = NULL;
136       break;
137       
138     default:
139       return JVMPI_NOT_AVAILABLE;
140     }
141   
142   return JVMPI_SUCCESS;
143 }
144 #endif
145
146 \f
147
148 void
149 _Jv_JNI_Init (void)
150 {
151   local_ref_table = new java::util::Hashtable;
152   global_ref_table = new java::util::Hashtable;
153
154 #ifdef ENABLE_JVMPI
155   _Jv_JVMPI_Interface.version = 1;
156   _Jv_JVMPI_Interface.EnableEvent = &jvmpiEnableEvent;
157   _Jv_JVMPI_Interface.DisableEvent = &jvmpiDisableEvent;
158   _Jv_JVMPI_Interface.EnableGC = &_Jv_EnableGC;
159   _Jv_JVMPI_Interface.DisableGC = &_Jv_DisableGC;
160   _Jv_JVMPI_Interface.RunGC = &_Jv_RunGC;
161 #endif
162 }
163
164 // Tell the GC that a certain pointer is live.
165 static void
166 mark_for_gc (jobject obj, java::util::Hashtable *ref_table)
167 {
168   JvSynchronize sync (ref_table);
169
170   using namespace java::lang;
171   Integer *refcount = (Integer *) ref_table->get (obj);
172   jint val = (refcount == NULL) ? 0 : refcount->intValue ();
173   // FIXME: what about out of memory error?
174   ref_table->put (obj, new Integer (val + 1));
175 }
176
177 // Unmark a pointer.
178 static void
179 unmark_for_gc (jobject obj, java::util::Hashtable *ref_table)
180 {
181   JvSynchronize sync (ref_table);
182
183   using namespace java::lang;
184   Integer *refcount = (Integer *) ref_table->get (obj);
185   JvAssert (refcount);
186   jint val = refcount->intValue () - 1;
187   JvAssert (val >= 0);
188   if (val == 0)
189     ref_table->remove (obj);
190   else
191     // FIXME: what about out of memory error?
192     ref_table->put (obj, new Integer (val));
193 }
194
195 \f
196
197 static jobject
198 _Jv_JNI_NewGlobalRef (JNIEnv *, jobject obj)
199 {
200   mark_for_gc (obj, global_ref_table);
201   return obj;
202 }
203
204 static void
205 _Jv_JNI_DeleteGlobalRef (JNIEnv *, jobject obj)
206 {
207   unmark_for_gc (obj, global_ref_table);
208 }
209
210 static void
211 _Jv_JNI_DeleteLocalRef (JNIEnv *env, jobject obj)
212 {
213   _Jv_JNI_LocalFrame *frame;
214
215   for (frame = env->locals; frame != NULL; frame = frame->next)
216     {
217       for (int i = 0; i < FRAME_SIZE; ++i)
218         {
219           if (frame->vec[i] == obj)
220             {
221               frame->vec[i] = NULL;
222               unmark_for_gc (obj, local_ref_table);
223               return;
224             }
225         }
226
227       // Don't go past a marked frame.
228       JvAssert (frame->marker == MARK_NONE);
229     }
230
231   JvAssert (0);
232 }
233
234 static jint
235 _Jv_JNI_EnsureLocalCapacity (JNIEnv *env, jint size)
236 {
237   // It is easier to just always allocate a new frame of the requested
238   // size.  This isn't the most efficient thing, but for now we don't
239   // care.  Note that _Jv_JNI_PushLocalFrame relies on this right now.
240
241   _Jv_JNI_LocalFrame *frame;
242   try
243     {
244       frame = (_Jv_JNI_LocalFrame *) _Jv_Malloc (sizeof (_Jv_JNI_LocalFrame)
245                                                  + size * sizeof (jobject));
246     }
247   catch (jthrowable t)
248     {
249       env->ex = t;
250       return JNI_ERR;
251     }
252
253   frame->marker = MARK_NONE;
254   frame->size = size;
255   memset (&frame->vec[0], 0, size * sizeof (jobject));
256   frame->next = env->locals;
257   env->locals = frame;
258
259   return 0;
260 }
261
262 static jint
263 _Jv_JNI_PushLocalFrame (JNIEnv *env, jint size)
264 {
265   jint r = _Jv_JNI_EnsureLocalCapacity (env, size);
266   if (r < 0)
267     return r;
268
269   // The new frame is on top.
270   env->locals->marker = MARK_USER;
271
272   return 0;
273 }
274
275 static jobject
276 _Jv_JNI_NewLocalRef (JNIEnv *env, jobject obj)
277 {
278   // Try to find an open slot somewhere in the topmost frame.
279   _Jv_JNI_LocalFrame *frame = env->locals;
280   bool done = false, set = false;
281   for (; frame != NULL && ! done; frame = frame->next)
282     {
283       for (int i = 0; i < frame->size; ++i)
284         {
285           if (frame->vec[i] == NULL)
286             {
287               set = true;
288               done = true;
289               frame->vec[i] = obj;
290               break;
291             }
292         }
293
294       // If we found a slot, or if the frame we just searched is the
295       // mark frame, then we are done.
296       if (done || frame->marker != MARK_NONE)
297         break;
298     }
299
300   if (! set)
301     {
302       // No slots, so we allocate a new frame.  According to the spec
303       // we could just die here.  FIXME: return value.
304       _Jv_JNI_EnsureLocalCapacity (env, 16);
305       // We know the first element of the new frame will be ok.
306       env->locals->vec[0] = obj;
307     }
308
309   mark_for_gc (obj, local_ref_table);
310   return obj;
311 }
312
313 static jobject
314 _Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result, int stop)
315 {
316   _Jv_JNI_LocalFrame *rf = env->locals;
317
318   bool done = false;
319   while (rf != NULL && ! done)
320     {  
321       for (int i = 0; i < rf->size; ++i)
322         if (rf->vec[i] != NULL)
323           unmark_for_gc (rf->vec[i], local_ref_table);
324
325       // If the frame we just freed is the marker frame, we are done.
326       done = (rf->marker == stop);
327
328       _Jv_JNI_LocalFrame *n = rf->next;
329       // When N==NULL, we've reached the stack-allocated frame, and we
330       // must not free it.  However, we must be sure to clear all its
331       // elements, since we might conceivably reuse it.
332       if (n == NULL)
333         {
334           memset (&rf->vec[0], 0, rf->size * sizeof (jobject));
335           break;
336         }
337
338       _Jv_Free (rf);
339       rf = n;
340     }
341
342   // Update the local frame information.
343   env->locals = rf;
344
345   return result == NULL ? NULL : _Jv_JNI_NewLocalRef (env, result);
346 }
347
348 static jobject
349 _Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result)
350 {
351   return _Jv_JNI_PopLocalFrame (env, result, MARK_USER);
352 }
353
354 // Pop a `system' frame from the stack.  This is `extern "C"' as it is
355 // used by the compiler.
356 extern "C" void
357 _Jv_JNI_PopSystemFrame (JNIEnv *env)
358 {
359   _Jv_JNI_PopLocalFrame (env, NULL, MARK_SYSTEM);
360
361   if (env->ex)
362     {
363       jthrowable t = env->ex;
364       env->ex = NULL;
365       throw t;
366     }
367 }
368
369 // This function is used from other template functions.  It wraps the
370 // return value appropriately; we specialize it so that object returns
371 // are turned into local references.
372 template<typename T>
373 static T
374 wrap_value (JNIEnv *, T value)
375 {
376   return value;
377 }
378
379 // This specialization is used for jobject, jclass, jstring, jarray,
380 // etc.
381 template<typename T>
382 static T *
383 wrap_value (JNIEnv *env, T *value)
384 {
385   return (value == NULL
386           ? value
387           : (T *) _Jv_JNI_NewLocalRef (env, (jobject) value));
388 }
389
390 \f
391
392 static jint
393 _Jv_JNI_GetVersion (JNIEnv *)
394 {
395   return JNI_VERSION_1_2;
396 }
397
398 static jclass
399 _Jv_JNI_DefineClass (JNIEnv *env, jobject loader, 
400                      const jbyte *buf, jsize bufLen)
401 {
402   try
403     {
404       jbyteArray bytes = JvNewByteArray (bufLen);
405
406       jbyte *elts = elements (bytes);
407       memcpy (elts, buf, bufLen * sizeof (jbyte));
408
409       java::lang::ClassLoader *l
410         = reinterpret_cast<java::lang::ClassLoader *> (loader);
411
412       jclass result = l->defineClass (bytes, 0, bufLen);
413       return (jclass) wrap_value (env, result);
414     }
415   catch (jthrowable t)
416     {
417       env->ex = t;
418       return NULL;
419     }
420 }
421
422 static jclass
423 _Jv_JNI_FindClass (JNIEnv *env, const char *name)
424 {
425   // FIXME: assume that NAME isn't too long.
426   int len = strlen (name);
427   char s[len + 1];
428   for (int i = 0; i <= len; ++i)
429     s[i] = (name[i] == '/') ? '.' : name[i];
430
431   jclass r = NULL;
432   try
433     {
434       // This might throw an out of memory exception.
435       jstring n = JvNewStringUTF (s);
436
437       java::lang::ClassLoader *loader = NULL;
438       if (env->klass != NULL)
439         loader = env->klass->getClassLoader ();
440
441       if (loader == NULL)
442         {
443           // FIXME: should use getBaseClassLoader, but we don't have that
444           // yet.
445           loader = java::lang::ClassLoader::getSystemClassLoader ();
446         }
447
448       r = loader->loadClass (n);
449     }
450   catch (jthrowable t)
451     {
452       env->ex = t;
453     }
454
455   return (jclass) wrap_value (env, r);
456 }
457
458 static jclass
459 _Jv_JNI_GetSuperclass (JNIEnv *env, jclass clazz)
460 {
461   return (jclass) wrap_value (env, clazz->getSuperclass ());
462 }
463
464 static jboolean
465 _Jv_JNI_IsAssignableFrom(JNIEnv *, jclass clazz1, jclass clazz2)
466 {
467   return clazz1->isAssignableFrom (clazz2);
468 }
469
470 static jint
471 _Jv_JNI_Throw (JNIEnv *env, jthrowable obj)
472 {
473   // We check in case the user did some funky cast.
474   JvAssert (obj != NULL && java::lang::Throwable::class$.isInstance (obj));
475   env->ex = obj;
476   return 0;
477 }
478
479 static jint
480 _Jv_JNI_ThrowNew (JNIEnv *env, jclass clazz, const char *message)
481 {
482   using namespace java::lang::reflect;
483
484   JvAssert (java::lang::Throwable::class$.isAssignableFrom (clazz));
485
486   int r = JNI_OK;
487   try
488     {
489       JArray<jclass> *argtypes
490         = (JArray<jclass> *) JvNewObjectArray (1, &java::lang::Class::class$,
491                                                NULL);
492
493       jclass *elts = elements (argtypes);
494       elts[0] = &StringClass;
495
496       Constructor *cons = clazz->getConstructor (argtypes);
497
498       jobjectArray values = JvNewObjectArray (1, &StringClass, NULL);
499       jobject *velts = elements (values);
500       velts[0] = JvNewStringUTF (message);
501
502       jobject obj = cons->newInstance (values);
503
504       env->ex = reinterpret_cast<jthrowable> (obj);
505     }
506   catch (jthrowable t)
507     {
508       env->ex = t;
509       r = JNI_ERR;
510     }
511
512   return r;
513 }
514
515 static jthrowable
516 _Jv_JNI_ExceptionOccurred (JNIEnv *env)
517 {
518   return (jthrowable) wrap_value (env, env->ex);
519 }
520
521 static void
522 _Jv_JNI_ExceptionDescribe (JNIEnv *env)
523 {
524   if (env->ex != NULL)
525     env->ex->printStackTrace();
526 }
527
528 static void
529 _Jv_JNI_ExceptionClear (JNIEnv *env)
530 {
531   env->ex = NULL;
532 }
533
534 static jboolean
535 _Jv_JNI_ExceptionCheck (JNIEnv *env)
536 {
537   return env->ex != NULL;
538 }
539
540 static void
541 _Jv_JNI_FatalError (JNIEnv *, const char *message)
542 {
543   JvFail (message);
544 }
545
546 \f
547
548 static jboolean
549 _Jv_JNI_IsSameObject (JNIEnv *, jobject obj1, jobject obj2)
550 {
551   return obj1 == obj2;
552 }
553
554 static jobject
555 _Jv_JNI_AllocObject (JNIEnv *env, jclass clazz)
556 {
557   jobject obj = NULL;
558   using namespace java::lang::reflect;
559
560   try
561     {
562       JvAssert (clazz && ! clazz->isArray ());
563       if (clazz->isInterface() || Modifier::isAbstract(clazz->getModifiers()))
564         env->ex = new java::lang::InstantiationException ();
565       else
566         {
567           // FIXME: will this work for String?
568           obj = JvAllocObject (clazz);
569         }
570     }
571   catch (jthrowable t)
572     {
573       env->ex = t;
574     }
575
576   return wrap_value (env, obj);
577 }
578
579 static jclass
580 _Jv_JNI_GetObjectClass (JNIEnv *env, jobject obj)
581 {
582   JvAssert (obj);
583   return (jclass) wrap_value (env, obj->getClass());
584 }
585
586 static jboolean
587 _Jv_JNI_IsInstanceOf (JNIEnv *, jobject obj, jclass clazz)
588 {
589   return clazz->isInstance(obj);
590 }
591
592 \f
593
594 //
595 // This section concerns method invocation.
596 //
597
598 template<jboolean is_static>
599 static jmethodID
600 _Jv_JNI_GetAnyMethodID (JNIEnv *env, jclass clazz,
601                         const char *name, const char *sig)
602 {
603   try
604     {
605       _Jv_InitClass (clazz);
606
607       _Jv_Utf8Const *name_u = _Jv_makeUtf8Const ((char *) name, -1);
608
609       // FIXME: assume that SIG isn't too long.
610       int len = strlen (sig);
611       char s[len + 1];
612       for (int i = 0; i <= len; ++i)
613         s[i] = (sig[i] == '/') ? '.' : sig[i];
614       _Jv_Utf8Const *sig_u = _Jv_makeUtf8Const ((char *) s, -1);
615
616       JvAssert (! clazz->isPrimitive());
617
618       using namespace java::lang::reflect;
619
620       while (clazz != NULL)
621         {
622           jint count = JvNumMethods (clazz);
623           jmethodID meth = JvGetFirstMethod (clazz);
624
625           for (jint i = 0; i < count; ++i)
626             {
627               if (((is_static && Modifier::isStatic (meth->accflags))
628                    || (! is_static && ! Modifier::isStatic (meth->accflags)))
629                   && _Jv_equalUtf8Consts (meth->name, name_u)
630                   && _Jv_equalUtf8Consts (meth->signature, sig_u))
631                 return meth;
632
633               meth = meth->getNextMethod();
634             }
635
636           clazz = clazz->getSuperclass ();
637         }
638
639       env->ex = new java::lang::NoSuchMethodError ();
640     }
641   catch (jthrowable t)
642     {
643       env->ex = t;
644     }
645
646   return NULL;
647 }
648
649 // This is a helper function which turns a va_list into an array of
650 // `jvalue's.  It needs signature information in order to do its work.
651 // The array of values must already be allocated.
652 static void
653 array_from_valist (jvalue *values, JArray<jclass> *arg_types, va_list vargs)
654 {
655   jclass *arg_elts = elements (arg_types);
656   for (int i = 0; i < arg_types->length; ++i)
657     {
658       if (arg_elts[i] == JvPrimClass (byte))
659         values[i].b = va_arg (vargs, jbyte);
660       else if (arg_elts[i] == JvPrimClass (short))
661         values[i].s = va_arg (vargs, jshort);
662       else if (arg_elts[i] == JvPrimClass (int))
663         values[i].i = va_arg (vargs, jint);
664       else if (arg_elts[i] == JvPrimClass (long))
665         values[i].j = va_arg (vargs, jlong);
666       else if (arg_elts[i] == JvPrimClass (float))
667         values[i].f = va_arg (vargs, jfloat);
668       else if (arg_elts[i] == JvPrimClass (double))
669         values[i].d = va_arg (vargs, jdouble);
670       else if (arg_elts[i] == JvPrimClass (boolean))
671         values[i].z = va_arg (vargs, jboolean);
672       else if (arg_elts[i] == JvPrimClass (char))
673         values[i].c = va_arg (vargs, jchar);
674       else
675         {
676           // An object.
677           values[i].l = va_arg (vargs, jobject);
678         }
679     }
680 }
681
682 // This can call any sort of method: virtual, "nonvirtual", static, or
683 // constructor.
684 template<typename T, invocation_type style>
685 static T
686 _Jv_JNI_CallAnyMethodV (JNIEnv *env, jobject obj, jclass klass,
687                         jmethodID id, va_list vargs)
688 {
689   if (style == normal)
690     id = _Jv_LookupDeclaredMethod (obj->getClass (), id->name, id->signature);
691
692   jclass decl_class = klass ? klass : obj->getClass ();
693   JvAssert (decl_class != NULL);
694
695   jclass return_type;
696   JArray<jclass> *arg_types;
697
698   try
699     {
700       _Jv_GetTypesFromSignature (id, decl_class,
701                                  &arg_types, &return_type);
702
703       jvalue args[arg_types->length];
704       array_from_valist (args, arg_types, vargs);
705
706       // For constructors we need to pass the Class we are instantiating.
707       if (style == constructor)
708         return_type = klass;
709
710       jvalue result;
711       jthrowable ex = _Jv_CallAnyMethodA (obj, return_type, id,
712                                           style == constructor,
713                                           arg_types, args, &result);
714
715       if (ex != NULL)
716         env->ex = ex;
717
718       // We cheat a little here.  FIXME.
719       return wrap_value (env, * (T *) &result);
720     }
721   catch (jthrowable t)
722     {
723       env->ex = t;
724     }
725
726   return wrap_value (env, (T) 0);
727 }
728
729 template<typename T, invocation_type style>
730 static T
731 _Jv_JNI_CallAnyMethod (JNIEnv *env, jobject obj, jclass klass,
732                        jmethodID method, ...)
733 {
734   va_list args;
735   T result;
736
737   va_start (args, method);
738   result = _Jv_JNI_CallAnyMethodV<T, style> (env, obj, klass, method, args);
739   va_end (args);
740
741   return result;
742 }
743
744 template<typename T, invocation_type style>
745 static T
746 _Jv_JNI_CallAnyMethodA (JNIEnv *env, jobject obj, jclass klass,
747                         jmethodID id, jvalue *args)
748 {
749   if (style == normal)
750     id = _Jv_LookupDeclaredMethod (obj->getClass (), id->name, id->signature);
751
752   jclass decl_class = klass ? klass : obj->getClass ();
753   JvAssert (decl_class != NULL);
754
755   jclass return_type;
756   JArray<jclass> *arg_types;
757   try
758     {
759       _Jv_GetTypesFromSignature (id, decl_class,
760                                  &arg_types, &return_type);
761
762       // For constructors we need to pass the Class we are instantiating.
763       if (style == constructor)
764         return_type = klass;
765
766       jvalue result;
767       jthrowable ex = _Jv_CallAnyMethodA (obj, return_type, id,
768                                           style == constructor,
769                                           arg_types, args, &result);
770
771       if (ex != NULL)
772         env->ex = ex;
773
774       // We cheat a little here.  FIXME.
775       return wrap_value (env, * (T *) &result);
776     }
777   catch (jthrowable t)
778     {
779       env->ex = t;
780     }
781
782   return wrap_value (env, (T) 0);
783 }
784
785 template<invocation_type style>
786 static void
787 _Jv_JNI_CallAnyVoidMethodV (JNIEnv *env, jobject obj, jclass klass,
788                             jmethodID id, va_list vargs)
789 {
790   if (style == normal)
791     id = _Jv_LookupDeclaredMethod (obj->getClass (), id->name, id->signature);
792
793   jclass decl_class = klass ? klass : obj->getClass ();
794   JvAssert (decl_class != NULL);
795
796   jclass return_type;
797   JArray<jclass> *arg_types;
798   try
799     {
800       _Jv_GetTypesFromSignature (id, decl_class,
801                                  &arg_types, &return_type);
802
803       jvalue args[arg_types->length];
804       array_from_valist (args, arg_types, vargs);
805
806       // For constructors we need to pass the Class we are instantiating.
807       if (style == constructor)
808         return_type = klass;
809
810       jthrowable ex = _Jv_CallAnyMethodA (obj, return_type, id,
811                                           style == constructor,
812                                           arg_types, args, NULL);
813
814       if (ex != NULL)
815         env->ex = ex;
816     }
817   catch (jthrowable t)
818     {
819       env->ex = t;
820     }
821 }
822
823 template<invocation_type style>
824 static void
825 _Jv_JNI_CallAnyVoidMethod (JNIEnv *env, jobject obj, jclass klass,
826                            jmethodID method, ...)
827 {
828   va_list args;
829
830   va_start (args, method);
831   _Jv_JNI_CallAnyVoidMethodV<style> (env, obj, klass, method, args);
832   va_end (args);
833 }
834
835 template<invocation_type style>
836 static void
837 _Jv_JNI_CallAnyVoidMethodA (JNIEnv *env, jobject obj, jclass klass,
838                             jmethodID id, jvalue *args)
839 {
840   if (style == normal)
841     id = _Jv_LookupDeclaredMethod (obj->getClass (), id->name, id->signature);
842
843   jclass decl_class = klass ? klass : obj->getClass ();
844   JvAssert (decl_class != NULL);
845
846   jclass return_type;
847   JArray<jclass> *arg_types;
848   try
849     {
850       _Jv_GetTypesFromSignature (id, decl_class,
851                                  &arg_types, &return_type);
852
853       jthrowable ex = _Jv_CallAnyMethodA (obj, return_type, id,
854                                           style == constructor,
855                                           arg_types, args, NULL);
856
857       if (ex != NULL)
858         env->ex = ex;
859     }
860   catch (jthrowable t)
861     {
862       env->ex = t;
863     }
864 }
865
866 // Functions with this signature are used to implement functions in
867 // the CallMethod family.
868 template<typename T>
869 static T
870 _Jv_JNI_CallMethodV (JNIEnv *env, jobject obj, jmethodID id, va_list args)
871 {
872   return _Jv_JNI_CallAnyMethodV<T, normal> (env, obj, NULL, id, args);
873 }
874
875 // Functions with this signature are used to implement functions in
876 // the CallMethod family.
877 template<typename T>
878 static T
879 _Jv_JNI_CallMethod (JNIEnv *env, jobject obj, jmethodID id, ...)
880 {
881   va_list args;
882   T result;
883
884   va_start (args, id);
885   result = _Jv_JNI_CallAnyMethodV<T, normal> (env, obj, NULL, id, args);
886   va_end (args);
887
888   return result;
889 }
890
891 // Functions with this signature are used to implement functions in
892 // the CallMethod family.
893 template<typename T>
894 static T
895 _Jv_JNI_CallMethodA (JNIEnv *env, jobject obj, jmethodID id, jvalue *args)
896 {
897   return _Jv_JNI_CallAnyMethodA<T, normal> (env, obj, NULL, id, args);
898 }
899
900 static void
901 _Jv_JNI_CallVoidMethodV (JNIEnv *env, jobject obj, jmethodID id, va_list args)
902 {
903   _Jv_JNI_CallAnyVoidMethodV<normal> (env, obj, NULL, id, args);
904 }
905
906 static void
907 _Jv_JNI_CallVoidMethod (JNIEnv *env, jobject obj, jmethodID id, ...)
908 {
909   va_list args;
910
911   va_start (args, id);
912   _Jv_JNI_CallAnyVoidMethodV<normal> (env, obj, NULL, id, args);
913   va_end (args);
914 }
915
916 static void
917 _Jv_JNI_CallVoidMethodA (JNIEnv *env, jobject obj, jmethodID id, jvalue *args)
918 {
919   _Jv_JNI_CallAnyVoidMethodA<normal> (env, obj, NULL, id, args);
920 }
921
922 // Functions with this signature are used to implement functions in
923 // the CallStaticMethod family.
924 template<typename T>
925 static T
926 _Jv_JNI_CallStaticMethodV (JNIEnv *env, jclass klass,
927                            jmethodID id, va_list args)
928 {
929   JvAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC));
930   JvAssert (java::lang::Class::class$.isInstance (klass));
931
932   return _Jv_JNI_CallAnyMethodV<T, static_type> (env, NULL, klass, id, args);
933 }
934
935 // Functions with this signature are used to implement functions in
936 // the CallStaticMethod family.
937 template<typename T>
938 static T
939 _Jv_JNI_CallStaticMethod (JNIEnv *env, jclass klass, jmethodID id, ...)
940 {
941   va_list args;
942   T result;
943
944   JvAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC));
945   JvAssert (java::lang::Class::class$.isInstance (klass));
946
947   va_start (args, id);
948   result = _Jv_JNI_CallAnyMethodV<T, static_type> (env, NULL, klass,
949                                                    id, args);
950   va_end (args);
951
952   return result;
953 }
954
955 // Functions with this signature are used to implement functions in
956 // the CallStaticMethod family.
957 template<typename T>
958 static T
959 _Jv_JNI_CallStaticMethodA (JNIEnv *env, jclass klass, jmethodID id,
960                            jvalue *args)
961 {
962   JvAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC));
963   JvAssert (java::lang::Class::class$.isInstance (klass));
964
965   return _Jv_JNI_CallAnyMethodA<T, static_type> (env, NULL, klass, id, args);
966 }
967
968 static void
969 _Jv_JNI_CallStaticVoidMethodV (JNIEnv *env, jclass klass, jmethodID id,
970                                va_list args)
971 {
972   _Jv_JNI_CallAnyVoidMethodV<static_type> (env, NULL, klass, id, args);
973 }
974
975 static void
976 _Jv_JNI_CallStaticVoidMethod (JNIEnv *env, jclass klass, jmethodID id, ...)
977 {
978   va_list args;
979
980   va_start (args, id);
981   _Jv_JNI_CallAnyVoidMethodV<static_type> (env, NULL, klass, id, args);
982   va_end (args);
983 }
984
985 static void
986 _Jv_JNI_CallStaticVoidMethodA (JNIEnv *env, jclass klass, jmethodID id,
987                                jvalue *args)
988 {
989   _Jv_JNI_CallAnyVoidMethodA<static_type> (env, NULL, klass, id, args);
990 }
991
992 static jobject
993 _Jv_JNI_NewObjectV (JNIEnv *env, jclass klass,
994                     jmethodID id, va_list args)
995 {
996   JvAssert (klass && ! klass->isArray ());
997   JvAssert (! strcmp (id->name->data, "<init>")
998             && id->signature->length > 2
999             && id->signature->data[0] == '('
1000             && ! strcmp (&id->signature->data[id->signature->length - 2],
1001                          ")V"));
1002
1003   return _Jv_JNI_CallAnyMethodV<jobject, constructor> (env, NULL, klass,
1004                                                        id, args);
1005 }
1006
1007 static jobject
1008 _Jv_JNI_NewObject (JNIEnv *env, jclass klass, jmethodID id, ...)
1009 {
1010   JvAssert (klass && ! klass->isArray ());
1011   JvAssert (! strcmp (id->name->data, "<init>")
1012             && id->signature->length > 2
1013             && id->signature->data[0] == '('
1014             && ! strcmp (&id->signature->data[id->signature->length - 2],
1015                          ")V"));
1016
1017   va_list args;
1018   jobject result;
1019
1020   va_start (args, id);
1021   result = _Jv_JNI_CallAnyMethodV<jobject, constructor> (env, NULL, klass,
1022                                                          id, args);
1023   va_end (args);
1024
1025   return result;
1026 }
1027
1028 static jobject
1029 _Jv_JNI_NewObjectA (JNIEnv *env, jclass klass, jmethodID id,
1030                     jvalue *args)
1031 {
1032   JvAssert (klass && ! klass->isArray ());
1033   JvAssert (! strcmp (id->name->data, "<init>")
1034             && id->signature->length > 2
1035             && id->signature->data[0] == '('
1036             && ! strcmp (&id->signature->data[id->signature->length - 2],
1037                          ")V"));
1038
1039   return _Jv_JNI_CallAnyMethodA<jobject, constructor> (env, NULL, klass,
1040                                                        id, args);
1041 }
1042
1043 \f
1044
1045 template<typename T>
1046 static T
1047 _Jv_JNI_GetField (JNIEnv *env, jobject obj, jfieldID field) 
1048 {
1049   JvAssert (obj);
1050   T *ptr = (T *) ((char *) obj + field->getOffset ());
1051   return wrap_value (env, *ptr);
1052 }
1053
1054 template<typename T>
1055 static void
1056 _Jv_JNI_SetField (JNIEnv *, jobject obj, jfieldID field, T value)
1057 {
1058   JvAssert (obj);
1059   T *ptr = (T *) ((char *) obj + field->getOffset ());
1060   *ptr = value;
1061 }
1062
1063 template<jboolean is_static>
1064 static jfieldID
1065 _Jv_JNI_GetAnyFieldID (JNIEnv *env, jclass clazz,
1066                        const char *name, const char *sig)
1067 {
1068   try
1069     {
1070       _Jv_InitClass (clazz);
1071
1072       _Jv_Utf8Const *a_name = _Jv_makeUtf8Const ((char *) name, -1);
1073
1074       // FIXME: assume that SIG isn't too long.
1075       int len = strlen (sig);
1076       char s[len + 1];
1077       for (int i = 0; i <= len; ++i)
1078         s[i] = (sig[i] == '/') ? '.' : sig[i];
1079       jclass field_class = _Jv_FindClassFromSignature ((char *) s, NULL);
1080
1081       // FIXME: what if field_class == NULL?
1082
1083       java::lang::ClassLoader *loader = clazz->getClassLoader ();
1084       while (clazz != NULL)
1085         {
1086           // We acquire the class lock so that fields aren't resolved
1087           // while we are running.
1088           JvSynchronize sync (clazz);
1089
1090           jint count = (is_static
1091                         ? JvNumStaticFields (clazz)
1092                         : JvNumInstanceFields (clazz));
1093           jfieldID field = (is_static
1094                             ? JvGetFirstStaticField (clazz)
1095                             : JvGetFirstInstanceField (clazz));
1096           for (jint i = 0; i < count; ++i)
1097             {
1098               _Jv_Utf8Const *f_name = field->getNameUtf8Const(clazz);
1099
1100               // The field might be resolved or it might not be.  It
1101               // is much simpler to always resolve it.
1102               _Jv_ResolveField (field, loader);
1103               if (_Jv_equalUtf8Consts (f_name, a_name)
1104                   && field->getClass() == field_class)
1105                 return field;
1106
1107               field = field->getNextField ();
1108             }
1109
1110           clazz = clazz->getSuperclass ();
1111         }
1112
1113       env->ex = new java::lang::NoSuchFieldError ();
1114     }
1115   catch (jthrowable t)
1116     {
1117       env->ex = t;
1118     }
1119   return NULL;
1120 }
1121
1122 template<typename T>
1123 static T
1124 _Jv_JNI_GetStaticField (JNIEnv *env, jclass, jfieldID field)
1125 {
1126   T *ptr = (T *) field->u.addr;
1127   return wrap_value (env, *ptr);
1128 }
1129
1130 template<typename T>
1131 static void
1132 _Jv_JNI_SetStaticField (JNIEnv *, jclass, jfieldID field, T value)
1133 {
1134   T *ptr = (T *) field->u.addr;
1135   *ptr = value;
1136 }
1137
1138 static jstring
1139 _Jv_JNI_NewString (JNIEnv *env, const jchar *unichars, jsize len)
1140 {
1141   try
1142     {
1143       jstring r = _Jv_NewString (unichars, len);
1144       return (jstring) wrap_value (env, r);
1145     }
1146   catch (jthrowable t)
1147     {
1148       env->ex = t;
1149       return NULL;
1150     }
1151 }
1152
1153 static jsize
1154 _Jv_JNI_GetStringLength (JNIEnv *, jstring string)
1155 {
1156   return string->length();
1157 }
1158
1159 static const jchar *
1160 _Jv_JNI_GetStringChars (JNIEnv *, jstring string, jboolean *isCopy)
1161 {
1162   jchar *result = _Jv_GetStringChars (string);
1163   mark_for_gc (string, global_ref_table);
1164   if (isCopy)
1165     *isCopy = false;
1166   return (const jchar *) result;
1167 }
1168
1169 static void
1170 _Jv_JNI_ReleaseStringChars (JNIEnv *, jstring string, const jchar *)
1171 {
1172   unmark_for_gc (string, global_ref_table);
1173 }
1174
1175 static jstring
1176 _Jv_JNI_NewStringUTF (JNIEnv *env, const char *bytes)
1177 {
1178   try
1179     {
1180       jstring result = JvNewStringUTF (bytes);
1181       return (jstring) wrap_value (env, result);
1182     }
1183   catch (jthrowable t)
1184     {
1185       env->ex = t;
1186       return NULL;
1187     }
1188 }
1189
1190 static jsize
1191 _Jv_JNI_GetStringUTFLength (JNIEnv *, jstring string)
1192 {
1193   return JvGetStringUTFLength (string);
1194 }
1195
1196 static const char *
1197 _Jv_JNI_GetStringUTFChars (JNIEnv *env, jstring string, jboolean *isCopy)
1198 {
1199   jsize len = JvGetStringUTFLength (string);
1200   try
1201     {
1202       char *r = (char *) _Jv_Malloc (len + 1);
1203       JvGetStringUTFRegion (string, 0, len, r);
1204       r[len] = '\0';
1205
1206       if (isCopy)
1207         *isCopy = true;
1208
1209       return (const char *) r;
1210     }
1211   catch (jthrowable t)
1212     {
1213       env->ex = t;
1214       return NULL;
1215     }
1216 }
1217
1218 static void
1219 _Jv_JNI_ReleaseStringUTFChars (JNIEnv *, jstring, const char *utf)
1220 {
1221   _Jv_Free ((void *) utf);
1222 }
1223
1224 static void
1225 _Jv_JNI_GetStringRegion (JNIEnv *env, jstring string, jsize start, jsize len,
1226                          jchar *buf)
1227 {
1228   jchar *result = _Jv_GetStringChars (string);
1229   if (start < 0 || start > string->length ()
1230       || len < 0 || start + len > string->length ())
1231     {
1232       try
1233         {
1234           env->ex = new java::lang::StringIndexOutOfBoundsException ();
1235         }
1236       catch (jthrowable t)
1237         {
1238           env->ex = t;
1239         }
1240     }
1241   else
1242     memcpy (buf, &result[start], len * sizeof (jchar));
1243 }
1244
1245 static void
1246 _Jv_JNI_GetStringUTFRegion (JNIEnv *env, jstring str, jsize start,
1247                             jsize len, char *buf)
1248 {
1249   if (start < 0 || start > str->length ()
1250       || len < 0 || start + len > str->length ())
1251     {
1252       try
1253         {
1254           env->ex = new java::lang::StringIndexOutOfBoundsException ();
1255         }
1256       catch (jthrowable t)
1257         {
1258           env->ex = t;
1259         }
1260     }
1261   else
1262     _Jv_GetStringUTFRegion (str, start, len, buf);
1263 }
1264
1265 static const jchar *
1266 _Jv_JNI_GetStringCritical (JNIEnv *, jstring str, jboolean *isCopy)
1267 {
1268   jchar *result = _Jv_GetStringChars (str);
1269   if (isCopy)
1270     *isCopy = false;
1271   return result;
1272 }
1273
1274 static void
1275 _Jv_JNI_ReleaseStringCritical (JNIEnv *, jstring, const jchar *)
1276 {
1277   // Nothing.
1278 }
1279
1280 static jsize
1281 _Jv_JNI_GetArrayLength (JNIEnv *, jarray array)
1282 {
1283   return array->length;
1284 }
1285
1286 static jarray
1287 _Jv_JNI_NewObjectArray (JNIEnv *env, jsize length, jclass elementClass,
1288                         jobject init)
1289 {
1290   try
1291     {
1292       jarray result = JvNewObjectArray (length, elementClass, init);
1293       return (jarray) wrap_value (env, result);
1294     }
1295   catch (jthrowable t)
1296     {
1297       env->ex = t;
1298       return NULL;
1299     }
1300 }
1301
1302 static jobject
1303 _Jv_JNI_GetObjectArrayElement (JNIEnv *env, jobjectArray array, jsize index)
1304 {
1305   jobject *elts = elements (array);
1306   return wrap_value (env, elts[index]);
1307 }
1308
1309 static void
1310 _Jv_JNI_SetObjectArrayElement (JNIEnv *env, jobjectArray array, jsize index,
1311                                jobject value)
1312 {
1313   try
1314     {
1315       _Jv_CheckArrayStore (array, value);
1316       jobject *elts = elements (array);
1317       elts[index] = value;
1318     }
1319   catch (jthrowable t)
1320     {
1321       env->ex = t;
1322     }
1323 }
1324
1325 template<typename T, jclass K>
1326 static JArray<T> *
1327 _Jv_JNI_NewPrimitiveArray (JNIEnv *env, jsize length)
1328 {
1329   try
1330     {
1331       return (JArray<T> *) wrap_value (env, _Jv_NewPrimArray (K, length));
1332     }
1333   catch (jthrowable t)
1334     {
1335       env->ex = t;
1336       return NULL;
1337     }
1338 }
1339
1340 template<typename T>
1341 static T *
1342 _Jv_JNI_GetPrimitiveArrayElements (JNIEnv *, JArray<T> *array,
1343                                    jboolean *isCopy)
1344 {
1345   T *elts = elements (array);
1346   if (isCopy)
1347     {
1348       // We elect never to copy.
1349       *isCopy = false;
1350     }
1351   mark_for_gc (array, global_ref_table);
1352   return elts;
1353 }
1354
1355 template<typename T>
1356 static void
1357 _Jv_JNI_ReleasePrimitiveArrayElements (JNIEnv *, JArray<T> *array,
1358                                        T *, jint /* mode */)
1359 {
1360   // Note that we ignore MODE.  We can do this because we never copy
1361   // the array elements.  My reading of the JNI documentation is that
1362   // this is an option for the implementor.
1363   unmark_for_gc (array, global_ref_table);
1364 }
1365
1366 template<typename T>
1367 static void
1368 _Jv_JNI_GetPrimitiveArrayRegion (JNIEnv *env, JArray<T> *array,
1369                                  jsize start, jsize len,
1370                                  T *buf)
1371 {
1372   // The cast to unsigned lets us save a comparison.
1373   if (start < 0 || len < 0
1374       || (unsigned long) (start + len) > (unsigned long) array->length)
1375     {
1376       try
1377         {
1378           // FIXME: index.
1379           env->ex = new java::lang::ArrayIndexOutOfBoundsException ();
1380         }
1381       catch (jthrowable t)
1382         {
1383           // Could have thown out of memory error.
1384           env->ex = t;
1385         }
1386     }
1387   else
1388     {
1389       T *elts = elements (array) + start;
1390       memcpy (buf, elts, len * sizeof (T));
1391     }
1392 }
1393
1394 template<typename T>
1395 static void
1396 _Jv_JNI_SetPrimitiveArrayRegion (JNIEnv *env, JArray<T> *array, 
1397                                  jsize start, jsize len, T *buf)
1398 {
1399   // The cast to unsigned lets us save a comparison.
1400   if (start < 0 || len < 0
1401       || (unsigned long) (start + len) > (unsigned long) array->length)
1402     {
1403       try
1404         {
1405           // FIXME: index.
1406           env->ex = new java::lang::ArrayIndexOutOfBoundsException ();
1407         }
1408       catch (jthrowable t)
1409         {
1410           env->ex = t;
1411         }
1412     }
1413   else
1414     {
1415       T *elts = elements (array) + start;
1416       memcpy (elts, buf, len * sizeof (T));
1417     }
1418 }
1419
1420 static void *
1421 _Jv_JNI_GetPrimitiveArrayCritical (JNIEnv *, jarray array,
1422                                    jboolean *isCopy)
1423 {
1424   // FIXME: does this work?
1425   jclass klass = array->getClass()->getComponentType();
1426   JvAssert (klass->isPrimitive ());
1427   char *r = _Jv_GetArrayElementFromElementType (array, klass);
1428   if (isCopy)
1429     *isCopy = false;
1430   return r;
1431 }
1432
1433 static void
1434 _Jv_JNI_ReleasePrimitiveArrayCritical (JNIEnv *, jarray, void *, jint)
1435 {
1436   // Nothing.
1437 }
1438
1439 static jint
1440 _Jv_JNI_MonitorEnter (JNIEnv *env, jobject obj)
1441 {
1442   try
1443     {
1444       _Jv_MonitorEnter (obj);
1445       return 0;
1446     }
1447   catch (jthrowable t)
1448     {
1449       env->ex = t;
1450     }
1451   return JNI_ERR;
1452 }
1453
1454 static jint
1455 _Jv_JNI_MonitorExit (JNIEnv *env, jobject obj)
1456 {
1457   try
1458     {
1459       _Jv_MonitorExit (obj);
1460       return 0;
1461     }
1462   catch (jthrowable t)
1463     {
1464       env->ex = t;
1465     }
1466   return JNI_ERR;
1467 }
1468
1469 // JDK 1.2
1470 jobject
1471 _Jv_JNI_ToReflectedField (JNIEnv *env, jclass cls, jfieldID fieldID,
1472                           jboolean)
1473 {
1474   try
1475     {
1476       java::lang::reflect::Field *field = new java::lang::reflect::Field();
1477       field->declaringClass = cls;
1478       field->offset = (char*) fieldID - (char *) cls->fields;
1479       field->name = _Jv_NewStringUtf8Const (fieldID->getNameUtf8Const (cls));
1480       return wrap_value (env, field);
1481     }
1482   catch (jthrowable t)
1483     {
1484       env->ex = t;
1485     }
1486   return NULL;
1487 }
1488
1489 // JDK 1.2
1490 static jfieldID
1491 _Jv_JNI_FromReflectedField (JNIEnv *, jobject f)
1492 {
1493   using namespace java::lang::reflect;
1494
1495   Field *field = reinterpret_cast<Field *> (f);
1496   return _Jv_FromReflectedField (field);
1497 }
1498
1499 jobject
1500 _Jv_JNI_ToReflectedMethod (JNIEnv *env, jclass klass, jmethodID id,
1501                            jboolean)
1502 {
1503   using namespace java::lang::reflect;
1504
1505   // FIXME.
1506   static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("<init>", 6);
1507
1508   jobject result = NULL;
1509
1510   try
1511     {
1512       if (_Jv_equalUtf8Consts (id->name, init_name))
1513         {
1514           // A constructor.
1515           Constructor *cons = new Constructor ();
1516           cons->offset = (char *) id - (char *) &klass->methods;
1517           cons->declaringClass = klass;
1518           result = cons;
1519         }
1520       else
1521         {
1522           Method *meth = new Method ();
1523           meth->offset = (char *) id - (char *) &klass->methods;
1524           meth->declaringClass = klass;
1525           result = meth;
1526         }
1527     }
1528   catch (jthrowable t)
1529     {
1530       env->ex = t;
1531     }
1532
1533   return wrap_value (env, result);
1534 }
1535
1536 static jmethodID
1537 _Jv_JNI_FromReflectedMethod (JNIEnv *, jobject method)
1538 {
1539   using namespace java::lang::reflect;
1540   if (Method::class$.isInstance (method))
1541     return _Jv_FromReflectedMethod (reinterpret_cast<Method *> (method));
1542   return
1543     _Jv_FromReflectedConstructor (reinterpret_cast<Constructor *> (method));
1544 }
1545
1546 static jint
1547 _Jv_JNI_RegisterNatives (JNIEnv *env, jclass k,
1548                          const JNINativeMethod *methods,
1549                          jint nMethods)
1550 {
1551 #ifdef INTERPRETER
1552   // For now, this only matters for interpreted methods.  FIXME.
1553   if (! _Jv_IsInterpretedClass (k))
1554     {
1555       // FIXME: throw exception.
1556       return JNI_ERR;
1557     }
1558   _Jv_InterpClass *klass = reinterpret_cast<_Jv_InterpClass *> (k);
1559
1560   // Look at each descriptor given us, and find the corresponding
1561   // method in the class.
1562   for (int j = 0; j < nMethods; ++j)
1563     {
1564       bool found = false;
1565
1566       _Jv_MethodBase **imeths = _Jv_GetFirstMethod (klass);
1567       for (int i = 0; i < JvNumMethods (klass); ++i)
1568         {
1569           _Jv_MethodBase *meth = imeths[i];
1570           _Jv_Method *self = meth->get_method ();
1571
1572           if (! strcmp (self->name->data, methods[j].name)
1573               && ! strcmp (self->signature->data, methods[j].signature))
1574             {
1575               if (! (self->accflags
1576                      & java::lang::reflect::Modifier::NATIVE))
1577                 break;
1578
1579               // Found a match that is native.
1580               _Jv_JNIMethod *jmeth = reinterpret_cast<_Jv_JNIMethod *> (meth);
1581               jmeth->set_function (methods[i].fnPtr);
1582               found = true;
1583               break;
1584             }
1585         }
1586
1587       if (! found)
1588         {
1589           jstring m = JvNewStringUTF (methods[j].name);
1590           try
1591             {
1592               env->ex =new java::lang::NoSuchMethodError (m);
1593             }
1594           catch (jthrowable t)
1595             {
1596               env->ex = t;
1597             }
1598           return JNI_ERR;
1599         }
1600     }
1601
1602   return JNI_OK;
1603 #else /* INTERPRETER */
1604   return JNI_ERR;
1605 #endif /* INTERPRETER */
1606 }
1607
1608 static jint
1609 _Jv_JNI_UnregisterNatives (JNIEnv *, jclass)
1610 {
1611   return JNI_ERR;
1612 }
1613
1614 \f
1615
1616 // Add a character to the buffer, encoding properly.
1617 static void
1618 add_char (char *buf, jchar c, int *here)
1619 {
1620   if (c == '_')
1621     {
1622       buf[(*here)++] = '_';
1623       buf[(*here)++] = '1';
1624     }
1625   else if (c == ';')
1626     {
1627       buf[(*here)++] = '_';
1628       buf[(*here)++] = '2';
1629     }
1630   else if (c == '[')
1631     {
1632       buf[(*here)++] = '_';
1633       buf[(*here)++] = '3';
1634     }
1635
1636   // Also check for `.' here because we might be passed an internal
1637   // qualified class name like `foo.bar'.
1638   else if (c == '/' || c == '.')
1639     buf[(*here)++] = '_';
1640   else if ((c >= '0' && c <= '9')
1641            || (c >= 'a' && c <= 'z')
1642            || (c >= 'A' && c <= 'Z'))
1643     buf[(*here)++] = (char) c;
1644   else
1645     {
1646       // "Unicode" character.
1647       buf[(*here)++] = '_';
1648       buf[(*here)++] = '0';
1649       for (int i = 0; i < 4; ++i)
1650         {
1651           int val = c & 0x0f;
1652           buf[(*here) + 3 - i] = (val > 10) ? ('a' + val - 10) : ('0' + val);
1653           c >>= 4;
1654         }
1655       *here += 4;
1656     }
1657 }
1658
1659 // Compute a mangled name for a native function.  This computes the
1660 // long name, and also returns an index which indicates where a NUL
1661 // can be placed to create the short name.  This function assumes that
1662 // the buffer is large enough for its results.
1663 static void
1664 mangled_name (jclass klass, _Jv_Utf8Const *func_name,
1665               _Jv_Utf8Const *signature, char *buf, int *long_start)
1666 {
1667   strcpy (buf, "Java_");
1668   int here = 5;
1669
1670   // Add fully qualified class name.
1671   jchar *chars = _Jv_GetStringChars (klass->getName ());
1672   jint len = klass->getName ()->length ();
1673   for (int i = 0; i < len; ++i)
1674     add_char (buf, chars[i], &here);
1675
1676   // Don't use add_char because we need a literal `_'.
1677   buf[here++] = '_';
1678
1679   const unsigned char *fn = (const unsigned char *) func_name->data;
1680   const unsigned char *limit = fn + func_name->length;
1681   for (int i = 0; ; ++i)
1682     {
1683       int ch = UTF8_GET (fn, limit);
1684       if (ch < 0)
1685         break;
1686       add_char (buf, ch, &here);
1687     }
1688
1689   // This is where the long signature begins.
1690   *long_start = here;
1691   buf[here++] = '_';
1692   buf[here++] = '_';
1693
1694   const unsigned char *sig = (const unsigned char *) signature->data;
1695   limit = sig + signature->length;
1696   JvAssert (sig[0] == '(');
1697   ++sig;
1698   while (1)
1699     {
1700       int ch = UTF8_GET (sig, limit);
1701       if (ch == ')' || ch < 0)
1702         break;
1703       add_char (buf, ch, &here);
1704     }
1705
1706   buf[here] = '\0';
1707 }
1708
1709 // Return the current thread's JNIEnv; if one does not exist, create
1710 // it.  Also create a new system frame for use.  This is `extern "C"'
1711 // because the compiler calls it.
1712 extern "C" JNIEnv *
1713 _Jv_GetJNIEnvNewFrame (jclass klass)
1714 {
1715   JNIEnv *env = _Jv_GetCurrentJNIEnv ();
1716   if (env == NULL)
1717     {
1718       env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv));
1719       env->p = &_Jv_JNIFunctions;
1720       env->ex = NULL;
1721       env->klass = klass;
1722       env->locals = NULL;
1723
1724       _Jv_SetCurrentJNIEnv (env);
1725     }
1726
1727   _Jv_JNI_LocalFrame *frame
1728     = (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame)
1729                                                   + (FRAME_SIZE
1730                                                      * sizeof (jobject)));
1731
1732   frame->marker = MARK_SYSTEM;
1733   frame->size = FRAME_SIZE;
1734   frame->next = env->locals;
1735   env->locals = frame;
1736
1737   for (int i = 0; i < frame->size; ++i)
1738     frame->vec[i] = NULL;
1739
1740   return env;
1741 }
1742
1743 // Return the function which implements a particular JNI method.  If
1744 // we can't find the function, we throw the appropriate exception.
1745 // This is `extern "C"' because the compiler uses it.
1746 extern "C" void *
1747 _Jv_LookupJNIMethod (jclass klass, _Jv_Utf8Const *name,
1748                      _Jv_Utf8Const *signature)
1749 {
1750   char buf[10 + 6 * (name->length + signature->length)];
1751   int long_start;
1752   void *function;
1753
1754   mangled_name (klass, name, signature, buf, &long_start);
1755   char c = buf[long_start];
1756   buf[long_start] = '\0';
1757   function = _Jv_FindSymbolInExecutable (buf);
1758   if (function == NULL)
1759     {
1760       buf[long_start] = c;
1761       function = _Jv_FindSymbolInExecutable (buf);
1762       if (function == NULL)
1763         {
1764           jstring str = JvNewStringUTF (name->data);
1765           throw new java::lang::AbstractMethodError (str);
1766         }
1767     }
1768
1769   return function;
1770 }
1771
1772 #ifdef INTERPRETER
1773
1774 // This function is the stub which is used to turn an ordinary (CNI)
1775 // method call into a JNI call.
1776 void
1777 _Jv_JNIMethod::call (ffi_cif *, void *ret, ffi_raw *args, void *__this)
1778 {
1779   _Jv_JNIMethod* _this = (_Jv_JNIMethod *) __this;
1780
1781   JNIEnv *env = _Jv_GetJNIEnvNewFrame (_this->defining_class);
1782
1783   // FIXME: we should mark every reference parameter as a local.  For
1784   // now we assume a conservative GC, and we assume that the
1785   // references are on the stack somewhere.
1786
1787   // We cache the value that we find, of course, but if we don't find
1788   // a value we don't cache that fact -- we might subsequently load a
1789   // library which finds the function in question.
1790   if (_this->function == NULL)
1791     _this->function = _Jv_LookupJNIMethod (_this->defining_class,
1792                                            _this->self->name,
1793                                            _this->self->signature);
1794
1795   JvAssert (_this->args_raw_size % sizeof (ffi_raw) == 0);
1796   ffi_raw real_args[2 + _this->args_raw_size / sizeof (ffi_raw)];
1797   int offset = 0;
1798
1799   // First argument is always the environment pointer.
1800   real_args[offset++].ptr = env;
1801
1802   // For a static method, we pass in the Class.  For non-static
1803   // methods, the `this' argument is already handled.
1804   if ((_this->self->accflags & java::lang::reflect::Modifier::STATIC))
1805     real_args[offset++].ptr = _this->defining_class;
1806
1807   // Copy over passed-in arguments.
1808   memcpy (&real_args[offset], args, _this->args_raw_size);
1809
1810   // The actual call to the JNI function.
1811   ffi_raw_call (&_this->jni_cif, (void (*)()) _this->function,
1812                 ret, real_args);
1813
1814   _Jv_JNI_PopSystemFrame (env);
1815 }
1816
1817 #endif /* INTERPRETER */
1818
1819 \f
1820
1821 //
1822 // Invocation API.
1823 //
1824
1825 // An internal helper function.
1826 static jint
1827 _Jv_JNI_AttachCurrentThread (JavaVM *, jstring name, void **penv, void *args)
1828 {
1829   JavaVMAttachArgs *attach = reinterpret_cast<JavaVMAttachArgs *> (args);
1830   java::lang::ThreadGroup *group = NULL;
1831
1832   if (attach)
1833     {
1834       // FIXME: do we really want to support 1.1?
1835       if (attach->version != JNI_VERSION_1_2
1836           && attach->version != JNI_VERSION_1_1)
1837         return JNI_EVERSION;
1838
1839       JvAssert (java::lang::ThreadGroup::class$.isInstance (attach->group));
1840       group = reinterpret_cast<java::lang::ThreadGroup *> (attach->group);
1841     }
1842
1843   // Attaching an already-attached thread is a no-op.
1844   if (_Jv_GetCurrentJNIEnv () != NULL)
1845     return 0;
1846
1847   JNIEnv *env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv));
1848   if (env == NULL)
1849     return JNI_ERR;
1850   env->p = &_Jv_JNIFunctions;
1851   env->ex = NULL;
1852   env->klass = NULL;
1853   env->locals
1854     = (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame)
1855                                                   + (FRAME_SIZE
1856                                                      * sizeof (jobject)));
1857   if (env->locals == NULL)
1858     {
1859       _Jv_Free (env);
1860       return JNI_ERR;
1861     }
1862   *penv = reinterpret_cast<void *> (env);
1863
1864   // This thread might already be a Java thread -- this function might
1865   // have been called simply to set the new JNIEnv.
1866   if (_Jv_ThreadCurrent () == NULL)
1867     {
1868       try
1869         {
1870           _Jv_AttachCurrentThread (name, group);
1871         }
1872       catch (jthrowable t)
1873         {
1874           return JNI_ERR;
1875         }
1876     }
1877   _Jv_SetCurrentJNIEnv (env);
1878
1879   return 0;
1880 }
1881
1882 // This is the one actually used by JNI.
1883 static jint
1884 _Jv_JNI_AttachCurrentThread (JavaVM *vm, void **penv, void *args)
1885 {
1886   return _Jv_JNI_AttachCurrentThread (vm, NULL, penv, args);
1887 }
1888
1889 static jint
1890 _Jv_JNI_DestroyJavaVM (JavaVM *vm)
1891 {
1892   JvAssert (the_vm && vm == the_vm);
1893
1894   JNIEnv *env;
1895   if (_Jv_ThreadCurrent () != NULL)
1896     {
1897       jstring main_name;
1898       // This sucks.
1899       try
1900         {
1901           main_name = JvNewStringLatin1 ("main");
1902         }
1903       catch (jthrowable t)
1904         {
1905           return JNI_ERR;
1906         }
1907
1908       jint r = _Jv_JNI_AttachCurrentThread (vm,
1909                                             main_name,
1910                                             reinterpret_cast<void **> (&env),
1911                                             NULL);
1912       if (r < 0)
1913         return r;
1914     }
1915   else
1916     env = _Jv_GetCurrentJNIEnv ();
1917
1918   _Jv_ThreadWait ();
1919
1920   // Docs say that this always returns an error code.
1921   return JNI_ERR;
1922 }
1923
1924 jint
1925 _Jv_JNI_DetachCurrentThread (JavaVM *)
1926 {
1927   jint code = _Jv_DetachCurrentThread ();
1928   return code  ? JNI_EDETACHED : 0;
1929 }
1930
1931 static jint
1932 _Jv_JNI_GetEnv (JavaVM *, void **penv, jint version)
1933 {
1934   if (_Jv_ThreadCurrent () == NULL)
1935     {
1936       *penv = NULL;
1937       return JNI_EDETACHED;
1938     }
1939
1940 #ifdef ENABLE_JVMPI
1941   // Handle JVMPI requests.
1942   if (version == JVMPI_VERSION_1)
1943     {
1944       *penv = (void *) &_Jv_JVMPI_Interface;
1945       return 0;
1946     }
1947 #endif
1948
1949   // FIXME: do we really want to support 1.1?
1950   if (version != JNI_VERSION_1_2 && version != JNI_VERSION_1_1)
1951     {
1952       *penv = NULL;
1953       return JNI_EVERSION;
1954     }
1955
1956   *penv = (void *) _Jv_GetCurrentJNIEnv ();
1957   return 0;
1958 }
1959
1960 jint
1961 JNI_GetDefaultJavaVMInitArgs (void *args)
1962 {
1963   jint version = * (jint *) args;
1964   // Here we only support 1.2.
1965   if (version != JNI_VERSION_1_2)
1966     return JNI_EVERSION;
1967
1968   JavaVMInitArgs *ia = reinterpret_cast<JavaVMInitArgs *> (args);
1969   ia->version = JNI_VERSION_1_2;
1970   ia->nOptions = 0;
1971   ia->options = NULL;
1972   ia->ignoreUnrecognized = true;
1973
1974   return 0;
1975 }
1976
1977 jint
1978 JNI_CreateJavaVM (JavaVM **vm, void **penv, void *args)
1979 {
1980   JvAssert (! the_vm);
1981   // FIXME: synchronize
1982   JavaVM *nvm = (JavaVM *) _Jv_MallocUnchecked (sizeof (JavaVM));
1983   if (nvm == NULL)
1984     return JNI_ERR;
1985   nvm->functions = &_Jv_JNI_InvokeFunctions;
1986
1987   // Parse the arguments.
1988   if (args != NULL)
1989     {
1990       jint version = * (jint *) args;
1991       // We only support 1.2.
1992       if (version != JNI_VERSION_1_2)
1993         return JNI_EVERSION;
1994       JavaVMInitArgs *ia = reinterpret_cast<JavaVMInitArgs *> (args);
1995       for (int i = 0; i < ia->nOptions; ++i)
1996         {
1997           if (! strcmp (ia->options[i].optionString, "vfprintf")
1998               || ! strcmp (ia->options[i].optionString, "exit")
1999               || ! strcmp (ia->options[i].optionString, "abort"))
2000             {
2001               // We are required to recognize these, but for now we
2002               // don't handle them in any way.  FIXME.
2003               continue;
2004             }
2005           else if (! strncmp (ia->options[i].optionString,
2006                               "-verbose", sizeof ("-verbose") - 1))
2007             {
2008               // We don't do anything with this option either.  We
2009               // might want to make sure the argument is valid, but we
2010               // don't really care all that much for now.
2011               continue;
2012             }
2013           else if (! strncmp (ia->options[i].optionString, "-D", 2))
2014             {
2015               // FIXME.
2016               continue;
2017             }
2018           else if (ia->ignoreUnrecognized)
2019             {
2020               if (ia->options[i].optionString[0] == '_'
2021                   || ! strncmp (ia->options[i].optionString, "-X", 2))
2022                 continue;
2023             }
2024
2025           return JNI_ERR;
2026         }
2027     }
2028
2029   jint r =_Jv_JNI_AttachCurrentThread (nvm, penv, NULL);
2030   if (r < 0)
2031     return r;
2032
2033   the_vm = nvm;
2034   *vm = the_vm;
2035   return 0;
2036 }
2037
2038 jint
2039 JNI_GetCreatedJavaVMs (JavaVM **vm_buffer, jsize buf_len, jsize *n_vms)
2040 {
2041   if (buf_len <= 0)
2042     return JNI_ERR;
2043
2044   // We only support a single VM.
2045   if (the_vm != NULL)
2046     {
2047       vm_buffer[0] = the_vm;
2048       *n_vms = 1;
2049     }
2050   else
2051     *n_vms = 0;
2052   return 0;
2053 }
2054
2055 JavaVM *
2056 _Jv_GetJavaVM ()
2057 {
2058   // FIXME: synchronize
2059   if (! the_vm)
2060     {
2061       JavaVM *nvm = (JavaVM *) _Jv_MallocUnchecked (sizeof (JavaVM));
2062       if (nvm != NULL)
2063         nvm->functions = &_Jv_JNI_InvokeFunctions;
2064       the_vm = nvm;
2065     }
2066
2067   // If this is a Java thread, we want to make sure it has an
2068   // associated JNIEnv.
2069   if (_Jv_ThreadCurrent () != NULL)
2070     {
2071       void *ignore;
2072       _Jv_JNI_AttachCurrentThread (the_vm, &ignore, NULL);
2073     }
2074
2075   return the_vm;
2076 }
2077
2078 static jint
2079 _Jv_JNI_GetJavaVM (JNIEnv *, JavaVM **vm)
2080 {
2081   *vm = _Jv_GetJavaVM ();
2082   return *vm == NULL ? JNI_ERR : JNI_OK;
2083 }
2084
2085 \f
2086
2087 #define NOT_IMPL NULL
2088 #define RESERVED NULL
2089
2090 struct JNINativeInterface _Jv_JNIFunctions =
2091 {
2092   RESERVED,
2093   RESERVED,
2094   RESERVED,
2095   RESERVED,
2096   _Jv_JNI_GetVersion,           // GetVersion
2097   _Jv_JNI_DefineClass,          // DefineClass
2098   _Jv_JNI_FindClass,            // FindClass
2099   _Jv_JNI_FromReflectedMethod,  // FromReflectedMethod
2100   _Jv_JNI_FromReflectedField,   // FromReflectedField
2101   _Jv_JNI_ToReflectedMethod,    // ToReflectedMethod
2102   _Jv_JNI_GetSuperclass,        // GetSuperclass
2103   _Jv_JNI_IsAssignableFrom,     // IsAssignableFrom
2104   _Jv_JNI_ToReflectedField,     // ToReflectedField
2105   _Jv_JNI_Throw,                // Throw
2106   _Jv_JNI_ThrowNew,             // ThrowNew
2107   _Jv_JNI_ExceptionOccurred,    // ExceptionOccurred
2108   _Jv_JNI_ExceptionDescribe,    // ExceptionDescribe
2109   _Jv_JNI_ExceptionClear,       // ExceptionClear
2110   _Jv_JNI_FatalError,           // FatalError
2111
2112   _Jv_JNI_PushLocalFrame,       // PushLocalFrame
2113   _Jv_JNI_PopLocalFrame,        // PopLocalFrame
2114   _Jv_JNI_NewGlobalRef,         // NewGlobalRef
2115   _Jv_JNI_DeleteGlobalRef,      // DeleteGlobalRef
2116   _Jv_JNI_DeleteLocalRef,       // DeleteLocalRef
2117
2118   _Jv_JNI_IsSameObject,         // IsSameObject
2119
2120   _Jv_JNI_NewLocalRef,          // NewLocalRef
2121   _Jv_JNI_EnsureLocalCapacity,  // EnsureLocalCapacity
2122
2123   _Jv_JNI_AllocObject,              // AllocObject
2124   _Jv_JNI_NewObject,                // NewObject
2125   _Jv_JNI_NewObjectV,               // NewObjectV
2126   _Jv_JNI_NewObjectA,               // NewObjectA
2127   _Jv_JNI_GetObjectClass,           // GetObjectClass
2128   _Jv_JNI_IsInstanceOf,             // IsInstanceOf
2129   _Jv_JNI_GetAnyMethodID<false>,    // GetMethodID
2130
2131   _Jv_JNI_CallMethod<jobject>,          // CallObjectMethod
2132   _Jv_JNI_CallMethodV<jobject>,         // CallObjectMethodV
2133   _Jv_JNI_CallMethodA<jobject>,         // CallObjectMethodA
2134   _Jv_JNI_CallMethod<jboolean>,         // CallBooleanMethod
2135   _Jv_JNI_CallMethodV<jboolean>,        // CallBooleanMethodV
2136   _Jv_JNI_CallMethodA<jboolean>,        // CallBooleanMethodA
2137   _Jv_JNI_CallMethod<jbyte>,            // CallByteMethod
2138   _Jv_JNI_CallMethodV<jbyte>,           // CallByteMethodV
2139   _Jv_JNI_CallMethodA<jbyte>,           // CallByteMethodA
2140   _Jv_JNI_CallMethod<jchar>,            // CallCharMethod
2141   _Jv_JNI_CallMethodV<jchar>,           // CallCharMethodV
2142   _Jv_JNI_CallMethodA<jchar>,           // CallCharMethodA
2143   _Jv_JNI_CallMethod<jshort>,           // CallShortMethod
2144   _Jv_JNI_CallMethodV<jshort>,          // CallShortMethodV
2145   _Jv_JNI_CallMethodA<jshort>,          // CallShortMethodA
2146   _Jv_JNI_CallMethod<jint>,             // CallIntMethod
2147   _Jv_JNI_CallMethodV<jint>,            // CallIntMethodV
2148   _Jv_JNI_CallMethodA<jint>,            // CallIntMethodA
2149   _Jv_JNI_CallMethod<jlong>,            // CallLongMethod
2150   _Jv_JNI_CallMethodV<jlong>,           // CallLongMethodV
2151   _Jv_JNI_CallMethodA<jlong>,           // CallLongMethodA
2152   _Jv_JNI_CallMethod<jfloat>,           // CallFloatMethod
2153   _Jv_JNI_CallMethodV<jfloat>,          // CallFloatMethodV
2154   _Jv_JNI_CallMethodA<jfloat>,          // CallFloatMethodA
2155   _Jv_JNI_CallMethod<jdouble>,          // CallDoubleMethod
2156   _Jv_JNI_CallMethodV<jdouble>,         // CallDoubleMethodV
2157   _Jv_JNI_CallMethodA<jdouble>,         // CallDoubleMethodA
2158   _Jv_JNI_CallVoidMethod,               // CallVoidMethod
2159   _Jv_JNI_CallVoidMethodV,              // CallVoidMethodV
2160   _Jv_JNI_CallVoidMethodA,              // CallVoidMethodA
2161
2162   // Nonvirtual method invocation functions follow.
2163   _Jv_JNI_CallAnyMethod<jobject, nonvirtual>,   // CallNonvirtualObjectMethod
2164   _Jv_JNI_CallAnyMethodV<jobject, nonvirtual>,  // CallNonvirtualObjectMethodV
2165   _Jv_JNI_CallAnyMethodA<jobject, nonvirtual>,  // CallNonvirtualObjectMethodA
2166   _Jv_JNI_CallAnyMethod<jboolean, nonvirtual>,  // CallNonvirtualBooleanMethod
2167   _Jv_JNI_CallAnyMethodV<jboolean, nonvirtual>, // CallNonvirtualBooleanMethodV
2168   _Jv_JNI_CallAnyMethodA<jboolean, nonvirtual>, // CallNonvirtualBooleanMethodA
2169   _Jv_JNI_CallAnyMethod<jbyte, nonvirtual>,     // CallNonvirtualByteMethod
2170   _Jv_JNI_CallAnyMethodV<jbyte, nonvirtual>,    // CallNonvirtualByteMethodV
2171   _Jv_JNI_CallAnyMethodA<jbyte, nonvirtual>,    // CallNonvirtualByteMethodA
2172   _Jv_JNI_CallAnyMethod<jchar, nonvirtual>,     // CallNonvirtualCharMethod
2173   _Jv_JNI_CallAnyMethodV<jchar, nonvirtual>,    // CallNonvirtualCharMethodV
2174   _Jv_JNI_CallAnyMethodA<jchar, nonvirtual>,    // CallNonvirtualCharMethodA
2175   _Jv_JNI_CallAnyMethod<jshort, nonvirtual>,    // CallNonvirtualShortMethod
2176   _Jv_JNI_CallAnyMethodV<jshort, nonvirtual>,   // CallNonvirtualShortMethodV
2177   _Jv_JNI_CallAnyMethodA<jshort, nonvirtual>,   // CallNonvirtualShortMethodA
2178   _Jv_JNI_CallAnyMethod<jint, nonvirtual>,      // CallNonvirtualIntMethod
2179   _Jv_JNI_CallAnyMethodV<jint, nonvirtual>,     // CallNonvirtualIntMethodV
2180   _Jv_JNI_CallAnyMethodA<jint, nonvirtual>,     // CallNonvirtualIntMethodA
2181   _Jv_JNI_CallAnyMethod<jlong, nonvirtual>,     // CallNonvirtualLongMethod
2182   _Jv_JNI_CallAnyMethodV<jlong, nonvirtual>,    // CallNonvirtualLongMethodV
2183   _Jv_JNI_CallAnyMethodA<jlong, nonvirtual>,    // CallNonvirtualLongMethodA
2184   _Jv_JNI_CallAnyMethod<jfloat, nonvirtual>,    // CallNonvirtualFloatMethod
2185   _Jv_JNI_CallAnyMethodV<jfloat, nonvirtual>,   // CallNonvirtualFloatMethodV
2186   _Jv_JNI_CallAnyMethodA<jfloat, nonvirtual>,   // CallNonvirtualFloatMethodA
2187   _Jv_JNI_CallAnyMethod<jdouble, nonvirtual>,   // CallNonvirtualDoubleMethod
2188   _Jv_JNI_CallAnyMethodV<jdouble, nonvirtual>,  // CallNonvirtualDoubleMethodV
2189   _Jv_JNI_CallAnyMethodA<jdouble, nonvirtual>,  // CallNonvirtualDoubleMethodA
2190   _Jv_JNI_CallAnyVoidMethod<nonvirtual>,        // CallNonvirtualVoidMethod
2191   _Jv_JNI_CallAnyVoidMethodV<nonvirtual>,       // CallNonvirtualVoidMethodV
2192   _Jv_JNI_CallAnyVoidMethodA<nonvirtual>,       // CallNonvirtualVoidMethodA
2193
2194   _Jv_JNI_GetAnyFieldID<false>, // GetFieldID
2195   _Jv_JNI_GetField<jobject>,    // GetObjectField
2196   _Jv_JNI_GetField<jboolean>,   // GetBooleanField
2197   _Jv_JNI_GetField<jbyte>,      // GetByteField
2198   _Jv_JNI_GetField<jchar>,      // GetCharField
2199   _Jv_JNI_GetField<jshort>,     // GetShortField
2200   _Jv_JNI_GetField<jint>,       // GetIntField
2201   _Jv_JNI_GetField<jlong>,      // GetLongField
2202   _Jv_JNI_GetField<jfloat>,     // GetFloatField
2203   _Jv_JNI_GetField<jdouble>,    // GetDoubleField
2204   _Jv_JNI_SetField,             // SetObjectField
2205   _Jv_JNI_SetField,             // SetBooleanField
2206   _Jv_JNI_SetField,             // SetByteField
2207   _Jv_JNI_SetField,             // SetCharField
2208   _Jv_JNI_SetField,             // SetShortField
2209   _Jv_JNI_SetField,             // SetIntField
2210   _Jv_JNI_SetField,             // SetLongField
2211   _Jv_JNI_SetField,             // SetFloatField
2212   _Jv_JNI_SetField,             // SetDoubleField
2213   _Jv_JNI_GetAnyMethodID<true>, // GetStaticMethodID
2214
2215   _Jv_JNI_CallStaticMethod<jobject>,      // CallStaticObjectMethod
2216   _Jv_JNI_CallStaticMethodV<jobject>,     // CallStaticObjectMethodV
2217   _Jv_JNI_CallStaticMethodA<jobject>,     // CallStaticObjectMethodA
2218   _Jv_JNI_CallStaticMethod<jboolean>,     // CallStaticBooleanMethod
2219   _Jv_JNI_CallStaticMethodV<jboolean>,    // CallStaticBooleanMethodV
2220   _Jv_JNI_CallStaticMethodA<jboolean>,    // CallStaticBooleanMethodA
2221   _Jv_JNI_CallStaticMethod<jbyte>,        // CallStaticByteMethod
2222   _Jv_JNI_CallStaticMethodV<jbyte>,       // CallStaticByteMethodV
2223   _Jv_JNI_CallStaticMethodA<jbyte>,       // CallStaticByteMethodA
2224   _Jv_JNI_CallStaticMethod<jchar>,        // CallStaticCharMethod
2225   _Jv_JNI_CallStaticMethodV<jchar>,       // CallStaticCharMethodV
2226   _Jv_JNI_CallStaticMethodA<jchar>,       // CallStaticCharMethodA
2227   _Jv_JNI_CallStaticMethod<jshort>,       // CallStaticShortMethod
2228   _Jv_JNI_CallStaticMethodV<jshort>,      // CallStaticShortMethodV
2229   _Jv_JNI_CallStaticMethodA<jshort>,      // CallStaticShortMethodA
2230   _Jv_JNI_CallStaticMethod<jint>,         // CallStaticIntMethod
2231   _Jv_JNI_CallStaticMethodV<jint>,        // CallStaticIntMethodV
2232   _Jv_JNI_CallStaticMethodA<jint>,        // CallStaticIntMethodA
2233   _Jv_JNI_CallStaticMethod<jlong>,        // CallStaticLongMethod
2234   _Jv_JNI_CallStaticMethodV<jlong>,       // CallStaticLongMethodV
2235   _Jv_JNI_CallStaticMethodA<jlong>,       // CallStaticLongMethodA
2236   _Jv_JNI_CallStaticMethod<jfloat>,       // CallStaticFloatMethod
2237   _Jv_JNI_CallStaticMethodV<jfloat>,      // CallStaticFloatMethodV
2238   _Jv_JNI_CallStaticMethodA<jfloat>,      // CallStaticFloatMethodA
2239   _Jv_JNI_CallStaticMethod<jdouble>,      // CallStaticDoubleMethod
2240   _Jv_JNI_CallStaticMethodV<jdouble>,     // CallStaticDoubleMethodV
2241   _Jv_JNI_CallStaticMethodA<jdouble>,     // CallStaticDoubleMethodA
2242   _Jv_JNI_CallStaticVoidMethod,           // CallStaticVoidMethod
2243   _Jv_JNI_CallStaticVoidMethodV,          // CallStaticVoidMethodV
2244   _Jv_JNI_CallStaticVoidMethodA,          // CallStaticVoidMethodA
2245
2246   _Jv_JNI_GetAnyFieldID<true>,         // GetStaticFieldID
2247   _Jv_JNI_GetStaticField<jobject>,     // GetStaticObjectField
2248   _Jv_JNI_GetStaticField<jboolean>,    // GetStaticBooleanField
2249   _Jv_JNI_GetStaticField<jbyte>,       // GetStaticByteField
2250   _Jv_JNI_GetStaticField<jchar>,       // GetStaticCharField
2251   _Jv_JNI_GetStaticField<jshort>,      // GetStaticShortField
2252   _Jv_JNI_GetStaticField<jint>,        // GetStaticIntField
2253   _Jv_JNI_GetStaticField<jlong>,       // GetStaticLongField
2254   _Jv_JNI_GetStaticField<jfloat>,      // GetStaticFloatField
2255   _Jv_JNI_GetStaticField<jdouble>,     // GetStaticDoubleField
2256   _Jv_JNI_SetStaticField,              // SetStaticObjectField
2257   _Jv_JNI_SetStaticField,              // SetStaticBooleanField
2258   _Jv_JNI_SetStaticField,              // SetStaticByteField
2259   _Jv_JNI_SetStaticField,              // SetStaticCharField
2260   _Jv_JNI_SetStaticField,              // SetStaticShortField
2261   _Jv_JNI_SetStaticField,              // SetStaticIntField
2262   _Jv_JNI_SetStaticField,              // SetStaticLongField
2263   _Jv_JNI_SetStaticField,              // SetStaticFloatField
2264   _Jv_JNI_SetStaticField,              // SetStaticDoubleField
2265   _Jv_JNI_NewString,                   // NewString
2266   _Jv_JNI_GetStringLength,             // GetStringLength
2267   _Jv_JNI_GetStringChars,              // GetStringChars
2268   _Jv_JNI_ReleaseStringChars,          // ReleaseStringChars
2269   _Jv_JNI_NewStringUTF,                // NewStringUTF
2270   _Jv_JNI_GetStringUTFLength,          // GetStringUTFLength
2271   _Jv_JNI_GetStringUTFChars,           // GetStringUTFLength
2272   _Jv_JNI_ReleaseStringUTFChars,       // ReleaseStringUTFChars
2273   _Jv_JNI_GetArrayLength,              // GetArrayLength
2274   _Jv_JNI_NewObjectArray,              // NewObjectArray
2275   _Jv_JNI_GetObjectArrayElement,       // GetObjectArrayElement
2276   _Jv_JNI_SetObjectArrayElement,       // SetObjectArrayElement
2277   _Jv_JNI_NewPrimitiveArray<jboolean, JvPrimClass (boolean)>,
2278                                                             // NewBooleanArray
2279   _Jv_JNI_NewPrimitiveArray<jbyte, JvPrimClass (byte)>,     // NewByteArray
2280   _Jv_JNI_NewPrimitiveArray<jchar, JvPrimClass (char)>,     // NewCharArray
2281   _Jv_JNI_NewPrimitiveArray<jshort, JvPrimClass (short)>,   // NewShortArray
2282   _Jv_JNI_NewPrimitiveArray<jint, JvPrimClass (int)>,       // NewIntArray
2283   _Jv_JNI_NewPrimitiveArray<jlong, JvPrimClass (long)>,     // NewLongArray
2284   _Jv_JNI_NewPrimitiveArray<jfloat, JvPrimClass (float)>,   // NewFloatArray
2285   _Jv_JNI_NewPrimitiveArray<jdouble, JvPrimClass (double)>, // NewDoubleArray
2286   _Jv_JNI_GetPrimitiveArrayElements,        // GetBooleanArrayElements
2287   _Jv_JNI_GetPrimitiveArrayElements,        // GetByteArrayElements
2288   _Jv_JNI_GetPrimitiveArrayElements,        // GetCharArrayElements
2289   _Jv_JNI_GetPrimitiveArrayElements,        // GetShortArrayElements
2290   _Jv_JNI_GetPrimitiveArrayElements,        // GetIntArrayElements
2291   _Jv_JNI_GetPrimitiveArrayElements,        // GetLongArrayElements
2292   _Jv_JNI_GetPrimitiveArrayElements,        // GetFloatArrayElements
2293   _Jv_JNI_GetPrimitiveArrayElements,        // GetDoubleArrayElements
2294   _Jv_JNI_ReleasePrimitiveArrayElements,    // ReleaseBooleanArrayElements
2295   _Jv_JNI_ReleasePrimitiveArrayElements,    // ReleaseByteArrayElements
2296   _Jv_JNI_ReleasePrimitiveArrayElements,    // ReleaseCharArrayElements
2297   _Jv_JNI_ReleasePrimitiveArrayElements,    // ReleaseShortArrayElements
2298   _Jv_JNI_ReleasePrimitiveArrayElements,    // ReleaseIntArrayElements
2299   _Jv_JNI_ReleasePrimitiveArrayElements,    // ReleaseLongArrayElements
2300   _Jv_JNI_ReleasePrimitiveArrayElements,    // ReleaseFloatArrayElements
2301   _Jv_JNI_ReleasePrimitiveArrayElements,    // ReleaseDoubleArrayElements
2302   _Jv_JNI_GetPrimitiveArrayRegion,          // GetBooleanArrayRegion
2303   _Jv_JNI_GetPrimitiveArrayRegion,          // GetByteArrayRegion
2304   _Jv_JNI_GetPrimitiveArrayRegion,          // GetCharArrayRegion
2305   _Jv_JNI_GetPrimitiveArrayRegion,          // GetShortArrayRegion
2306   _Jv_JNI_GetPrimitiveArrayRegion,          // GetIntArrayRegion
2307   _Jv_JNI_GetPrimitiveArrayRegion,          // GetLongArrayRegion
2308   _Jv_JNI_GetPrimitiveArrayRegion,          // GetFloatArrayRegion
2309   _Jv_JNI_GetPrimitiveArrayRegion,          // GetDoubleArrayRegion
2310   _Jv_JNI_SetPrimitiveArrayRegion,          // SetBooleanArrayRegion
2311   _Jv_JNI_SetPrimitiveArrayRegion,          // SetByteArrayRegion
2312   _Jv_JNI_SetPrimitiveArrayRegion,          // SetCharArrayRegion
2313   _Jv_JNI_SetPrimitiveArrayRegion,          // SetShortArrayRegion
2314   _Jv_JNI_SetPrimitiveArrayRegion,          // SetIntArrayRegion
2315   _Jv_JNI_SetPrimitiveArrayRegion,          // SetLongArrayRegion
2316   _Jv_JNI_SetPrimitiveArrayRegion,          // SetFloatArrayRegion
2317   _Jv_JNI_SetPrimitiveArrayRegion,          // SetDoubleArrayRegion
2318   _Jv_JNI_RegisterNatives,                  // RegisterNatives
2319   _Jv_JNI_UnregisterNatives,                // UnregisterNatives
2320   _Jv_JNI_MonitorEnter,                     // MonitorEnter
2321   _Jv_JNI_MonitorExit,                      // MonitorExit
2322   _Jv_JNI_GetJavaVM,                        // GetJavaVM
2323
2324   _Jv_JNI_GetStringRegion,                  // GetStringRegion
2325   _Jv_JNI_GetStringUTFRegion,               // GetStringUTFRegion
2326   _Jv_JNI_GetPrimitiveArrayCritical,        // GetPrimitiveArrayCritical
2327   _Jv_JNI_ReleasePrimitiveArrayCritical,    // ReleasePrimitiveArrayCritical
2328   _Jv_JNI_GetStringCritical,                // GetStringCritical
2329   _Jv_JNI_ReleaseStringCritical,            // ReleaseStringCritical
2330
2331   NOT_IMPL /* newweakglobalref */,
2332   NOT_IMPL /* deleteweakglobalref */,
2333
2334   _Jv_JNI_ExceptionCheck
2335 };
2336
2337 struct JNIInvokeInterface _Jv_JNI_InvokeFunctions =
2338 {
2339   RESERVED,
2340   RESERVED,
2341   RESERVED,
2342
2343   _Jv_JNI_DestroyJavaVM,
2344   _Jv_JNI_AttachCurrentThread,
2345   _Jv_JNI_DetachCurrentThread,
2346   _Jv_JNI_GetEnv
2347 };