OSDN Git Service

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