1 // natMethod.cc - Native code for Method class.
3 /* Copyright (C) 1998, 1999, 2000, 2001 , 2002, 2003 Free Software Foundation
5 This file is part of libgcj.
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
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>
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/NullPointerException.h>
34 #include <java/lang/ArrayIndexOutOfBoundsException.h>
35 #include <java/lang/VirtualMachineError.h>
36 #include <java/lang/Class.h>
37 #include <gcj/method.h>
38 #include <gnu/gcj/RawData.h>
45 #include <java/lang/UnsupportedOperationException.h>
54 // This is used to determine when a primitive widening conversion is
56 static cpair primitives[] =
59 { JvPrimClass (boolean), &java::lang::Boolean::class$ },
60 { JvPrimClass (byte), &java::lang::Byte::class$ },
62 { JvPrimClass (short), &java::lang::Short::class$ },
64 { JvPrimClass (char), &java::lang::Character::class$ },
65 { JvPrimClass (int), &java::lang::Integer::class$ },
66 { JvPrimClass (long), &java::lang::Long::class$ },
67 { JvPrimClass (float), &java::lang::Float::class$ },
68 { JvPrimClass (double), &java::lang::Double::class$ },
72 static inline jboolean
73 can_widen (jclass from, jclass to)
75 int fromx = -1, tox = -1;
77 for (int i = 0; primitives[i].prim; ++i)
79 if (primitives[i].wrap == from)
81 if (primitives[i].prim == to)
85 // Can't handle a miss.
86 if (fromx == -1 || tox == -1)
88 // Boolean arguments may not be widened.
89 if (fromx == BOOLEAN && tox != BOOLEAN)
91 // Nothing promotes to char.
92 if (tox == CHAR && fromx != CHAR)
99 static inline ffi_type *
100 get_ffi_type (jclass klass)
104 return &ffi_type_pointer;
107 if (klass == JvPrimClass (byte))
109 else if (klass == JvPrimClass (short))
110 r = &ffi_type_sint16;
111 else if (klass == JvPrimClass (int))
112 r = &ffi_type_sint32;
113 else if (klass == JvPrimClass (long))
114 r = &ffi_type_sint64;
115 else if (klass == JvPrimClass (float))
117 else if (klass == JvPrimClass (double))
118 r = &ffi_type_double;
119 else if (klass == JvPrimClass (boolean))
121 // On some platforms a bool is a byte, on others an int.
122 if (sizeof (jboolean) == sizeof (jbyte))
126 JvAssert (sizeof (jboolean) == sizeof (jint));
127 r = &ffi_type_sint32;
130 else if (klass == JvPrimClass (char))
131 r = &ffi_type_uint16;
134 JvAssert (! klass->isPrimitive());
135 r = &ffi_type_pointer;
143 java::lang::reflect::Method::invoke (jobject obj, jobjectArray args)
145 using namespace java::lang::reflect;
147 if (parameter_types == NULL)
150 jmethodID meth = _Jv_FromReflectedMethod (this);
154 if (Modifier::isStatic(meth->accflags))
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 objClass = declaringClass;
164 objClass = JV_CLASS (obj);
166 if (! _Jv_IsAssignableFrom (declaringClass, objClass))
167 throw new java::lang::IllegalArgumentException;
170 // Check accessibility, if required.
171 if (! (Modifier::isPublic (meth->accflags) || this->isAccessible()))
173 gnu::gcj::runtime::StackTrace *t
174 = new gnu::gcj::runtime::StackTrace(4);
175 Class *caller = NULL;
178 for (int i = 1; !caller; i++)
180 caller = t->classAt (i);
183 catch (::java::lang::ArrayIndexOutOfBoundsException *e)
187 if (! _Jv_CheckAccess(caller, objClass, meth->accflags))
188 throw new IllegalAccessException;
191 return _Jv_CallAnyMethodA (obj, return_type, meth, false,
192 parameter_types, args);
196 java::lang::reflect::Method::getModifiers ()
198 // Ignore all unknown flags.
199 return _Jv_FromReflectedMethod (this)->accflags & Modifier::ALL_FLAGS;
203 java::lang::reflect::Method::getName ()
206 name = _Jv_NewStringUtf8Const (_Jv_FromReflectedMethod (this)->name);
210 /* Internal method to set return_type and parameter_types fields. */
213 java::lang::reflect::Method::getType ()
215 _Jv_Method *method = _Jv_FromReflectedMethod (this);
216 _Jv_GetTypesFromSignature (method,
222 if (method->throws != NULL)
224 while (method->throws[count] != NULL)
229 = (JArray<jclass> *) JvNewObjectArray (count, &java::lang::Class::class$,
231 jclass *elts = elements (exception_types);
232 for (int i = 0; i < count; ++i)
233 elts[i] = _Jv_FindClass (method->throws[i],
234 declaringClass->getClassLoaderInternal ());
238 _Jv_GetTypesFromSignature (jmethodID method,
239 jclass declaringClass,
240 JArray<jclass> **arg_types_out,
241 jclass *return_type_out)
244 _Jv_Utf8Const* sig = method->signature;
245 java::lang::ClassLoader *loader = declaringClass->getClassLoaderInternal();
246 char *ptr = sig->data;
248 /* First just count the number of parameters. */
274 while (*ptr != ';' && ptr[1] != '\0');
280 JArray<jclass> *args = (JArray<jclass> *)
281 JvNewObjectArray (numArgs, &java::lang::Class::class$, NULL);
282 jclass* argPtr = elements (args);
283 for (ptr = sig->data; *ptr != '\0'; ptr++)
287 for (; *ptr == '['; ptr++)
294 argPtr = return_type_out;
307 type = _Jv_FindClassFromSignature(ptr, loader);
310 type = _Jv_FindClassFromSignature(ptr, loader);
313 while (*ptr != ';' && ptr[1] != '\0');
317 while (--num_arrays >= 0)
318 type = _Jv_GetArrayClass (type, loader);
319 // ARGPTR can be NULL if we are processing the return value of a
320 // call from Constructor.
324 *arg_types_out = args;
327 // This is a very rough analog of the JNI CallNonvirtual<type>MethodA
328 // functions. It handles both Methods and Constructors, and it can
329 // handle any return type. In the Constructor case, the `obj'
330 // argument is unused and should be NULL; also, the `return_type' is
331 // the class that the constructor will construct. RESULT is a pointer
332 // to a `jvalue' (see jni.h); for a void method this should be NULL.
333 // This function returns an exception (if one was thrown), or NULL if
336 _Jv_CallAnyMethodA (jobject obj,
339 jboolean is_constructor,
340 jboolean is_virtual_call,
341 JArray<jclass> *parameter_types,
344 jboolean is_jni_call)
346 using namespace java::lang::reflect;
349 JvAssert (! is_constructor || ! obj);
350 JvAssert (! is_constructor || return_type);
352 // See whether call needs an object as the first argument. A
353 // constructor does need a `this' argument, but it is one we create.
354 jboolean needs_this = false;
356 || ! Modifier::isStatic(meth->accflags))
359 int param_count = parameter_types->length;
364 // A constructor itself always returns void.
365 if (is_constructor || return_type == JvPrimClass (void))
366 rtype = &ffi_type_void;
368 rtype = get_ffi_type (return_type);
369 ffi_type **argtypes = (ffi_type **) __builtin_alloca (param_count
370 * sizeof (ffi_type *));
372 jclass *paramelts = elements (parameter_types);
374 // Special case for the `this' argument of a constructor. Note that
375 // the JDK 1.2 docs specify that the new object must be allocated
376 // before argument conversions are done.
378 obj = JvAllocObject (return_type);
380 const int size_per_arg = sizeof(jvalue);
383 char *p = (char *) __builtin_alloca (param_count * size_per_arg);
384 // Overallocate to get correct alignment.
385 void **values = (void **)
386 __builtin_alloca (param_count * sizeof (void *));
391 // The `NULL' type is `Object'.
392 argtypes[i] = get_ffi_type (NULL);
394 memcpy (p, &obj, sizeof (jobject));
399 for (int arg = 0; i < param_count; ++i, ++arg)
403 argtypes[i] = get_ffi_type (paramelts[arg]);
404 if (paramelts[arg]->isPrimitive())
405 tsize = paramelts[arg]->size();
407 tsize = sizeof (jobject);
409 // Copy appropriate bits from the jvalue into the ffi array.
410 // FIXME: we could do this copying all in one loop, above, by
411 // over-allocating a bit.
412 // How do we do this without breaking big-endian platforms?
414 memcpy (p, &args[arg], tsize);
418 if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, param_count,
419 rtype, argtypes) != FFI_OK)
420 throw new java::lang::VirtualMachineError(JvNewStringLatin1("internal error: ffi_prep_cif failed"));
422 using namespace java::lang;
423 using namespace java::lang::reflect;
441 case FFI_TYPE_SINT16:
444 case FFI_TYPE_UINT16:
447 case FFI_TYPE_SINT32:
450 case FFI_TYPE_SINT64:
456 case FFI_TYPE_DOUBLE:
459 case FFI_TYPE_POINTER:
463 JvFail ("Unknown ffi_call return type");
469 if (is_virtual_call && ! Modifier::isFinal (meth->accflags))
471 _Jv_VTable *vtable = *(_Jv_VTable **) obj;
472 ncode = vtable->get_method (meth->index);
481 ffi_call (&cif, (void (*)()) ncode, &ffi_result, values);
483 catch (Throwable *ex)
485 // For JNI we just throw the real error. For reflection, we
486 // wrap the underlying method's exception in an
487 // InvocationTargetException.
489 ex = new InvocationTargetException (ex);
493 // Since ffi_call returns integer values promoted to a word, use
494 // a narrowing conversion for jbyte, jchar, etc. results.
495 // Note that boolean is handled either by the FFI_TYPE_SINT8 or
496 // FFI_TYPE_SINT32 case.
506 result->b = (jbyte)ffi_result.i;
508 case FFI_TYPE_SINT16:
509 result->s = (jshort)ffi_result.i;
511 case FFI_TYPE_UINT16:
512 result->c = (jchar)ffi_result.i;
514 case FFI_TYPE_SINT32:
515 result->i = (jint)ffi_result.i;
517 case FFI_TYPE_SINT64:
518 result->j = (jlong)ffi_result.l;
521 result->f = (jfloat)ffi_result.f;
523 case FFI_TYPE_DOUBLE:
524 result->d = (jdouble)ffi_result.d;
526 case FFI_TYPE_POINTER:
527 result->l = (jobject)ffi_result.o;
530 JvFail ("Unknown ffi_call return type");
535 throw new java::lang::UnsupportedOperationException(JvNewStringLatin1("reflection not available in this build"));
539 // This is another version of _Jv_CallAnyMethodA, but this one does
540 // more checking and is used by the reflection (and not JNI) code.
542 _Jv_CallAnyMethodA (jobject obj,
545 jboolean is_constructor,
546 JArray<jclass> *parameter_types,
549 if (parameter_types->length == 0 && args == NULL)
551 // The JDK accepts this, so we do too.
553 else if (parameter_types->length != args->length)
554 throw new java::lang::IllegalArgumentException;
556 int param_count = parameter_types->length;
558 jclass *paramelts = elements (parameter_types);
559 jobject *argelts = args == NULL ? NULL : elements (args);
560 jvalue argvals[param_count];
562 #define COPY(Where, What, Type) \
565 memcpy ((Where), &val, sizeof (Type)); \
568 for (int i = 0; i < param_count; ++i)
570 jclass k = argelts[i] ? argelts[i]->getClass() : NULL;
571 if (paramelts[i]->isPrimitive())
575 || ! can_widen (k, paramelts[i]))
576 throw new java::lang::IllegalArgumentException;
578 if (paramelts[i] == JvPrimClass (boolean))
580 ((java::lang::Boolean *) argelts[i])->booleanValue(),
582 else if (paramelts[i] == JvPrimClass (char))
584 ((java::lang::Character *) argelts[i])->charValue(),
588 java::lang::Number *num = (java::lang::Number *) argelts[i];
589 if (paramelts[i] == JvPrimClass (byte))
590 COPY (&argvals[i], num->byteValue(), jbyte);
591 else if (paramelts[i] == JvPrimClass (short))
592 COPY (&argvals[i], num->shortValue(), jshort);
593 else if (paramelts[i] == JvPrimClass (int))
594 COPY (&argvals[i], num->intValue(), jint);
595 else if (paramelts[i] == JvPrimClass (long))
596 COPY (&argvals[i], num->longValue(), jlong);
597 else if (paramelts[i] == JvPrimClass (float))
598 COPY (&argvals[i], num->floatValue(), jfloat);
599 else if (paramelts[i] == JvPrimClass (double))
600 COPY (&argvals[i], num->doubleValue(), jdouble);
605 if (argelts[i] && ! paramelts[i]->isAssignableFrom (k))
606 throw new java::lang::IllegalArgumentException;
607 COPY (&argvals[i], argelts[i], jobject);
612 _Jv_CallAnyMethodA (obj, return_type, meth, is_constructor,
613 _Jv_isVirtualMethod (meth),
614 parameter_types, argvals, &ret_value,
618 #define VAL(Wrapper, Field) (new Wrapper (ret_value.Field))
621 else if (return_type == JvPrimClass (byte))
622 r = VAL (java::lang::Byte, b);
623 else if (return_type == JvPrimClass (short))
624 r = VAL (java::lang::Short, s);
625 else if (return_type == JvPrimClass (int))
626 r = VAL (java::lang::Integer, i);
627 else if (return_type == JvPrimClass (long))
628 r = VAL (java::lang::Long, j);
629 else if (return_type == JvPrimClass (float))
630 r = VAL (java::lang::Float, f);
631 else if (return_type == JvPrimClass (double))
632 r = VAL (java::lang::Double, d);
633 else if (return_type == JvPrimClass (boolean))
634 r = VAL (java::lang::Boolean, z);
635 else if (return_type == JvPrimClass (char))
636 r = VAL (java::lang::Character, c);
637 else if (return_type == JvPrimClass (void))
641 JvAssert (return_type == NULL || ! return_type->isPrimitive());