OSDN Git Service

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