OSDN Git Service

2004-12-10 Andrew Haley <aph@redhat.com>
[pf3gnuchains/gcc-fork.git] / libjava / java / lang / reflect / natMethod.cc
1 // natMethod.cc - Native code for Method class.
2
3 /* Copyright (C) 1998, 1999, 2000, 2001 , 2002, 2003, 2004 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 <gcj/cni.h>
14 #include <jvm.h>
15 #include <jni.h>
16
17 #include <java/lang/reflect/Method.h>
18 #include <java/lang/reflect/Constructor.h>
19 #include <java/lang/reflect/InvocationTargetException.h>
20 #include <java/lang/reflect/Modifier.h>
21
22 #include <java/lang/Void.h>
23 #include <java/lang/Byte.h>
24 #include <java/lang/Boolean.h>
25 #include <java/lang/Character.h>
26 #include <java/lang/Short.h>
27 #include <java/lang/Integer.h>
28 #include <java/lang/Long.h>
29 #include <java/lang/Float.h>
30 #include <java/lang/Double.h>
31 #include <java/lang/IllegalAccessException.h>
32 #include <java/lang/IllegalArgumentException.h>
33 #include <java/lang/IncompatibleClassChangeError.h>
34 #include <java/lang/NullPointerException.h>
35 #include <java/lang/ArrayIndexOutOfBoundsException.h>
36 #include <java/lang/VirtualMachineError.h>
37 #include <java/lang/Class.h>
38 #include <gcj/method.h>
39 #include <gnu/gcj/RawData.h>
40
41 #include <stdlib.h>
42
43 #if USE_LIBFFI
44 #include <ffi.h>
45 #else
46 #include <java/lang/UnsupportedOperationException.h>
47 #endif
48
49 struct cpair
50 {
51   jclass prim;
52   jclass wrap;
53 };
54
55 // This is used to determine when a primitive widening conversion is
56 // allowed.
57 static cpair primitives[] =
58 {
59 #define BOOLEAN 0
60   { JvPrimClass (boolean), &java::lang::Boolean::class$ },
61   { JvPrimClass (byte), &java::lang::Byte::class$ },
62 #define SHORT 2
63   { JvPrimClass (short), &java::lang::Short::class$ },
64 #define CHAR 3
65   { JvPrimClass (char), &java::lang::Character::class$ },
66   { JvPrimClass (int), &java::lang::Integer::class$ },
67   { JvPrimClass (long), &java::lang::Long::class$ },
68   { JvPrimClass (float), &java::lang::Float::class$ },
69   { JvPrimClass (double), &java::lang::Double::class$ },
70   { NULL, NULL }
71 };
72
73 static inline jboolean
74 can_widen (jclass from, jclass to)
75 {
76   int fromx = -1, tox = -1;
77
78   for (int i = 0; primitives[i].prim; ++i)
79     {
80       if (primitives[i].wrap == from)
81         fromx = i;
82       if (primitives[i].prim == to)
83         tox = i;
84     }
85
86   // Can't handle a miss.
87   if (fromx == -1 || tox == -1)
88     return false;
89   // Boolean arguments may not be widened.
90   if (fromx == BOOLEAN && tox != BOOLEAN)
91     return false;
92   // Nothing promotes to char.
93   if (tox == CHAR && fromx != CHAR)
94     return false;
95
96   return fromx <= tox;
97 }
98
99 #ifdef USE_LIBFFI
100 static inline ffi_type *
101 get_ffi_type (jclass klass)
102 {
103   // A special case.
104   if (klass == NULL)
105     return &ffi_type_pointer;
106
107   ffi_type *r;
108   if (klass == JvPrimClass (byte))
109     r = &ffi_type_sint8;
110   else if (klass == JvPrimClass (short))
111     r = &ffi_type_sint16;
112   else if (klass == JvPrimClass (int))
113     r = &ffi_type_sint32;
114   else if (klass == JvPrimClass (long))
115     r = &ffi_type_sint64;
116   else if (klass == JvPrimClass (float))
117     r = &ffi_type_float;
118   else if (klass == JvPrimClass (double))
119     r = &ffi_type_double;
120   else if (klass == JvPrimClass (boolean))
121     {
122       // On some platforms a bool is a byte, on others an int.
123       if (sizeof (jboolean) == sizeof (jbyte))
124         r = &ffi_type_sint8;
125       else
126         {
127           JvAssert (sizeof (jboolean) == sizeof (jint));
128           r = &ffi_type_sint32;
129         }
130     }
131   else if (klass == JvPrimClass (char))
132     r = &ffi_type_uint16;
133   else
134     {
135       JvAssert (! klass->isPrimitive());
136       r = &ffi_type_pointer;
137     }
138
139   return r;
140 }
141 #endif // USE_LIBFFI
142
143 jobject
144 java::lang::reflect::Method::invoke (jobject obj, jobjectArray args)
145 {
146   using namespace java::lang::reflect;
147   jclass iface = NULL;
148   
149   if (parameter_types == NULL)
150     getType ();
151     
152   jmethodID meth = _Jv_FromReflectedMethod (this);
153
154   if (Modifier::isStatic(meth->accflags))
155     {
156       // We have to initialize a static class.  It is safe to do this
157       // here and not in _Jv_CallAnyMethodA because JNI initializes a
158       // class whenever a method lookup is done.
159       _Jv_InitClass (declaringClass);
160     }
161   else
162     {
163       jclass objClass = JV_CLASS (obj);
164       if (! _Jv_IsAssignableFrom (declaringClass, objClass))
165         throw new java::lang::IllegalArgumentException;
166     }
167
168   // Check accessibility, if required.
169   if (! (Modifier::isPublic (meth->accflags) || this->isAccessible()))
170     {
171       gnu::gcj::runtime::StackTrace *t 
172         = new gnu::gcj::runtime::StackTrace(4);
173       Class *caller = NULL;
174       try
175         {
176           for (int i = 1; !caller; i++)
177             {
178               caller = t->classAt (i);
179             }
180         }
181       catch (::java::lang::ArrayIndexOutOfBoundsException *e)
182         {
183         }
184
185       if (! _Jv_CheckAccess(caller, declaringClass, meth->accflags))
186         throw new IllegalAccessException;
187     }
188
189   if (declaringClass->isInterface())
190     iface = declaringClass;
191   
192   return _Jv_CallAnyMethodA (obj, return_type, meth, false,
193                              parameter_types, args, iface);
194 }
195
196 jint
197 java::lang::reflect::Method::getModifiers ()
198 {
199   // Ignore all unknown flags.
200   return _Jv_FromReflectedMethod (this)->accflags & Modifier::ALL_FLAGS;
201 }
202
203 jstring
204 java::lang::reflect::Method::getName ()
205 {
206   if (name == NULL)
207     name = _Jv_NewStringUtf8Const (_Jv_FromReflectedMethod (this)->name);
208   return name;
209 }
210
211 /* Internal method to set return_type and parameter_types fields. */
212
213 void
214 java::lang::reflect::Method::getType ()
215 {
216   _Jv_Method *method = _Jv_FromReflectedMethod (this);
217   _Jv_GetTypesFromSignature (method,
218                              declaringClass,
219                              &parameter_types,
220                              &return_type);
221
222   int count = 0;
223   if (method->throws != NULL)
224     {
225       while (method->throws[count] != NULL)
226         ++count;
227     }
228
229   exception_types
230     = (JArray<jclass> *) JvNewObjectArray (count, &java::lang::Class::class$,
231                                            NULL);
232   jclass *elts = elements (exception_types);
233   for (int i = 0; i < count; ++i)
234     elts[i] = _Jv_FindClass (method->throws[i],
235                              declaringClass->getClassLoaderInternal ());
236 }
237
238 void
239 _Jv_GetTypesFromSignature (jmethodID method,
240                            jclass declaringClass,
241                            JArray<jclass> **arg_types_out,
242                            jclass *return_type_out)
243 {
244
245   _Jv_Utf8Const* sig = method->signature;
246   java::lang::ClassLoader *loader = declaringClass->getClassLoaderInternal();
247   char *ptr = sig->chars();
248   int numArgs = 0;
249   /* First just count the number of parameters. */
250   for (; ; ptr++)
251     {
252       switch (*ptr)
253         {
254         case 0:
255         case ')':
256         case 'V':
257           break;
258         case '[':
259         case '(':
260           continue;
261         case 'B':
262         case 'C':
263         case 'D':
264         case 'F':
265         case 'S':
266         case 'I':
267         case 'J':
268         case 'Z':
269           numArgs++;
270           continue;
271         case 'L':
272           numArgs++;
273           do 
274             ptr++;
275           while (*ptr != ';' && ptr[1] != '\0');
276           continue;
277         }
278       break;
279     }
280
281   JArray<jclass> *args = (JArray<jclass> *)
282     JvNewObjectArray (numArgs, &java::lang::Class::class$, NULL);
283   jclass* argPtr = elements (args);
284   for (ptr = sig->chars(); *ptr != '\0'; ptr++)
285     {
286       int num_arrays = 0;
287       jclass type;
288       for (; *ptr == '[';  ptr++)
289         num_arrays++;
290       switch (*ptr)
291         {
292         default:
293           return;
294         case ')':
295           argPtr = return_type_out;
296           continue;
297         case '(':
298           continue;
299         case 'V':
300         case 'B':
301         case 'C':
302         case 'D':
303         case 'F':
304         case 'S':
305         case 'I':
306         case 'J':
307         case 'Z':
308           type = _Jv_FindClassFromSignature(ptr, loader);
309           break;
310         case 'L':
311           type = _Jv_FindClassFromSignature(ptr, loader);
312           do 
313             ptr++;
314           while (*ptr != ';' && ptr[1] != '\0');
315           break;
316         }
317
318       while (--num_arrays >= 0)
319         type = _Jv_GetArrayClass (type, loader);
320       // ARGPTR can be NULL if we are processing the return value of a
321       // call from Constructor.
322       if (argPtr)
323         *argPtr++ = type;
324     }
325   *arg_types_out = args;
326 }
327
328 // This is a very rough analog of the JNI CallNonvirtual<type>MethodA
329 // functions.  It handles both Methods and Constructors, and it can
330 // handle any return type.  In the Constructor case, the `obj'
331 // argument is unused and should be NULL; also, the `return_type' is
332 // the class that the constructor will construct.  RESULT is a pointer
333 // to a `jvalue' (see jni.h); for a void method this should be NULL.
334 // This function returns an exception (if one was thrown), or NULL if
335 // the call went ok.
336 void
337 _Jv_CallAnyMethodA (jobject obj,
338                     jclass return_type,
339                     jmethodID meth,
340                     jboolean is_constructor,
341                     jboolean is_virtual_call,
342                     JArray<jclass> *parameter_types,
343                     jvalue *args,
344                     jvalue *result,
345                     jboolean is_jni_call,
346                     jclass iface)
347 {
348   using namespace java::lang::reflect;
349   
350 #ifdef USE_LIBFFI
351   JvAssert (! is_constructor || ! obj);
352   JvAssert (! is_constructor || return_type);
353
354   // See whether call needs an object as the first argument.  A
355   // constructor does need a `this' argument, but it is one we create.
356   jboolean needs_this = false;
357   if (is_constructor
358       || ! Modifier::isStatic(meth->accflags))
359     needs_this = true;
360
361   int param_count = parameter_types->length;
362   if (needs_this)
363     ++param_count;
364
365   ffi_type *rtype;
366   // A constructor itself always returns void.
367   if (is_constructor || return_type == JvPrimClass (void))
368     rtype = &ffi_type_void;
369   else
370     rtype = get_ffi_type (return_type);
371   ffi_type **argtypes = (ffi_type **) __builtin_alloca (param_count
372                                                         * sizeof (ffi_type *));
373
374   jclass *paramelts = elements (parameter_types);
375
376   // Special case for the `this' argument of a constructor.  Note that
377   // the JDK 1.2 docs specify that the new object must be allocated
378   // before argument conversions are done.
379   if (is_constructor)
380     obj = _Jv_AllocObject (return_type);
381
382   const int size_per_arg = sizeof(jvalue);
383   ffi_cif cif;
384
385   char *p = (char *) __builtin_alloca (param_count * size_per_arg);
386                 // Overallocate to get correct alignment.
387   void **values = (void **)
388                         __builtin_alloca (param_count * sizeof (void *));
389
390   int i = 0;
391   if (needs_this)
392     {
393       // The `NULL' type is `Object'.
394       argtypes[i] = get_ffi_type (NULL);
395       values[i] = p;
396       memcpy (p, &obj, sizeof (jobject));
397       p += size_per_arg;
398       ++i;
399     }
400
401   for (int arg = 0; i < param_count; ++i, ++arg)
402     {
403       int tsize;
404
405       argtypes[i] = get_ffi_type (paramelts[arg]);
406       if (paramelts[arg]->isPrimitive())
407         tsize = paramelts[arg]->size();
408       else
409         tsize = sizeof (jobject);
410
411       // Copy appropriate bits from the jvalue into the ffi array.
412       // FIXME: we could do this copying all in one loop, above, by
413       // over-allocating a bit.
414       // How do we do this without breaking big-endian platforms?
415       values[i] = p;
416       memcpy (p, &args[arg], tsize);
417       p += size_per_arg;
418     }
419
420   if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, param_count,
421                     rtype, argtypes) != FFI_OK)
422     throw new java::lang::VirtualMachineError(JvNewStringLatin1("internal error: ffi_prep_cif failed"));
423
424   using namespace java::lang;
425   using namespace java::lang::reflect;
426
427   union
428   {
429     ffi_arg i;
430     jobject o;
431     jlong l;
432     jfloat f;
433     jdouble d;
434   } ffi_result;
435
436   switch (rtype->type)
437     {
438     case FFI_TYPE_VOID:
439       break;
440     case FFI_TYPE_SINT8:
441       result->b = 0;
442       break;
443     case FFI_TYPE_SINT16:
444       result->s = 0;
445       break;
446     case FFI_TYPE_UINT16:
447       result->c = 0;
448       break;
449     case FFI_TYPE_SINT32:
450       result->i = 0;
451       break;
452     case FFI_TYPE_SINT64:
453       result->j = 0;
454       break;
455     case FFI_TYPE_FLOAT:
456       result->f = 0;
457       break;
458     case FFI_TYPE_DOUBLE:
459       result->d = 0;
460       break;
461     case FFI_TYPE_POINTER:
462       result->l = 0;
463       break;
464     default:
465       JvFail ("Unknown ffi_call return type");
466       break;
467     }
468
469   void *ncode;
470
471   // FIXME: If a vtable index is -1 at this point it is invalid, so we
472   // have to use the ncode.  
473   //
474   // This can happen because methods in final classes don't have
475   // vtable entries, but _Jv_isVirtualMethod() doesn't know that.  We
476   // could solve this problem by allocating a vtable index for methods
477   // in final classes.
478   if (is_virtual_call 
479       && ! Modifier::isFinal (meth->accflags)
480       && (_Jv_ushort)-1 != meth->index)
481     {
482       _Jv_VTable *vtable = *(_Jv_VTable **) obj;
483       if (iface == NULL)
484         {
485           if (is_jni_call && Modifier::isAbstract (meth->accflags))
486             {
487               // With JNI we don't know if this is an interface call
488               // or a call to an abstract method.  Look up the method
489               // by name, the slow way.
490               _Jv_Method *concrete_meth
491                 = _Jv_LookupDeclaredMethod (vtable->clas,
492                                             meth->name,
493                                             meth->signature,
494                                             NULL);
495               if (concrete_meth == NULL
496                   || concrete_meth->ncode == NULL
497                   || Modifier::isAbstract(concrete_meth->accflags))
498                 throw new java::lang::IncompatibleClassChangeError
499                   (_Jv_GetMethodString (vtable->clas, meth->name));
500               ncode = concrete_meth->ncode;
501             }
502           else
503             ncode = vtable->get_method (meth->index);
504         }
505       else
506         ncode = _Jv_LookupInterfaceMethodIdx (vtable->clas, iface,
507                                               meth->index);
508     }
509   else
510     {
511       ncode = meth->ncode;
512     }
513
514   try
515     {
516       ffi_call (&cif, (void (*)()) ncode, &ffi_result, values);
517     }
518   catch (Throwable *ex)
519     {
520       // For JNI we just throw the real error.  For reflection, we
521       // wrap the underlying method's exception in an
522       // InvocationTargetException.
523       if (! is_jni_call)
524         ex = new InvocationTargetException (ex);
525       throw ex;
526     }
527
528   // Since ffi_call returns integer values promoted to a word, use
529   // a narrowing conversion for jbyte, jchar, etc. results.
530   // Note that boolean is handled either by the FFI_TYPE_SINT8 or
531   // FFI_TYPE_SINT32 case.
532   if (is_constructor)
533     result->l = obj;
534   else
535     {
536       switch (rtype->type)
537         {
538         case FFI_TYPE_VOID:
539           break;
540         case FFI_TYPE_SINT8:
541           result->b = (jbyte)ffi_result.i;
542           break;
543         case FFI_TYPE_SINT16:
544           result->s = (jshort)ffi_result.i;
545           break;
546         case FFI_TYPE_UINT16:
547           result->c = (jchar)ffi_result.i;
548           break;
549         case FFI_TYPE_SINT32:
550           result->i = (jint)ffi_result.i;
551           break;
552         case FFI_TYPE_SINT64:
553           result->j = (jlong)ffi_result.l;
554           break;
555         case FFI_TYPE_FLOAT:
556           result->f = (jfloat)ffi_result.f;
557           break;
558         case FFI_TYPE_DOUBLE:
559           result->d = (jdouble)ffi_result.d;
560           break;
561         case FFI_TYPE_POINTER:
562           result->l = (jobject)ffi_result.o;
563           break;
564         default:
565           JvFail ("Unknown ffi_call return type");
566           break;
567         }
568     }
569 #else
570   throw new java::lang::UnsupportedOperationException(JvNewStringLatin1("reflection not available in this build"));
571 #endif // USE_LIBFFI
572 }
573
574 // This is another version of _Jv_CallAnyMethodA, but this one does
575 // more checking and is used by the reflection (and not JNI) code.
576 jobject
577 _Jv_CallAnyMethodA (jobject obj,
578                     jclass return_type,
579                     jmethodID meth,
580                     jboolean is_constructor,
581                     JArray<jclass> *parameter_types,
582                     jobjectArray args,
583                     jclass iface)
584 {
585   if (parameter_types->length == 0 && args == NULL)
586     {
587       // The JDK accepts this, so we do too.
588     }
589   else if (parameter_types->length != args->length)
590     throw new java::lang::IllegalArgumentException;
591
592   int param_count = parameter_types->length;
593
594   jclass *paramelts = elements (parameter_types);
595   jobject *argelts = args == NULL ? NULL : elements (args);
596   jvalue argvals[param_count];
597
598 #define COPY(Where, What, Type) \
599   do { \
600     Type val = (What); \
601     memcpy ((Where), &val, sizeof (Type)); \
602   } while (0)
603
604   for (int i = 0; i < param_count; ++i)
605     {
606       jclass k = argelts[i] ? argelts[i]->getClass() : NULL;
607       if (paramelts[i]->isPrimitive())
608         {
609           if (! argelts[i]
610               || ! k
611               || ! can_widen (k, paramelts[i]))
612             throw new java::lang::IllegalArgumentException;
613             
614           if (paramelts[i] == JvPrimClass (boolean))
615             COPY (&argvals[i],
616                   ((java::lang::Boolean *) argelts[i])->booleanValue(),
617                   jboolean);
618           else if (paramelts[i] == JvPrimClass (char))
619             COPY (&argvals[i],
620                   ((java::lang::Character *) argelts[i])->charValue(),
621                   jchar);
622           else
623             {
624               java::lang::Number *num = (java::lang::Number *) argelts[i];
625               if (paramelts[i] == JvPrimClass (byte))
626                 COPY (&argvals[i], num->byteValue(), jbyte);
627               else if (paramelts[i] == JvPrimClass (short))
628                 COPY (&argvals[i], num->shortValue(), jshort);
629               else if (paramelts[i] == JvPrimClass (int))
630                 COPY (&argvals[i], num->intValue(), jint);
631               else if (paramelts[i] == JvPrimClass (long))
632                 COPY (&argvals[i], num->longValue(), jlong);
633               else if (paramelts[i] == JvPrimClass (float))
634                 COPY (&argvals[i], num->floatValue(), jfloat);
635               else if (paramelts[i] == JvPrimClass (double))
636                 COPY (&argvals[i], num->doubleValue(), jdouble);
637             }
638         }
639       else
640         {
641           if (argelts[i] && ! paramelts[i]->isAssignableFrom (k))
642             throw new java::lang::IllegalArgumentException;
643           COPY (&argvals[i], argelts[i], jobject);
644         }
645     }
646
647   jvalue ret_value;
648   _Jv_CallAnyMethodA (obj, return_type, meth, is_constructor,
649                       _Jv_isVirtualMethod (meth),
650                       parameter_types, argvals, &ret_value,
651                       false, iface);
652
653   jobject r;
654 #define VAL(Wrapper, Field)  (new Wrapper (ret_value.Field))
655   if (is_constructor)
656     r = ret_value.l;
657   else  if (return_type == JvPrimClass (byte))
658     r = VAL (java::lang::Byte, b);
659   else if (return_type == JvPrimClass (short))
660     r = VAL (java::lang::Short, s);
661   else if (return_type == JvPrimClass (int))
662     r = VAL (java::lang::Integer, i);
663   else if (return_type == JvPrimClass (long))
664     r = VAL (java::lang::Long, j);
665   else if (return_type == JvPrimClass (float))
666     r = VAL (java::lang::Float, f);
667   else if (return_type == JvPrimClass (double))
668     r = VAL (java::lang::Double, d);
669   else if (return_type == JvPrimClass (boolean))
670     r = VAL (java::lang::Boolean, z);
671   else if (return_type == JvPrimClass (char))
672     r = VAL (java::lang::Character, c);
673   else if (return_type == JvPrimClass (void))
674     r = NULL;
675   else
676     {
677       JvAssert (return_type == NULL || ! return_type->isPrimitive());
678       r = ret_value.l;
679     }
680
681   return r;
682 }