source: trunk/src/gcc/libjava/jni.cc@ 141

Last change on this file since 141 was 2, checked in by bird, 23 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 67.3 KB
Line 
1// jni.cc - JNI implementation, including the jump table.
2
3/* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation
4
5 This file is part of libgcj.
6
7This software is copyrighted work licensed under the terms of the
8Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9details. */
10
11#include <config.h>
12
13#include <stddef.h>
14#include <string.h>
15
16#include <gcj/cni.h>
17#include <jvm.h>
18#include <java-assert.h>
19#include <jni.h>
20#ifdef ENABLE_JVMPI
21#include <jvmpi.h>
22#endif
23
24#include <java/lang/Class.h>
25#include <java/lang/ClassLoader.h>
26#include <java/lang/Throwable.h>
27#include <java/lang/ArrayIndexOutOfBoundsException.h>
28#include <java/lang/StringIndexOutOfBoundsException.h>
29#include <java/lang/UnsatisfiedLinkError.h>
30#include <java/lang/InstantiationException.h>
31#include <java/lang/NoSuchFieldError.h>
32#include <java/lang/NoSuchMethodError.h>
33#include <java/lang/reflect/Constructor.h>
34#include <java/lang/reflect/Method.h>
35#include <java/lang/reflect/Modifier.h>
36#include <java/lang/OutOfMemoryError.h>
37#include <java/util/IdentityHashMap.h>
38#include <java/lang/Integer.h>
39#include <java/lang/ThreadGroup.h>
40#include <java/lang/Thread.h>
41
42#include <gcj/method.h>
43#include <gcj/field.h>
44
45#include <java-interp.h>
46#include <java-threads.h>
47
48using namespace gcj;
49
50// This enum is used to select different template instantiations in
51// the invocation code.
52enum invocation_type
53{
54 normal,
55 nonvirtual,
56 static_type,
57 constructor
58};
59
60// Forward declarations.
61extern struct JNINativeInterface _Jv_JNIFunctions;
62extern struct JNIInvokeInterface _Jv_JNI_InvokeFunctions;
63
64// Number of slots in the default frame. The VM must allow at least
65// 16.
66#define FRAME_SIZE 32
67
68// Mark value indicating this is an overflow frame.
69#define MARK_NONE 0
70// Mark value indicating this is a user frame.
71#define MARK_USER 1
72// Mark value indicating this is a system frame.
73#define MARK_SYSTEM 2
74
75// This structure is used to keep track of local references.
76struct _Jv_JNI_LocalFrame
77{
78 // This is true if this frame object represents a pushed frame (eg
79 // from PushLocalFrame).
80 int marker : 2;
81
82 // Number of elements in frame.
83 int size : 30;
84
85 // Next frame in chain.
86 _Jv_JNI_LocalFrame *next;
87
88 // The elements. These are allocated using the C "struct hack".
89 jobject vec[0];
90};
91
92// This holds a reference count for all local references.
93static java::util::IdentityHashMap *local_ref_table;
94// This holds a reference count for all global references.
95static java::util::IdentityHashMap *global_ref_table;
96
97// The only VM.
98static JavaVM *the_vm;
99
100#ifdef ENABLE_JVMPI
101// The only JVMPI interface description.
102static JVMPI_Interface _Jv_JVMPI_Interface;
103
104static jint
105jvmpiEnableEvent (jint event_type, void *)
106{
107 switch (event_type)
108 {
109 case JVMPI_EVENT_OBJECT_ALLOC:
110 _Jv_JVMPI_Notify_OBJECT_ALLOC = _Jv_JVMPI_Interface.NotifyEvent;
111 break;
112
113 case JVMPI_EVENT_THREAD_START:
114 _Jv_JVMPI_Notify_THREAD_START = _Jv_JVMPI_Interface.NotifyEvent;
115 break;
116
117 case JVMPI_EVENT_THREAD_END:
118 _Jv_JVMPI_Notify_THREAD_END = _Jv_JVMPI_Interface.NotifyEvent;
119 break;
120
121 default:
122 return JVMPI_NOT_AVAILABLE;
123 }
124
125 return JVMPI_SUCCESS;
126}
127
128static jint
129jvmpiDisableEvent (jint event_type, void *)
130{
131 switch (event_type)
132 {
133 case JVMPI_EVENT_OBJECT_ALLOC:
134 _Jv_JVMPI_Notify_OBJECT_ALLOC = NULL;
135 break;
136
137 default:
138 return JVMPI_NOT_AVAILABLE;
139 }
140
141 return JVMPI_SUCCESS;
142}
143#endif
144
145
146
147
148void
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.
165static void
166mark_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.
178static void
179unmark_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.
197template<typename T>
198static T
199unwrap (T val)
200{
201 return val;
202}
203
204// Unwrap a weak reference, if required.
205template<typename T>
206static T *
207unwrap (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
219
220
221static jobject
222_Jv_JNI_NewGlobalRef (JNIEnv *, jobject obj)
223{
224 // This seems weird but I think it is correct.
225 obj = unwrap (obj);
226 mark_for_gc (obj, global_ref_table);
227 return obj;
228}
229
230static void
231_Jv_JNI_DeleteGlobalRef (JNIEnv *, jobject obj)
232{
233 // This seems weird but I think it is correct.
234 obj = unwrap (obj);
235 unmark_for_gc (obj, global_ref_table);
236}
237
238static void
239_Jv_JNI_DeleteLocalRef (JNIEnv *env, jobject obj)
240{
241 _Jv_JNI_LocalFrame *frame;
242
243 // This seems weird but I think it is correct.
244 obj = unwrap (obj);
245
246 for (frame = env->locals; frame != NULL; frame = frame->next)
247 {
248 for (int i = 0; i < frame->size; ++i)
249 {
250 if (frame->vec[i] == obj)
251 {
252 frame->vec[i] = NULL;
253 unmark_for_gc (obj, local_ref_table);
254 return;
255 }
256 }
257
258 // Don't go past a marked frame.
259 JvAssert (frame->marker == MARK_NONE);
260 }
261
262 JvAssert (0);
263}
264
265static jint
266_Jv_JNI_EnsureLocalCapacity (JNIEnv *env, jint size)
267{
268 // It is easier to just always allocate a new frame of the requested
269 // size. This isn't the most efficient thing, but for now we don't
270 // care. Note that _Jv_JNI_PushLocalFrame relies on this right now.
271
272 _Jv_JNI_LocalFrame *frame;
273 try
274 {
275 frame = (_Jv_JNI_LocalFrame *) _Jv_Malloc (sizeof (_Jv_JNI_LocalFrame)
276 + size * sizeof (jobject));
277 }
278 catch (jthrowable t)
279 {
280 env->ex = t;
281 return JNI_ERR;
282 }
283
284 frame->marker = MARK_NONE;
285 frame->size = size;
286 memset (&frame->vec[0], 0, size * sizeof (jobject));
287 frame->next = env->locals;
288 env->locals = frame;
289
290 return 0;
291}
292
293static jint
294_Jv_JNI_PushLocalFrame (JNIEnv *env, jint size)
295{
296 jint r = _Jv_JNI_EnsureLocalCapacity (env, size);
297 if (r < 0)
298 return r;
299
300 // The new frame is on top.
301 env->locals->marker = MARK_USER;
302
303 return 0;
304}
305
306static jobject
307_Jv_JNI_NewLocalRef (JNIEnv *env, jobject obj)
308{
309 // This seems weird but I think it is correct.
310 obj = unwrap (obj);
311
312 // Try to find an open slot somewhere in the topmost frame.
313 _Jv_JNI_LocalFrame *frame = env->locals;
314 bool done = false, set = false;
315 for (; frame != NULL && ! done; frame = frame->next)
316 {
317 for (int i = 0; i < frame->size; ++i)
318 {
319 if (frame->vec[i] == NULL)
320 {
321 set = true;
322 done = true;
323 frame->vec[i] = obj;
324 break;
325 }
326 }
327
328 // If we found a slot, or if the frame we just searched is the
329 // mark frame, then we are done.
330 if (done || frame == NULL || frame->marker != MARK_NONE)
331 break;
332 }
333
334 if (! set)
335 {
336 // No slots, so we allocate a new frame. According to the spec
337 // we could just die here. FIXME: return value.
338 _Jv_JNI_EnsureLocalCapacity (env, 16);
339 // We know the first element of the new frame will be ok.
340 env->locals->vec[0] = obj;
341 }
342
343 mark_for_gc (obj, local_ref_table);
344 return obj;
345}
346
347static jobject
348_Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result, int stop)
349{
350 _Jv_JNI_LocalFrame *rf = env->locals;
351
352 bool done = false;
353 while (rf != NULL && ! done)
354 {
355 for (int i = 0; i < rf->size; ++i)
356 if (rf->vec[i] != NULL)
357 unmark_for_gc (rf->vec[i], local_ref_table);
358
359 // If the frame we just freed is the marker frame, we are done.
360 done = (rf->marker == stop);
361
362 _Jv_JNI_LocalFrame *n = rf->next;
363 // When N==NULL, we've reached the stack-allocated frame, and we
364 // must not free it. However, we must be sure to clear all its
365 // elements, since we might conceivably reuse it.
366 if (n == NULL)
367 {
368 memset (&rf->vec[0], 0, rf->size * sizeof (jobject));
369 break;
370 }
371
372 _Jv_Free (rf);
373 rf = n;
374 }
375
376 // Update the local frame information.
377 env->locals = rf;
378
379 return result == NULL ? NULL : _Jv_JNI_NewLocalRef (env, result);
380}
381
382static jobject
383_Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result)
384{
385 return _Jv_JNI_PopLocalFrame (env, result, MARK_USER);
386}
387
388// Pop a `system' frame from the stack. This is `extern "C"' as it is
389// used by the compiler.
390extern "C" void
391_Jv_JNI_PopSystemFrame (JNIEnv *env)
392{
393 _Jv_JNI_PopLocalFrame (env, NULL, MARK_SYSTEM);
394
395 if (env->ex)
396 {
397 jthrowable t = env->ex;
398 env->ex = NULL;
399 throw t;
400 }
401}
402
403// This function is used from other template functions. It wraps the
404// return value appropriately; we specialize it so that object returns
405// are turned into local references.
406template<typename T>
407static T
408wrap_value (JNIEnv *, T value)
409{
410 return value;
411}
412
413// This specialization is used for jobject, jclass, jstring, jarray,
414// etc.
415template<typename T>
416static T *
417wrap_value (JNIEnv *env, T *value)
418{
419 return (value == NULL
420 ? value
421 : (T *) _Jv_JNI_NewLocalRef (env, (jobject) value));
422}
423
424
425
426
427static jint
428_Jv_JNI_GetVersion (JNIEnv *)
429{
430 return JNI_VERSION_1_2;
431}
432
433static jclass
434_Jv_JNI_DefineClass (JNIEnv *env, jobject loader,
435 const jbyte *buf, jsize bufLen)
436{
437 try
438 {
439 loader = unwrap (loader);
440
441 jbyteArray bytes = JvNewByteArray (bufLen);
442
443 jbyte *elts = elements (bytes);
444 memcpy (elts, buf, bufLen * sizeof (jbyte));
445
446 java::lang::ClassLoader *l
447 = reinterpret_cast<java::lang::ClassLoader *> (loader);
448
449 jclass result = l->defineClass (bytes, 0, bufLen);
450 return (jclass) wrap_value (env, result);
451 }
452 catch (jthrowable t)
453 {
454 env->ex = t;
455 return NULL;
456 }
457}
458
459static jclass
460_Jv_JNI_FindClass (JNIEnv *env, const char *name)
461{
462 // FIXME: assume that NAME isn't too long.
463 int len = strlen (name);
464 char s[len + 1];
465 for (int i = 0; i <= len; ++i)
466 s[i] = (name[i] == '/') ? '.' : name[i];
467
468 jclass r = NULL;
469 try
470 {
471 // This might throw an out of memory exception.
472 jstring n = JvNewStringUTF (s);
473
474 java::lang::ClassLoader *loader = NULL;
475 if (env->klass != NULL)
476 loader = env->klass->getClassLoader ();
477
478 if (loader == NULL)
479 {
480 // FIXME: should use getBaseClassLoader, but we don't have that
481 // yet.
482 loader = java::lang::ClassLoader::getSystemClassLoader ();
483 }
484
485 r = loader->loadClass (n);
486 }
487 catch (jthrowable t)
488 {
489 env->ex = t;
490 }
491
492 return (jclass) wrap_value (env, r);
493}
494
495static jclass
496_Jv_JNI_GetSuperclass (JNIEnv *env, jclass clazz)
497{
498 return (jclass) wrap_value (env, unwrap (clazz)->getSuperclass ());
499}
500
501static jboolean
502_Jv_JNI_IsAssignableFrom(JNIEnv *, jclass clazz1, jclass clazz2)
503{
504 return unwrap (clazz1)->isAssignableFrom (unwrap (clazz2));
505}
506
507static jint
508_Jv_JNI_Throw (JNIEnv *env, jthrowable obj)
509{
510 // We check in case the user did some funky cast.
511 obj = unwrap (obj);
512 JvAssert (obj != NULL && java::lang::Throwable::class$.isInstance (obj));
513 env->ex = obj;
514 return 0;
515}
516
517static jint
518_Jv_JNI_ThrowNew (JNIEnv *env, jclass clazz, const char *message)
519{
520 using namespace java::lang::reflect;
521
522 clazz = unwrap (clazz);
523 JvAssert (java::lang::Throwable::class$.isAssignableFrom (clazz));
524
525 int r = JNI_OK;
526 try
527 {
528 JArray<jclass> *argtypes
529 = (JArray<jclass> *) JvNewObjectArray (1, &java::lang::Class::class$,
530 NULL);
531
532 jclass *elts = elements (argtypes);
533 elts[0] = &StringClass;
534
535 Constructor *cons = clazz->getConstructor (argtypes);
536
537 jobjectArray values = JvNewObjectArray (1, &StringClass, NULL);
538 jobject *velts = elements (values);
539 velts[0] = JvNewStringUTF (message);
540
541 jobject obj = cons->newInstance (values);
542
543 env->ex = reinterpret_cast<jthrowable> (obj);
544 }
545 catch (jthrowable t)
546 {
547 env->ex = t;
548 r = JNI_ERR;
549 }
550
551 return r;
552}
553
554static jthrowable
555_Jv_JNI_ExceptionOccurred (JNIEnv *env)
556{
557 return (jthrowable) wrap_value (env, env->ex);
558}
559
560static void
561_Jv_JNI_ExceptionDescribe (JNIEnv *env)
562{
563 if (env->ex != NULL)
564 env->ex->printStackTrace();
565}
566
567static void
568_Jv_JNI_ExceptionClear (JNIEnv *env)
569{
570 env->ex = NULL;
571}
572
573static jboolean
574_Jv_JNI_ExceptionCheck (JNIEnv *env)
575{
576 return env->ex != NULL;
577}
578
579static void
580_Jv_JNI_FatalError (JNIEnv *, const char *message)
581{
582 JvFail (message);
583}
584
585
586
587
588static jboolean
589_Jv_JNI_IsSameObject (JNIEnv *, jobject obj1, jobject obj2)
590{
591 return unwrap (obj1) == unwrap (obj2);
592}
593
594static 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
620static 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
628static jboolean
629_Jv_JNI_IsInstanceOf (JNIEnv *, jobject obj, jclass clazz)
630{
631 return unwrap (clazz)->isInstance(unwrap (obj));
632}
633
634
635
636
637//
638// This section concerns method invocation.
639//
640
641template<jboolean is_static>
642static jmethodID
643_Jv_JNI_GetAnyMethodID (JNIEnv *env, jclass clazz,
644 const char *name, const char *sig)
645{
646 try
647 {
648 clazz = unwrap (clazz);
649 _Jv_InitClass (clazz);
650
651 _Jv_Utf8Const *name_u = _Jv_makeUtf8Const ((char *) name, -1);
652
653 // FIXME: assume that SIG isn't too long.
654 int len = strlen (sig);
655 char s[len + 1];
656 for (int i = 0; i <= len; ++i)
657 s[i] = (sig[i] == '/') ? '.' : sig[i];
658 _Jv_Utf8Const *sig_u = _Jv_makeUtf8Const ((char *) s, -1);
659
660 JvAssert (! clazz->isPrimitive());
661
662 using namespace java::lang::reflect;
663
664 while (clazz != NULL)
665 {
666 jint count = JvNumMethods (clazz);
667 jmethodID meth = JvGetFirstMethod (clazz);
668
669 for (jint i = 0; i < count; ++i)
670 {
671 if (((is_static && Modifier::isStatic (meth->accflags))
672 || (! is_static && ! Modifier::isStatic (meth->accflags)))
673 && _Jv_equalUtf8Consts (meth->name, name_u)
674 && _Jv_equalUtf8Consts (meth->signature, sig_u))
675 return meth;
676
677 meth = meth->getNextMethod();
678 }
679
680 clazz = clazz->getSuperclass ();
681 }
682
683 env->ex = new java::lang::NoSuchMethodError ();
684 }
685 catch (jthrowable t)
686 {
687 env->ex = t;
688 }
689
690 return NULL;
691}
692
693// This is a helper function which turns a va_list into an array of
694// `jvalue's. It needs signature information in order to do its work.
695// The array of values must already be allocated.
696static void
697array_from_valist (jvalue *values, JArray<jclass> *arg_types, va_list vargs)
698{
699 jclass *arg_elts = elements (arg_types);
700 for (int i = 0; i < arg_types->length; ++i)
701 {
702 if (arg_elts[i] == JvPrimClass (byte))
703 values[i].b = (jbyte) va_arg (vargs, int);
704 else if (arg_elts[i] == JvPrimClass (short))
705 values[i].s = (jshort) va_arg (vargs, int);
706 else if (arg_elts[i] == JvPrimClass (int))
707 values[i].i = va_arg (vargs, jint);
708 else if (arg_elts[i] == JvPrimClass (long))
709 values[i].j = va_arg (vargs, jlong);
710 else if (arg_elts[i] == JvPrimClass (float))
711 values[i].f = va_arg (vargs, jfloat);
712 else if (arg_elts[i] == JvPrimClass (double))
713 values[i].d = va_arg (vargs, jdouble);
714 else if (arg_elts[i] == JvPrimClass (boolean))
715 values[i].z = (jboolean) va_arg (vargs, int);
716 else if (arg_elts[i] == JvPrimClass (char))
717 values[i].c = (jchar) va_arg (vargs, int);
718 else
719 {
720 // An object.
721 values[i].l = unwrap (va_arg (vargs, jobject));
722 }
723 }
724}
725
726// This can call any sort of method: virtual, "nonvirtual", static, or
727// constructor.
728template<typename T, invocation_type style>
729static T
730_Jv_JNI_CallAnyMethodV (JNIEnv *env, jobject obj, jclass klass,
731 jmethodID id, va_list vargs)
732{
733 obj = unwrap (obj);
734 klass = unwrap (klass);
735
736 if (style == normal)
737 id = _Jv_LookupDeclaredMethod (obj->getClass (), id->name, id->signature);
738
739 jclass decl_class = klass ? klass : obj->getClass ();
740 JvAssert (decl_class != NULL);
741
742 jclass return_type;
743 JArray<jclass> *arg_types;
744
745 try
746 {
747 _Jv_GetTypesFromSignature (id, decl_class,
748 &arg_types, &return_type);
749
750 jvalue args[arg_types->length];
751 array_from_valist (args, arg_types, vargs);
752
753 // For constructors we need to pass the Class we are instantiating.
754 if (style == constructor)
755 return_type = klass;
756
757 jvalue result;
758 jthrowable ex = _Jv_CallAnyMethodA (obj, return_type, id,
759 style == constructor,
760 arg_types, args, &result);
761
762 if (ex != NULL)
763 env->ex = ex;
764
765 // We cheat a little here. FIXME.
766 return wrap_value (env, * (T *) &result);
767 }
768 catch (jthrowable t)
769 {
770 env->ex = t;
771 }
772
773 return wrap_value (env, (T) 0);
774}
775
776template<typename T, invocation_type style>
777static T
778_Jv_JNI_CallAnyMethod (JNIEnv *env, jobject obj, jclass klass,
779 jmethodID method, ...)
780{
781 va_list args;
782 T result;
783
784 va_start (args, method);
785 result = _Jv_JNI_CallAnyMethodV<T, style> (env, obj, klass, method, args);
786 va_end (args);
787
788 return result;
789}
790
791template<typename T, invocation_type style>
792static T
793_Jv_JNI_CallAnyMethodA (JNIEnv *env, jobject obj, jclass klass,
794 jmethodID id, jvalue *args)
795{
796 obj = unwrap (obj);
797 klass = unwrap (klass);
798
799 if (style == normal)
800 id = _Jv_LookupDeclaredMethod (obj->getClass (), id->name, id->signature);
801
802 jclass decl_class = klass ? klass : obj->getClass ();
803 JvAssert (decl_class != NULL);
804
805 jclass return_type;
806 JArray<jclass> *arg_types;
807 try
808 {
809 _Jv_GetTypesFromSignature (id, decl_class,
810 &arg_types, &return_type);
811
812 // For constructors we need to pass the Class we are instantiating.
813 if (style == constructor)
814 return_type = klass;
815
816 // Unwrap arguments as required. Eww.
817 jclass *type_elts = elements (arg_types);
818 jvalue arg_copy[arg_types->length];
819 for (int i = 0; i < arg_types->length; ++i)
820 {
821 if (type_elts[i]->isPrimitive ())
822 arg_copy[i] = args[i];
823 else
824 arg_copy[i].l = unwrap (args[i].l);
825 }
826
827 jvalue result;
828 jthrowable ex = _Jv_CallAnyMethodA (obj, return_type, id,
829 style == constructor,
830 arg_types, arg_copy, &result);
831
832 if (ex != NULL)
833 env->ex = ex;
834
835 // We cheat a little here. FIXME.
836 return wrap_value (env, * (T *) &result);
837 }
838 catch (jthrowable t)
839 {
840 env->ex = t;
841 }
842
843 return wrap_value (env, (T) 0);
844}
845
846template<invocation_type style>
847static void
848_Jv_JNI_CallAnyVoidMethodV (JNIEnv *env, jobject obj, jclass klass,
849 jmethodID id, va_list vargs)
850{
851 obj = unwrap (obj);
852 klass = unwrap (klass);
853
854 if (style == normal)
855 id = _Jv_LookupDeclaredMethod (obj->getClass (), id->name, id->signature);
856
857 jclass decl_class = klass ? klass : obj->getClass ();
858 JvAssert (decl_class != NULL);
859
860 jclass return_type;
861 JArray<jclass> *arg_types;
862 try
863 {
864 _Jv_GetTypesFromSignature (id, decl_class,
865 &arg_types, &return_type);
866
867 jvalue args[arg_types->length];
868 array_from_valist (args, arg_types, vargs);
869
870 // For constructors we need to pass the Class we are instantiating.
871 if (style == constructor)
872 return_type = klass;
873
874 jthrowable ex = _Jv_CallAnyMethodA (obj, return_type, id,
875 style == constructor,
876 arg_types, args, NULL);
877
878 if (ex != NULL)
879 env->ex = ex;
880 }
881 catch (jthrowable t)
882 {
883 env->ex = t;
884 }
885}
886
887template<invocation_type style>
888static void
889_Jv_JNI_CallAnyVoidMethod (JNIEnv *env, jobject obj, jclass klass,
890 jmethodID method, ...)
891{
892 va_list args;
893
894 va_start (args, method);
895 _Jv_JNI_CallAnyVoidMethodV<style> (env, obj, klass, method, args);
896 va_end (args);
897}
898
899template<invocation_type style>
900static void
901_Jv_JNI_CallAnyVoidMethodA (JNIEnv *env, jobject obj, jclass klass,
902 jmethodID id, jvalue *args)
903{
904 if (style == normal)
905 id = _Jv_LookupDeclaredMethod (obj->getClass (), id->name, id->signature);
906
907 jclass decl_class = klass ? klass : obj->getClass ();
908 JvAssert (decl_class != NULL);
909
910 jclass return_type;
911 JArray<jclass> *arg_types;
912 try
913 {
914 _Jv_GetTypesFromSignature (id, decl_class,
915 &arg_types, &return_type);
916
917 // Unwrap arguments as required. Eww.
918 jclass *type_elts = elements (arg_types);
919 jvalue arg_copy[arg_types->length];
920 for (int i = 0; i < arg_types->length; ++i)
921 {
922 if (type_elts[i]->isPrimitive ())
923 arg_copy[i] = args[i];
924 else
925 arg_copy[i].l = unwrap (args[i].l);
926 }
927
928 jthrowable ex = _Jv_CallAnyMethodA (obj, return_type, id,
929 style == constructor,
930 arg_types, args, NULL);
931
932 if (ex != NULL)
933 env->ex = ex;
934 }
935 catch (jthrowable t)
936 {
937 env->ex = t;
938 }
939}
940
941// Functions with this signature are used to implement functions in
942// the CallMethod family.
943template<typename T>
944static T
945_Jv_JNI_CallMethodV (JNIEnv *env, jobject obj, jmethodID id, va_list args)
946{
947 return _Jv_JNI_CallAnyMethodV<T, normal> (env, obj, NULL, id, args);
948}
949
950// Functions with this signature are used to implement functions in
951// the CallMethod family.
952template<typename T>
953static T
954_Jv_JNI_CallMethod (JNIEnv *env, jobject obj, jmethodID id, ...)
955{
956 va_list args;
957 T result;
958
959 va_start (args, id);
960 result = _Jv_JNI_CallAnyMethodV<T, normal> (env, obj, NULL, id, args);
961 va_end (args);
962
963 return result;
964}
965
966// Functions with this signature are used to implement functions in
967// the CallMethod family.
968template<typename T>
969static T
970_Jv_JNI_CallMethodA (JNIEnv *env, jobject obj, jmethodID id, jvalue *args)
971{
972 return _Jv_JNI_CallAnyMethodA<T, normal> (env, obj, NULL, id, args);
973}
974
975static void
976_Jv_JNI_CallVoidMethodV (JNIEnv *env, jobject obj, jmethodID id, va_list args)
977{
978 _Jv_JNI_CallAnyVoidMethodV<normal> (env, obj, NULL, id, args);
979}
980
981static void
982_Jv_JNI_CallVoidMethod (JNIEnv *env, jobject obj, jmethodID id, ...)
983{
984 va_list args;
985
986 va_start (args, id);
987 _Jv_JNI_CallAnyVoidMethodV<normal> (env, obj, NULL, id, args);
988 va_end (args);
989}
990
991static void
992_Jv_JNI_CallVoidMethodA (JNIEnv *env, jobject obj, jmethodID id, jvalue *args)
993{
994 _Jv_JNI_CallAnyVoidMethodA<normal> (env, obj, NULL, id, args);
995}
996
997// Functions with this signature are used to implement functions in
998// the CallStaticMethod family.
999template<typename T>
1000static T
1001_Jv_JNI_CallStaticMethodV (JNIEnv *env, jclass klass,
1002 jmethodID id, va_list args)
1003{
1004 JvAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC));
1005 JvAssert (java::lang::Class::class$.isInstance (unwrap (klass)));
1006
1007 return _Jv_JNI_CallAnyMethodV<T, static_type> (env, NULL, klass, id, args);
1008}
1009
1010// Functions with this signature are used to implement functions in
1011// the CallStaticMethod family.
1012template<typename T>
1013static T
1014_Jv_JNI_CallStaticMethod (JNIEnv *env, jclass klass, jmethodID id, ...)
1015{
1016 va_list args;
1017 T result;
1018
1019 JvAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC));
1020 JvAssert (java::lang::Class::class$.isInstance (unwrap (klass)));
1021
1022 va_start (args, id);
1023 result = _Jv_JNI_CallAnyMethodV<T, static_type> (env, NULL, klass,
1024 id, args);
1025 va_end (args);
1026
1027 return result;
1028}
1029
1030// Functions with this signature are used to implement functions in
1031// the CallStaticMethod family.
1032template<typename T>
1033static T
1034_Jv_JNI_CallStaticMethodA (JNIEnv *env, jclass klass, jmethodID id,
1035 jvalue *args)
1036{
1037 JvAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC));
1038 JvAssert (java::lang::Class::class$.isInstance (unwrap (klass)));
1039
1040 return _Jv_JNI_CallAnyMethodA<T, static_type> (env, NULL, klass, id, args);
1041}
1042
1043static void
1044_Jv_JNI_CallStaticVoidMethodV (JNIEnv *env, jclass klass, jmethodID id,
1045 va_list args)
1046{
1047 _Jv_JNI_CallAnyVoidMethodV<static_type> (env, NULL, klass, id, args);
1048}
1049
1050static void
1051_Jv_JNI_CallStaticVoidMethod (JNIEnv *env, jclass klass, jmethodID id, ...)
1052{
1053 va_list args;
1054
1055 va_start (args, id);
1056 _Jv_JNI_CallAnyVoidMethodV<static_type> (env, NULL, klass, id, args);
1057 va_end (args);
1058}
1059
1060static void
1061_Jv_JNI_CallStaticVoidMethodA (JNIEnv *env, jclass klass, jmethodID id,
1062 jvalue *args)
1063{
1064 _Jv_JNI_CallAnyVoidMethodA<static_type> (env, NULL, klass, id, args);
1065}
1066
1067static jobject
1068_Jv_JNI_NewObjectV (JNIEnv *env, jclass klass,
1069 jmethodID id, va_list args)
1070{
1071 JvAssert (klass && ! klass->isArray ());
1072 JvAssert (! strcmp (id->name->data, "<init>")
1073 && id->signature->length > 2
1074 && id->signature->data[0] == '('
1075 && ! strcmp (&id->signature->data[id->signature->length - 2],
1076 ")V"));
1077
1078 return _Jv_JNI_CallAnyMethodV<jobject, constructor> (env, NULL, klass,
1079 id, args);
1080}
1081
1082static jobject
1083_Jv_JNI_NewObject (JNIEnv *env, jclass klass, jmethodID id, ...)
1084{
1085 JvAssert (klass && ! klass->isArray ());
1086 JvAssert (! strcmp (id->name->data, "<init>")
1087 && id->signature->length > 2
1088 && id->signature->data[0] == '('
1089 && ! strcmp (&id->signature->data[id->signature->length - 2],
1090 ")V"));
1091
1092 va_list args;
1093 jobject result;
1094
1095 va_start (args, id);
1096 result = _Jv_JNI_CallAnyMethodV<jobject, constructor> (env, NULL, klass,
1097 id, args);
1098 va_end (args);
1099
1100 return result;
1101}
1102
1103static jobject
1104_Jv_JNI_NewObjectA (JNIEnv *env, jclass klass, jmethodID id,
1105 jvalue *args)
1106{
1107 JvAssert (klass && ! klass->isArray ());
1108 JvAssert (! strcmp (id->name->data, "<init>")
1109 && id->signature->length > 2
1110 && id->signature->data[0] == '('
1111 && ! strcmp (&id->signature->data[id->signature->length - 2],
1112 ")V"));
1113
1114 return _Jv_JNI_CallAnyMethodA<jobject, constructor> (env, NULL, klass,
1115 id, args);
1116}
1117
1118
1119
1120
1121template<typename T>
1122static T
1123_Jv_JNI_GetField (JNIEnv *env, jobject obj, jfieldID field)
1124{
1125 obj = unwrap (obj);
1126 JvAssert (obj);
1127 T *ptr = (T *) ((char *) obj + field->getOffset ());
1128 return wrap_value (env, *ptr);
1129}
1130
1131template<typename T>
1132static void
1133_Jv_JNI_SetField (JNIEnv *, jobject obj, jfieldID field, T value)
1134{
1135 obj = unwrap (obj);
1136 value = unwrap (value);
1137
1138 JvAssert (obj);
1139 T *ptr = (T *) ((char *) obj + field->getOffset ());
1140 *ptr = value;
1141}
1142
1143template<jboolean is_static>
1144static jfieldID
1145_Jv_JNI_GetAnyFieldID (JNIEnv *env, jclass clazz,
1146 const char *name, const char *sig)
1147{
1148 try
1149 {
1150 clazz = unwrap (clazz);
1151
1152 _Jv_InitClass (clazz);
1153
1154 _Jv_Utf8Const *a_name = _Jv_makeUtf8Const ((char *) name, -1);
1155
1156 // FIXME: assume that SIG isn't too long.
1157 int len = strlen (sig);
1158 char s[len + 1];
1159 for (int i = 0; i <= len; ++i)
1160 s[i] = (sig[i] == '/') ? '.' : sig[i];
1161 jclass field_class = _Jv_FindClassFromSignature ((char *) s, NULL);
1162
1163 // FIXME: what if field_class == NULL?
1164
1165 java::lang::ClassLoader *loader = clazz->getClassLoader ();
1166 while (clazz != NULL)
1167 {
1168 // We acquire the class lock so that fields aren't resolved
1169 // while we are running.
1170 JvSynchronize sync (clazz);
1171
1172 jint count = (is_static
1173 ? JvNumStaticFields (clazz)
1174 : JvNumInstanceFields (clazz));
1175 jfieldID field = (is_static
1176 ? JvGetFirstStaticField (clazz)
1177 : JvGetFirstInstanceField (clazz));
1178 for (jint i = 0; i < count; ++i)
1179 {
1180 _Jv_Utf8Const *f_name = field->getNameUtf8Const(clazz);
1181
1182 // The field might be resolved or it might not be. It
1183 // is much simpler to always resolve it.
1184 _Jv_ResolveField (field, loader);
1185 if (_Jv_equalUtf8Consts (f_name, a_name)
1186 && field->getClass() == field_class)
1187 return field;
1188
1189 field = field->getNextField ();
1190 }
1191
1192 clazz = clazz->getSuperclass ();
1193 }
1194
1195 env->ex = new java::lang::NoSuchFieldError ();
1196 }