OSDN Git Service

* jni.cc (nathash, nathash_count, nathash_size): New globals.
[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/IdentityHashMap.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::IdentityHashMap *local_ref_table;
95 // This holds a reference count for all global references.
96 static java::util::IdentityHashMap *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::IdentityHashMap;
152   global_ref_table = new java::util::IdentityHashMap;
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::IdentityHashMap *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::IdentityHashMap *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 \f
1547
1548 // Hash table of native methods.
1549 static JNINativeMethod *nathash;
1550 // Number of slots used.
1551 static int nathash_count = 0;
1552 // Number of slots available.  Must be power of 2.
1553 static int nathash_size = 0;
1554
1555 #define DELETED_ENTRY ((char *) (~0))
1556
1557 // Compute a hash value for a native method descriptor.
1558 static int
1559 hash (const JNINativeMethod *method)
1560 {
1561   char *ptr;
1562   int hash = 0;
1563
1564   ptr = method->name;
1565   while (*ptr)
1566     hash = (31 * hash) + *ptr++;
1567
1568   ptr = method->signature;
1569   while (*ptr)
1570     hash = (31 * hash) + *ptr++;
1571
1572   return hash;
1573 }
1574
1575 // Find the slot where a native method goes.
1576 static JNINativeMethod *
1577 nathash_find_slot (const JNINativeMethod *method)
1578 {
1579   jint h = hash (method);
1580   int step = (h ^ (h >> 16)) | 1;
1581   int w = h & (nathash_size - 1);
1582   int del = -1;
1583
1584   for (;;)
1585     {
1586       JNINativeMethod *slotp = &nathash[w];
1587       if (slotp->name == NULL)
1588         {
1589           if (del >= 0)
1590             return &nathash[del];
1591           else
1592             return slotp;
1593         }
1594       else if (slotp->name == DELETED_ENTRY)
1595         del = w;
1596       else if (! strcmp (slotp->name, method->name)
1597                && ! strcmp (slotp->signature, method->signature))
1598         return slotp;
1599       w = (w + step) & (nathash_size - 1);
1600     }
1601 }
1602
1603 // Find a method.  Return NULL if it isn't in the hash table.
1604 static void *
1605 nathash_find (JNINativeMethod *method)
1606 {
1607   if (nathash == NULL)
1608     return NULL;
1609   JNINativeMethod *slot = nathash_find_slot (method);
1610   if (slot->name == NULL || slot->name == DELETED_ENTRY)
1611     return NULL;
1612   return slot->fnPtr;
1613 }
1614
1615 static void
1616 natrehash ()
1617 {
1618   if (nathash == NULL)
1619     {
1620       nathash_size = 1024;
1621       nathash =
1622         (JNINativeMethod *) _Jv_AllocBytes (nathash_size
1623                                             * sizeof (JNINativeMethod));
1624       memset (nathash, 0, nathash_size * sizeof (JNINativeMethod));
1625     }
1626   else
1627     {
1628       int savesize = nathash_size;
1629       JNINativeMethod *savehash = nathash;
1630       nathash_size *= 2;
1631       nathash =
1632         (JNINativeMethod *) _Jv_AllocBytes (nathash_size
1633                                             * sizeof (JNINativeMethod));
1634       memset (nathash, 0, nathash_size * sizeof (JNINativeMethod));
1635
1636       for (int i = 0; i < savesize; ++i)
1637         {
1638           if (savehash[i].name != NULL && savehash[i].name != DELETED_ENTRY)
1639             {
1640               JNINativeMethod *slot = nathash_find_slot (&savehash[i]);
1641               *slot = savehash[i];
1642             }
1643         }
1644     }
1645 }
1646
1647 static void
1648 nathash_add (const JNINativeMethod *method)
1649 {
1650   if (3 * nathash_count >= 2 * nathash_size)
1651     natrehash ();
1652   JNINativeMethod *slot = nathash_find_slot (method);
1653   // If the slot has a real entry in it, then there is no work to do.
1654   if (slot->name != NULL && slot->name != DELETED_ENTRY)
1655     return;
1656   // FIXME
1657   slot->name = strdup (method->name);
1658   slot->signature = strdup (method->signature);
1659   slot->fnPtr = method->fnPtr;
1660 }
1661
1662 static jint
1663 _Jv_JNI_RegisterNatives (JNIEnv *env, jclass klass,
1664                          const JNINativeMethod *methods,
1665                          jint nMethods)
1666 {
1667   // Synchronize while we do the work.  This must match
1668   // synchronization in some other functions that manipulate or use
1669   // the nathash table.
1670   JvSynchronize sync (global_ref_table);
1671
1672   // Look at each descriptor given us, and find the corresponding
1673   // method in the class.
1674   for (int j = 0; j < nMethods; ++j)
1675     {
1676       bool found = false;
1677
1678       _Jv_Method *imeths = JvGetFirstMethod (klass);
1679       for (int i = 0; i < JvNumMethods (klass); ++i)
1680         {
1681           _Jv_Method *self = &imeths[i];
1682
1683           if (! strcmp (self->name->data, methods[j].name)
1684               && ! strcmp (self->signature->data, methods[j].signature))
1685             {
1686               if (! (self->accflags
1687                      & java::lang::reflect::Modifier::NATIVE))
1688                 break;
1689
1690               // Found a match that is native.
1691               found = true;
1692               nathash_add (&methods[j]);
1693
1694               break;
1695             }
1696         }
1697
1698       if (! found)
1699         {
1700           jstring m = JvNewStringUTF (methods[j].name);
1701           try
1702             {
1703               env->ex =new java::lang::NoSuchMethodError (m);
1704             }
1705           catch (jthrowable t)
1706             {
1707               env->ex = t;
1708             }
1709           return JNI_ERR;
1710         }
1711     }
1712
1713   return JNI_OK;
1714 }
1715
1716 static jint
1717 _Jv_JNI_UnregisterNatives (JNIEnv *, jclass)
1718 {
1719   // FIXME -- we could implement this.
1720   return JNI_ERR;
1721 }
1722
1723 \f
1724
1725 // Add a character to the buffer, encoding properly.
1726 static void
1727 add_char (char *buf, jchar c, int *here)
1728 {
1729   if (c == '_')
1730     {
1731       buf[(*here)++] = '_';
1732       buf[(*here)++] = '1';
1733     }
1734   else if (c == ';')
1735     {
1736       buf[(*here)++] = '_';
1737       buf[(*here)++] = '2';
1738     }
1739   else if (c == '[')
1740     {
1741       buf[(*here)++] = '_';
1742       buf[(*here)++] = '3';
1743     }
1744
1745   // Also check for `.' here because we might be passed an internal
1746   // qualified class name like `foo.bar'.
1747   else if (c == '/' || c == '.')
1748     buf[(*here)++] = '_';
1749   else if ((c >= '0' && c <= '9')
1750            || (c >= 'a' && c <= 'z')
1751            || (c >= 'A' && c <= 'Z'))
1752     buf[(*here)++] = (char) c;
1753   else
1754     {
1755       // "Unicode" character.
1756       buf[(*here)++] = '_';
1757       buf[(*here)++] = '0';
1758       for (int i = 0; i < 4; ++i)
1759         {
1760           int val = c & 0x0f;
1761           buf[(*here) + 3 - i] = (val > 10) ? ('a' + val - 10) : ('0' + val);
1762           c >>= 4;
1763         }
1764       *here += 4;
1765     }
1766 }
1767
1768 // Compute a mangled name for a native function.  This computes the
1769 // long name, and also returns an index which indicates where a NUL
1770 // can be placed to create the short name.  This function assumes that
1771 // the buffer is large enough for its results.
1772 static void
1773 mangled_name (jclass klass, _Jv_Utf8Const *func_name,
1774               _Jv_Utf8Const *signature, char *buf, int *long_start)
1775 {
1776   strcpy (buf, "Java_");
1777   int here = 5;
1778
1779   // Add fully qualified class name.
1780   jchar *chars = _Jv_GetStringChars (klass->getName ());
1781   jint len = klass->getName ()->length ();
1782   for (int i = 0; i < len; ++i)
1783     add_char (buf, chars[i], &here);
1784
1785   // Don't use add_char because we need a literal `_'.
1786   buf[here++] = '_';
1787
1788   const unsigned char *fn = (const unsigned char *) func_name->data;
1789   const unsigned char *limit = fn + func_name->length;
1790   for (int i = 0; ; ++i)
1791     {
1792       int ch = UTF8_GET (fn, limit);
1793       if (ch < 0)
1794         break;
1795       add_char (buf, ch, &here);
1796     }
1797
1798   // This is where the long signature begins.
1799   *long_start = here;
1800   buf[here++] = '_';
1801   buf[here++] = '_';
1802
1803   const unsigned char *sig = (const unsigned char *) signature->data;
1804   limit = sig + signature->length;
1805   JvAssert (sig[0] == '(');
1806   ++sig;
1807   while (1)
1808     {
1809       int ch = UTF8_GET (sig, limit);
1810       if (ch == ')' || ch < 0)
1811         break;
1812       add_char (buf, ch, &here);
1813     }
1814
1815   buf[here] = '\0';
1816 }
1817
1818 // Return the current thread's JNIEnv; if one does not exist, create
1819 // it.  Also create a new system frame for use.  This is `extern "C"'
1820 // because the compiler calls it.
1821 extern "C" JNIEnv *
1822 _Jv_GetJNIEnvNewFrame (jclass klass)
1823 {
1824   JNIEnv *env = _Jv_GetCurrentJNIEnv ();
1825   if (env == NULL)
1826     {
1827       env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv));
1828       env->p = &_Jv_JNIFunctions;
1829       env->ex = NULL;
1830       env->klass = klass;
1831       env->locals = NULL;
1832
1833       _Jv_SetCurrentJNIEnv (env);
1834     }
1835
1836   _Jv_JNI_LocalFrame *frame
1837     = (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame)
1838                                                   + (FRAME_SIZE
1839                                                      * sizeof (jobject)));
1840
1841   frame->marker = MARK_SYSTEM;
1842   frame->size = FRAME_SIZE;
1843   frame->next = env->locals;
1844   env->locals = frame;
1845
1846   for (int i = 0; i < frame->size; ++i)
1847     frame->vec[i] = NULL;
1848
1849   return env;
1850 }
1851
1852 // Return the function which implements a particular JNI method.  If
1853 // we can't find the function, we throw the appropriate exception.
1854 // This is `extern "C"' because the compiler uses it.
1855 extern "C" void *
1856 _Jv_LookupJNIMethod (jclass klass, _Jv_Utf8Const *name,
1857                      _Jv_Utf8Const *signature)
1858 {
1859   char buf[10 + 6 * (name->length + signature->length)];
1860   int long_start;
1861   void *function;
1862
1863   // Synchronize on something convenient.  Right now we use the hash.
1864   JvSynchronize sync (global_ref_table);
1865
1866   // First see if we have an override in the hash table.
1867   strncpy (buf, name->data, name->length);
1868   buf[name->length] = '\0';
1869   strncpy (buf + name->length + 1, signature->data, signature->length);
1870   buf[name->length + signature->length + 1] = '\0';
1871   JNINativeMethod meth;
1872   meth.name = buf;
1873   meth.signature = buf + name->length + 1;
1874   function = nathash_find (&meth);
1875   if (function != NULL)
1876     return function;
1877
1878   // If there was no override, then look in the symbol table.
1879   mangled_name (klass, name, signature, buf, &long_start);
1880   char c = buf[long_start];
1881   buf[long_start] = '\0';
1882   function = _Jv_FindSymbolInExecutable (buf);
1883   if (function == NULL)
1884     {
1885       buf[long_start] = c;
1886       function = _Jv_FindSymbolInExecutable (buf);
1887       if (function == NULL)
1888         {
1889           jstring str = JvNewStringUTF (name->data);
1890           throw new java::lang::AbstractMethodError (str);
1891         }
1892     }
1893
1894   return function;
1895 }
1896
1897 #ifdef INTERPRETER
1898
1899 // This function is the stub which is used to turn an ordinary (CNI)
1900 // method call into a JNI call.
1901 void
1902 _Jv_JNIMethod::call (ffi_cif *, void *ret, ffi_raw *args, void *__this)
1903 {
1904   _Jv_JNIMethod* _this = (_Jv_JNIMethod *) __this;
1905
1906   JNIEnv *env = _Jv_GetJNIEnvNewFrame (_this->defining_class);
1907
1908   // FIXME: we should mark every reference parameter as a local.  For
1909   // now we assume a conservative GC, and we assume that the
1910   // references are on the stack somewhere.
1911
1912   // We cache the value that we find, of course, but if we don't find
1913   // a value we don't cache that fact -- we might subsequently load a
1914   // library which finds the function in question.
1915   {
1916     // Synchronize on a convenient object to ensure sanity in case two
1917     // threads reach this point for the same function at the same
1918     // time.
1919     JvSynchronize sync (global_ref_table);
1920     if (_this->function == NULL)
1921       _this->function = _Jv_LookupJNIMethod (_this->defining_class,
1922                                              _this->self->name,
1923                                              _this->self->signature);
1924   }
1925
1926   JvAssert (_this->args_raw_size % sizeof (ffi_raw) == 0);
1927   ffi_raw real_args[2 + _this->args_raw_size / sizeof (ffi_raw)];
1928   int offset = 0;
1929
1930   // First argument is always the environment pointer.
1931   real_args[offset++].ptr = env;
1932
1933   // For a static method, we pass in the Class.  For non-static
1934   // methods, the `this' argument is already handled.
1935   if ((_this->self->accflags & java::lang::reflect::Modifier::STATIC))
1936     real_args[offset++].ptr = _this->defining_class;
1937
1938   // Copy over passed-in arguments.
1939   memcpy (&real_args[offset], args, _this->args_raw_size);
1940
1941   // The actual call to the JNI function.
1942   ffi_raw_call (&_this->jni_cif, (void (*)()) _this->function,
1943                 ret, real_args);
1944
1945   _Jv_JNI_PopSystemFrame (env);
1946 }
1947
1948 #endif /* INTERPRETER */
1949
1950 \f
1951
1952 //
1953 // Invocation API.
1954 //
1955
1956 // An internal helper function.
1957 static jint
1958 _Jv_JNI_AttachCurrentThread (JavaVM *, jstring name, void **penv, void *args)
1959 {
1960   JavaVMAttachArgs *attach = reinterpret_cast<JavaVMAttachArgs *> (args);
1961   java::lang::ThreadGroup *group = NULL;
1962
1963   if (attach)
1964     {
1965       // FIXME: do we really want to support 1.1?
1966       if (attach->version != JNI_VERSION_1_2
1967           && attach->version != JNI_VERSION_1_1)
1968         return JNI_EVERSION;
1969
1970       JvAssert (java::lang::ThreadGroup::class$.isInstance (attach->group));
1971       group = reinterpret_cast<java::lang::ThreadGroup *> (attach->group);
1972     }
1973
1974   // Attaching an already-attached thread is a no-op.
1975   if (_Jv_GetCurrentJNIEnv () != NULL)
1976     return 0;
1977
1978   JNIEnv *env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv));
1979   if (env == NULL)
1980     return JNI_ERR;
1981   env->p = &_Jv_JNIFunctions;
1982   env->ex = NULL;
1983   env->klass = NULL;
1984   env->locals
1985     = (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame)
1986                                                   + (FRAME_SIZE
1987                                                      * sizeof (jobject)));
1988   if (env->locals == NULL)
1989     {
1990       _Jv_Free (env);
1991       return JNI_ERR;
1992     }
1993   *penv = reinterpret_cast<void *> (env);
1994
1995   // This thread might already be a Java thread -- this function might
1996   // have been called simply to set the new JNIEnv.
1997   if (_Jv_ThreadCurrent () == NULL)
1998     {
1999       try
2000         {
2001           _Jv_AttachCurrentThread (name, group);
2002         }
2003       catch (jthrowable t)
2004         {
2005           return JNI_ERR;
2006         }
2007     }
2008   _Jv_SetCurrentJNIEnv (env);
2009
2010   return 0;
2011 }
2012
2013 // This is the one actually used by JNI.
2014 static jint
2015 _Jv_JNI_AttachCurrentThread (JavaVM *vm, void **penv, void *args)
2016 {
2017   return _Jv_JNI_AttachCurrentThread (vm, NULL, penv, args);
2018 }
2019
2020 static jint
2021 _Jv_JNI_DestroyJavaVM (JavaVM *vm)
2022 {
2023   JvAssert (the_vm && vm == the_vm);
2024
2025   JNIEnv *env;
2026   if (_Jv_ThreadCurrent () != NULL)
2027     {
2028       jstring main_name;
2029       // This sucks.
2030       try
2031         {
2032           main_name = JvNewStringLatin1 ("main");
2033         }
2034       catch (jthrowable t)
2035         {
2036           return JNI_ERR;
2037         }
2038
2039       jint r = _Jv_JNI_AttachCurrentThread (vm,
2040                                             main_name,
2041                                             reinterpret_cast<void **> (&env),
2042                                             NULL);
2043       if (r < 0)
2044         return r;
2045     }
2046   else
2047     env = _Jv_GetCurrentJNIEnv ();
2048
2049   _Jv_ThreadWait ();
2050
2051   // Docs say that this always returns an error code.
2052   return JNI_ERR;
2053 }
2054
2055 jint
2056 _Jv_JNI_DetachCurrentThread (JavaVM *)
2057 {
2058   jint code = _Jv_DetachCurrentThread ();
2059   return code  ? JNI_EDETACHED : 0;
2060 }
2061
2062 static jint
2063 _Jv_JNI_GetEnv (JavaVM *, void **penv, jint version)
2064 {
2065   if (_Jv_ThreadCurrent () == NULL)
2066     {
2067       *penv = NULL;
2068       return JNI_EDETACHED;
2069     }
2070
2071 #ifdef ENABLE_JVMPI
2072   // Handle JVMPI requests.
2073   if (version == JVMPI_VERSION_1)
2074     {
2075       *penv = (void *) &_Jv_JVMPI_Interface;
2076       return 0;
2077     }
2078 #endif
2079
2080   // FIXME: do we really want to support 1.1?
2081   if (version != JNI_VERSION_1_2 && version != JNI_VERSION_1_1)
2082     {
2083       *penv = NULL;
2084       return JNI_EVERSION;
2085     }
2086
2087   *penv = (void *) _Jv_GetCurrentJNIEnv ();
2088   return 0;
2089 }
2090
2091 jint
2092 JNI_GetDefaultJavaVMInitArgs (void *args)
2093 {
2094   jint version = * (jint *) args;
2095   // Here we only support 1.2.
2096   if (version != JNI_VERSION_1_2)
2097     return JNI_EVERSION;
2098
2099   JavaVMInitArgs *ia = reinterpret_cast<JavaVMInitArgs *> (args);
2100   ia->version = JNI_VERSION_1_2;
2101   ia->nOptions = 0;
2102   ia->options = NULL;
2103   ia->ignoreUnrecognized = true;
2104
2105   return 0;
2106 }
2107
2108 jint
2109 JNI_CreateJavaVM (JavaVM **vm, void **penv, void *args)
2110 {
2111   JvAssert (! the_vm);
2112   // FIXME: synchronize
2113   JavaVM *nvm = (JavaVM *) _Jv_MallocUnchecked (sizeof (JavaVM));
2114   if (nvm == NULL)
2115     return JNI_ERR;
2116   nvm->functions = &_Jv_JNI_InvokeFunctions;
2117
2118   // Parse the arguments.
2119   if (args != NULL)
2120     {
2121       jint version = * (jint *) args;
2122       // We only support 1.2.
2123       if (version != JNI_VERSION_1_2)
2124         return JNI_EVERSION;
2125       JavaVMInitArgs *ia = reinterpret_cast<JavaVMInitArgs *> (args);
2126       for (int i = 0; i < ia->nOptions; ++i)
2127         {
2128           if (! strcmp (ia->options[i].optionString, "vfprintf")
2129               || ! strcmp (ia->options[i].optionString, "exit")
2130               || ! strcmp (ia->options[i].optionString, "abort"))
2131             {
2132               // We are required to recognize these, but for now we
2133               // don't handle them in any way.  FIXME.
2134               continue;
2135             }
2136           else if (! strncmp (ia->options[i].optionString,
2137                               "-verbose", sizeof ("-verbose") - 1))
2138             {
2139               // We don't do anything with this option either.  We
2140               // might want to make sure the argument is valid, but we
2141               // don't really care all that much for now.
2142               continue;
2143             }
2144           else if (! strncmp (ia->options[i].optionString, "-D", 2))
2145             {
2146               // FIXME.
2147               continue;
2148             }
2149           else if (ia->ignoreUnrecognized)
2150             {
2151               if (ia->options[i].optionString[0] == '_'
2152                   || ! strncmp (ia->options[i].optionString, "-X", 2))
2153                 continue;
2154             }
2155
2156           return JNI_ERR;
2157         }
2158     }
2159
2160   jint r =_Jv_JNI_AttachCurrentThread (nvm, penv, NULL);
2161   if (r < 0)
2162     return r;
2163
2164   the_vm = nvm;
2165   *vm = the_vm;
2166
2167   _Jv_JNI_Init();
2168
2169   return 0;
2170 }
2171
2172 jint
2173 JNI_GetCreatedJavaVMs (JavaVM **vm_buffer, jsize buf_len, jsize *n_vms)
2174 {
2175   if (buf_len <= 0)
2176     return JNI_ERR;
2177
2178   // We only support a single VM.
2179   if (the_vm != NULL)
2180     {
2181       vm_buffer[0] = the_vm;
2182       *n_vms = 1;
2183     }
2184   else
2185     *n_vms = 0;
2186   return 0;
2187 }
2188
2189 JavaVM *
2190 _Jv_GetJavaVM ()
2191 {
2192   // FIXME: synchronize
2193   if (! the_vm)
2194     {
2195       JavaVM *nvm = (JavaVM *) _Jv_MallocUnchecked (sizeof (JavaVM));
2196       if (nvm != NULL)
2197         nvm->functions = &_Jv_JNI_InvokeFunctions;
2198       the_vm = nvm;
2199     }
2200
2201   // If this is a Java thread, we want to make sure it has an
2202   // associated JNIEnv.
2203   if (_Jv_ThreadCurrent () != NULL)
2204     {
2205       void *ignore;
2206       _Jv_JNI_AttachCurrentThread (the_vm, &ignore, NULL);
2207     }
2208
2209   return the_vm;
2210 }
2211
2212 static jint
2213 _Jv_JNI_GetJavaVM (JNIEnv *, JavaVM **vm)
2214 {
2215   *vm = _Jv_GetJavaVM ();
2216   return *vm == NULL ? JNI_ERR : JNI_OK;
2217 }
2218
2219 \f
2220
2221 #define NOT_IMPL NULL
2222 #define RESERVED NULL
2223
2224 struct JNINativeInterface _Jv_JNIFunctions =
2225 {
2226   RESERVED,
2227   RESERVED,
2228   RESERVED,
2229   RESERVED,
2230   _Jv_JNI_GetVersion,           // GetVersion
2231   _Jv_JNI_DefineClass,          // DefineClass
2232   _Jv_JNI_FindClass,            // FindClass
2233   _Jv_JNI_FromReflectedMethod,  // FromReflectedMethod
2234   _Jv_JNI_FromReflectedField,   // FromReflectedField
2235   _Jv_JNI_ToReflectedMethod,    // ToReflectedMethod
2236   _Jv_JNI_GetSuperclass,        // GetSuperclass
2237   _Jv_JNI_IsAssignableFrom,     // IsAssignableFrom
2238   _Jv_JNI_ToReflectedField,     // ToReflectedField
2239   _Jv_JNI_Throw,                // Throw
2240   _Jv_JNI_ThrowNew,             // ThrowNew
2241   _Jv_JNI_ExceptionOccurred,    // ExceptionOccurred
2242   _Jv_JNI_ExceptionDescribe,    // ExceptionDescribe
2243   _Jv_JNI_ExceptionClear,       // ExceptionClear
2244   _Jv_JNI_FatalError,           // FatalError
2245
2246   _Jv_JNI_PushLocalFrame,       // PushLocalFrame
2247   _Jv_JNI_PopLocalFrame,        // PopLocalFrame
2248   _Jv_JNI_NewGlobalRef,         // NewGlobalRef
2249   _Jv_JNI_DeleteGlobalRef,      // DeleteGlobalRef
2250   _Jv_JNI_DeleteLocalRef,       // DeleteLocalRef
2251
2252   _Jv_JNI_IsSameObject,         // IsSameObject
2253
2254   _Jv_JNI_NewLocalRef,          // NewLocalRef
2255   _Jv_JNI_EnsureLocalCapacity,  // EnsureLocalCapacity
2256
2257   _Jv_JNI_AllocObject,              // AllocObject
2258   _Jv_JNI_NewObject,                // NewObject
2259   _Jv_JNI_NewObjectV,               // NewObjectV
2260   _Jv_JNI_NewObjectA,               // NewObjectA
2261   _Jv_JNI_GetObjectClass,           // GetObjectClass
2262   _Jv_JNI_IsInstanceOf,             // IsInstanceOf
2263   _Jv_JNI_GetAnyMethodID<false>,    // GetMethodID
2264
2265   _Jv_JNI_CallMethod<jobject>,          // CallObjectMethod
2266   _Jv_JNI_CallMethodV<jobject>,         // CallObjectMethodV
2267   _Jv_JNI_CallMethodA<jobject>,         // CallObjectMethodA
2268   _Jv_JNI_CallMethod<jboolean>,         // CallBooleanMethod
2269   _Jv_JNI_CallMethodV<jboolean>,        // CallBooleanMethodV
2270   _Jv_JNI_CallMethodA<jboolean>,        // CallBooleanMethodA
2271   _Jv_JNI_CallMethod<jbyte>,            // CallByteMethod
2272   _Jv_JNI_CallMethodV<jbyte>,           // CallByteMethodV
2273   _Jv_JNI_CallMethodA<jbyte>,           // CallByteMethodA
2274   _Jv_JNI_CallMethod<jchar>,            // CallCharMethod
2275   _Jv_JNI_CallMethodV<jchar>,           // CallCharMethodV
2276   _Jv_JNI_CallMethodA<jchar>,           // CallCharMethodA
2277   _Jv_JNI_CallMethod<jshort>,           // CallShortMethod
2278   _Jv_JNI_CallMethodV<jshort>,          // CallShortMethodV
2279   _Jv_JNI_CallMethodA<jshort>,          // CallShortMethodA
2280   _Jv_JNI_CallMethod<jint>,             // CallIntMethod
2281   _Jv_JNI_CallMethodV<jint>,            // CallIntMethodV
2282   _Jv_JNI_CallMethodA<jint>,            // CallIntMethodA
2283   _Jv_JNI_CallMethod<jlong>,            // CallLongMethod
2284   _Jv_JNI_CallMethodV<jlong>,           // CallLongMethodV
2285   _Jv_JNI_CallMethodA<jlong>,           // CallLongMethodA
2286   _Jv_JNI_CallMethod<jfloat>,           // CallFloatMethod
2287   _Jv_JNI_CallMethodV<jfloat>,          // CallFloatMethodV
2288   _Jv_JNI_CallMethodA<jfloat>,          // CallFloatMethodA
2289   _Jv_JNI_CallMethod<jdouble>,          // CallDoubleMethod
2290   _Jv_JNI_CallMethodV<jdouble>,         // CallDoubleMethodV
2291   _Jv_JNI_CallMethodA<jdouble>,         // CallDoubleMethodA
2292   _Jv_JNI_CallVoidMethod,               // CallVoidMethod
2293   _Jv_JNI_CallVoidMethodV,              // CallVoidMethodV
2294   _Jv_JNI_CallVoidMethodA,              // CallVoidMethodA
2295
2296   // Nonvirtual method invocation functions follow.
2297   _Jv_JNI_CallAnyMethod<jobject, nonvirtual>,   // CallNonvirtualObjectMethod
2298   _Jv_JNI_CallAnyMethodV<jobject, nonvirtual>,  // CallNonvirtualObjectMethodV
2299   _Jv_JNI_CallAnyMethodA<jobject, nonvirtual>,  // CallNonvirtualObjectMethodA
2300   _Jv_JNI_CallAnyMethod<jboolean, nonvirtual>,  // CallNonvirtualBooleanMethod
2301   _Jv_JNI_CallAnyMethodV<jboolean, nonvirtual>, // CallNonvirtualBooleanMethodV
2302   _Jv_JNI_CallAnyMethodA<jboolean, nonvirtual>, // CallNonvirtualBooleanMethodA
2303   _Jv_JNI_CallAnyMethod<jbyte, nonvirtual>,     // CallNonvirtualByteMethod
2304   _Jv_JNI_CallAnyMethodV<jbyte, nonvirtual>,    // CallNonvirtualByteMethodV
2305   _Jv_JNI_CallAnyMethodA<jbyte, nonvirtual>,    // CallNonvirtualByteMethodA
2306   _Jv_JNI_CallAnyMethod<jchar, nonvirtual>,     // CallNonvirtualCharMethod
2307   _Jv_JNI_CallAnyMethodV<jchar, nonvirtual>,    // CallNonvirtualCharMethodV
2308   _Jv_JNI_CallAnyMethodA<jchar, nonvirtual>,    // CallNonvirtualCharMethodA
2309   _Jv_JNI_CallAnyMethod<jshort, nonvirtual>,    // CallNonvirtualShortMethod
2310   _Jv_JNI_CallAnyMethodV<jshort, nonvirtual>,   // CallNonvirtualShortMethodV
2311   _Jv_JNI_CallAnyMethodA<jshort, nonvirtual>,   // CallNonvirtualShortMethodA
2312   _Jv_JNI_CallAnyMethod<jint, nonvirtual>,      // CallNonvirtualIntMethod
2313   _Jv_JNI_CallAnyMethodV<jint, nonvirtual>,     // CallNonvirtualIntMethodV
2314   _Jv_JNI_CallAnyMethodA<jint, nonvirtual>,     // CallNonvirtualIntMethodA
2315   _Jv_JNI_CallAnyMethod<jlong, nonvirtual>,     // CallNonvirtualLongMethod
2316   _Jv_JNI_CallAnyMethodV<jlong, nonvirtual>,    // CallNonvirtualLongMethodV
2317   _Jv_JNI_CallAnyMethodA<jlong, nonvirtual>,    // CallNonvirtualLongMethodA
2318   _Jv_JNI_CallAnyMethod<jfloat, nonvirtual>,    // CallNonvirtualFloatMethod
2319   _Jv_JNI_CallAnyMethodV<jfloat, nonvirtual>,   // CallNonvirtualFloatMethodV
2320   _Jv_JNI_CallAnyMethodA<jfloat, nonvirtual>,   // CallNonvirtualFloatMethodA
2321   _Jv_JNI_CallAnyMethod<jdouble, nonvirtual>,   // CallNonvirtualDoubleMethod
2322   _Jv_JNI_CallAnyMethodV<jdouble, nonvirtual>,  // CallNonvirtualDoubleMethodV
2323   _Jv_JNI_CallAnyMethodA<jdouble, nonvirtual>,  // CallNonvirtualDoubleMethodA
2324   _Jv_JNI_CallAnyVoidMethod<nonvirtual>,        // CallNonvirtualVoidMethod
2325   _Jv_JNI_CallAnyVoidMethodV<nonvirtual>,       // CallNonvirtualVoidMethodV
2326   _Jv_JNI_CallAnyVoidMethodA<nonvirtual>,       // CallNonvirtualVoidMethodA
2327
2328   _Jv_JNI_GetAnyFieldID<false>, // GetFieldID
2329   _Jv_JNI_GetField<jobject>,    // GetObjectField
2330   _Jv_JNI_GetField<jboolean>,   // GetBooleanField
2331   _Jv_JNI_GetField<jbyte>,      // GetByteField
2332   _Jv_JNI_GetField<jchar>,      // GetCharField
2333   _Jv_JNI_GetField<jshort>,     // GetShortField
2334   _Jv_JNI_GetField<jint>,       // GetIntField
2335   _Jv_JNI_GetField<jlong>,      // GetLongField
2336   _Jv_JNI_GetField<jfloat>,     // GetFloatField
2337   _Jv_JNI_GetField<jdouble>,    // GetDoubleField
2338   _Jv_JNI_SetField,             // SetObjectField
2339   _Jv_JNI_SetField,             // SetBooleanField
2340   _Jv_JNI_SetField,             // SetByteField
2341   _Jv_JNI_SetField,             // SetCharField
2342   _Jv_JNI_SetField,             // SetShortField
2343   _Jv_JNI_SetField,             // SetIntField
2344   _Jv_JNI_SetField,             // SetLongField
2345   _Jv_JNI_SetField,             // SetFloatField
2346   _Jv_JNI_SetField,             // SetDoubleField
2347   _Jv_JNI_GetAnyMethodID<true>, // GetStaticMethodID
2348
2349   _Jv_JNI_CallStaticMethod<jobject>,      // CallStaticObjectMethod
2350   _Jv_JNI_CallStaticMethodV<jobject>,     // CallStaticObjectMethodV
2351   _Jv_JNI_CallStaticMethodA<jobject>,     // CallStaticObjectMethodA
2352   _Jv_JNI_CallStaticMethod<jboolean>,     // CallStaticBooleanMethod
2353   _Jv_JNI_CallStaticMethodV<jboolean>,    // CallStaticBooleanMethodV
2354   _Jv_JNI_CallStaticMethodA<jboolean>,    // CallStaticBooleanMethodA
2355   _Jv_JNI_CallStaticMethod<jbyte>,        // CallStaticByteMethod
2356   _Jv_JNI_CallStaticMethodV<jbyte>,       // CallStaticByteMethodV
2357   _Jv_JNI_CallStaticMethodA<jbyte>,       // CallStaticByteMethodA
2358   _Jv_JNI_CallStaticMethod<jchar>,        // CallStaticCharMethod
2359   _Jv_JNI_CallStaticMethodV<jchar>,       // CallStaticCharMethodV
2360   _Jv_JNI_CallStaticMethodA<jchar>,       // CallStaticCharMethodA
2361   _Jv_JNI_CallStaticMethod<jshort>,       // CallStaticShortMethod
2362   _Jv_JNI_CallStaticMethodV<jshort>,      // CallStaticShortMethodV
2363   _Jv_JNI_CallStaticMethodA<jshort>,      // CallStaticShortMethodA
2364   _Jv_JNI_CallStaticMethod<jint>,         // CallStaticIntMethod
2365   _Jv_JNI_CallStaticMethodV<jint>,        // CallStaticIntMethodV
2366   _Jv_JNI_CallStaticMethodA<jint>,        // CallStaticIntMethodA
2367   _Jv_JNI_CallStaticMethod<jlong>,        // CallStaticLongMethod
2368   _Jv_JNI_CallStaticMethodV<jlong>,       // CallStaticLongMethodV
2369   _Jv_JNI_CallStaticMethodA<jlong>,       // CallStaticLongMethodA
2370   _Jv_JNI_CallStaticMethod<jfloat>,       // CallStaticFloatMethod
2371   _Jv_JNI_CallStaticMethodV<jfloat>,      // CallStaticFloatMethodV
2372   _Jv_JNI_CallStaticMethodA<jfloat>,      // CallStaticFloatMethodA
2373   _Jv_JNI_CallStaticMethod<jdouble>,      // CallStaticDoubleMethod
2374   _Jv_JNI_CallStaticMethodV<jdouble>,     // CallStaticDoubleMethodV
2375   _Jv_JNI_CallStaticMethodA<jdouble>,     // CallStaticDoubleMethodA
2376   _Jv_JNI_CallStaticVoidMethod,           // CallStaticVoidMethod
2377   _Jv_JNI_CallStaticVoidMethodV,          // CallStaticVoidMethodV
2378   _Jv_JNI_CallStaticVoidMethodA,          // CallStaticVoidMethodA
2379
2380   _Jv_JNI_GetAnyFieldID<true>,         // GetStaticFieldID
2381   _Jv_JNI_GetStaticField<jobject>,     // GetStaticObjectField
2382   _Jv_JNI_GetStaticField<jboolean>,    // GetStaticBooleanField
2383   _Jv_JNI_GetStaticField<jbyte>,       // GetStaticByteField
2384   _Jv_JNI_GetStaticField<jchar>,       // GetStaticCharField
2385   _Jv_JNI_GetStaticField<jshort>,      // GetStaticShortField
2386   _Jv_JNI_GetStaticField<jint>,        // GetStaticIntField
2387   _Jv_JNI_GetStaticField<jlong>,       // GetStaticLongField
2388   _Jv_JNI_GetStaticField<jfloat>,      // GetStaticFloatField
2389   _Jv_JNI_GetStaticField<jdouble>,     // GetStaticDoubleField
2390   _Jv_JNI_SetStaticField,              // SetStaticObjectField
2391   _Jv_JNI_SetStaticField,              // SetStaticBooleanField
2392   _Jv_JNI_SetStaticField,              // SetStaticByteField
2393   _Jv_JNI_SetStaticField,              // SetStaticCharField
2394   _Jv_JNI_SetStaticField,              // SetStaticShortField
2395   _Jv_JNI_SetStaticField,              // SetStaticIntField
2396   _Jv_JNI_SetStaticField,              // SetStaticLongField
2397   _Jv_JNI_SetStaticField,              // SetStaticFloatField
2398   _Jv_JNI_SetStaticField,              // SetStaticDoubleField
2399   _Jv_JNI_NewString,                   // NewString
2400   _Jv_JNI_GetStringLength,             // GetStringLength
2401   _Jv_JNI_GetStringChars,              // GetStringChars
2402   _Jv_JNI_ReleaseStringChars,          // ReleaseStringChars
2403   _Jv_JNI_NewStringUTF,                // NewStringUTF
2404   _Jv_JNI_GetStringUTFLength,          // GetStringUTFLength
2405   _Jv_JNI_GetStringUTFChars,           // GetStringUTFLength
2406   _Jv_JNI_ReleaseStringUTFChars,       // ReleaseStringUTFChars
2407   _Jv_JNI_GetArrayLength,              // GetArrayLength
2408   _Jv_JNI_NewObjectArray,              // NewObjectArray
2409   _Jv_JNI_GetObjectArrayElement,       // GetObjectArrayElement
2410   _Jv_JNI_SetObjectArrayElement,       // SetObjectArrayElement
2411   _Jv_JNI_NewPrimitiveArray<jboolean, JvPrimClass (boolean)>,
2412                                                             // NewBooleanArray
2413   _Jv_JNI_NewPrimitiveArray<jbyte, JvPrimClass (byte)>,     // NewByteArray
2414   _Jv_JNI_NewPrimitiveArray<jchar, JvPrimClass (char)>,     // NewCharArray
2415   _Jv_JNI_NewPrimitiveArray<jshort, JvPrimClass (short)>,   // NewShortArray
2416   _Jv_JNI_NewPrimitiveArray<jint, JvPrimClass (int)>,       // NewIntArray
2417   _Jv_JNI_NewPrimitiveArray<jlong, JvPrimClass (long)>,     // NewLongArray
2418   _Jv_JNI_NewPrimitiveArray<jfloat, JvPrimClass (float)>,   // NewFloatArray
2419   _Jv_JNI_NewPrimitiveArray<jdouble, JvPrimClass (double)>, // NewDoubleArray
2420   _Jv_JNI_GetPrimitiveArrayElements,        // GetBooleanArrayElements
2421   _Jv_JNI_GetPrimitiveArrayElements,        // GetByteArrayElements
2422   _Jv_JNI_GetPrimitiveArrayElements,        // GetCharArrayElements
2423   _Jv_JNI_GetPrimitiveArrayElements,        // GetShortArrayElements
2424   _Jv_JNI_GetPrimitiveArrayElements,        // GetIntArrayElements
2425   _Jv_JNI_GetPrimitiveArrayElements,        // GetLongArrayElements
2426   _Jv_JNI_GetPrimitiveArrayElements,        // GetFloatArrayElements
2427   _Jv_JNI_GetPrimitiveArrayElements,        // GetDoubleArrayElements
2428   _Jv_JNI_ReleasePrimitiveArrayElements,    // ReleaseBooleanArrayElements
2429   _Jv_JNI_ReleasePrimitiveArrayElements,    // ReleaseByteArrayElements
2430   _Jv_JNI_ReleasePrimitiveArrayElements,    // ReleaseCharArrayElements
2431   _Jv_JNI_ReleasePrimitiveArrayElements,    // ReleaseShortArrayElements
2432   _Jv_JNI_ReleasePrimitiveArrayElements,    // ReleaseIntArrayElements
2433   _Jv_JNI_ReleasePrimitiveArrayElements,    // ReleaseLongArrayElements
2434   _Jv_JNI_ReleasePrimitiveArrayElements,    // ReleaseFloatArrayElements
2435   _Jv_JNI_ReleasePrimitiveArrayElements,    // ReleaseDoubleArrayElements
2436   _Jv_JNI_GetPrimitiveArrayRegion,          // GetBooleanArrayRegion
2437   _Jv_JNI_GetPrimitiveArrayRegion,          // GetByteArrayRegion
2438   _Jv_JNI_GetPrimitiveArrayRegion,          // GetCharArrayRegion
2439   _Jv_JNI_GetPrimitiveArrayRegion,          // GetShortArrayRegion
2440   _Jv_JNI_GetPrimitiveArrayRegion,          // GetIntArrayRegion
2441   _Jv_JNI_GetPrimitiveArrayRegion,          // GetLongArrayRegion
2442   _Jv_JNI_GetPrimitiveArrayRegion,          // GetFloatArrayRegion
2443   _Jv_JNI_GetPrimitiveArrayRegion,          // GetDoubleArrayRegion
2444   _Jv_JNI_SetPrimitiveArrayRegion,          // SetBooleanArrayRegion
2445   _Jv_JNI_SetPrimitiveArrayRegion,          // SetByteArrayRegion
2446   _Jv_JNI_SetPrimitiveArrayRegion,          // SetCharArrayRegion
2447   _Jv_JNI_SetPrimitiveArrayRegion,          // SetShortArrayRegion
2448   _Jv_JNI_SetPrimitiveArrayRegion,          // SetIntArrayRegion
2449   _Jv_JNI_SetPrimitiveArrayRegion,          // SetLongArrayRegion
2450   _Jv_JNI_SetPrimitiveArrayRegion,          // SetFloatArrayRegion
2451   _Jv_JNI_SetPrimitiveArrayRegion,          // SetDoubleArrayRegion
2452   _Jv_JNI_RegisterNatives,                  // RegisterNatives
2453   _Jv_JNI_UnregisterNatives,                // UnregisterNatives
2454   _Jv_JNI_MonitorEnter,                     // MonitorEnter
2455   _Jv_JNI_MonitorExit,                      // MonitorExit
2456   _Jv_JNI_GetJavaVM,                        // GetJavaVM
2457
2458   _Jv_JNI_GetStringRegion,                  // GetStringRegion
2459   _Jv_JNI_GetStringUTFRegion,               // GetStringUTFRegion
2460   _Jv_JNI_GetPrimitiveArrayCritical,        // GetPrimitiveArrayCritical
2461   _Jv_JNI_ReleasePrimitiveArrayCritical,    // ReleasePrimitiveArrayCritical
2462   _Jv_JNI_GetStringCritical,                // GetStringCritical
2463   _Jv_JNI_ReleaseStringCritical,            // ReleaseStringCritical
2464
2465   NOT_IMPL /* newweakglobalref */,
2466   NOT_IMPL /* deleteweakglobalref */,
2467
2468   _Jv_JNI_ExceptionCheck
2469 };
2470
2471 struct JNIInvokeInterface _Jv_JNI_InvokeFunctions =
2472 {
2473   RESERVED,
2474   RESERVED,
2475   RESERVED,
2476
2477   _Jv_JNI_DestroyJavaVM,
2478   _Jv_JNI_AttachCurrentThread,
2479   _Jv_JNI_DetachCurrentThread,
2480   _Jv_JNI_GetEnv
2481 };