OSDN Git Service

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