OSDN Git Service

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