OSDN Git Service

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