OSDN Git Service

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