X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=libjava%2Fjava%2Flang%2Freflect%2FnatMethod.cc;h=b4b3a7a9b06943c857f07801ede679960d454c30;hp=1fab48ab311d2bac5cbb14f07950044131f6e1ff;hb=34ac03a9d40cb9f1cffd7f99fe1b2c520cc0c162;hpb=c9d1e3944ceffbfc9634b208e96ceb51d5cc965a diff --git a/libjava/java/lang/reflect/natMethod.cc b/libjava/java/lang/reflect/natMethod.cc index 1fab48ab311..b4b3a7a9b06 100644 --- a/libjava/java/lang/reflect/natMethod.cc +++ b/libjava/java/lang/reflect/natMethod.cc @@ -1,6 +1,6 @@ // natMethod.cc - Native code for Method class. -/* Copyright (C) 1998, 1999, 2000, 2001 , 2002 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001 , 2002, 2003, 2004 Free Software Foundation This file is part of libgcj. @@ -28,8 +28,12 @@ details. */ #include #include #include +#include #include +#include #include +#include +#include #include #include #include @@ -42,17 +46,6 @@ details. */ #include #endif -// FIXME: remove these. -#define BooleanClass java::lang::Boolean::class$ -#define VoidClass java::lang::Void::class$ -#define ByteClass java::lang::Byte::class$ -#define ShortClass java::lang::Short::class$ -#define CharacterClass java::lang::Character::class$ -#define IntegerClass java::lang::Integer::class$ -#define LongClass java::lang::Long::class$ -#define FloatClass java::lang::Float::class$ -#define DoubleClass java::lang::Double::class$ - struct cpair { jclass prim; @@ -64,16 +57,16 @@ struct cpair static cpair primitives[] = { #define BOOLEAN 0 - { JvPrimClass (boolean), &BooleanClass }, - { JvPrimClass (byte), &ByteClass }, + { JvPrimClass (boolean), &java::lang::Boolean::class$ }, + { JvPrimClass (byte), &java::lang::Byte::class$ }, #define SHORT 2 - { JvPrimClass (short), &ShortClass }, + { JvPrimClass (short), &java::lang::Short::class$ }, #define CHAR 3 - { JvPrimClass (char), &CharacterClass }, - { JvPrimClass (int), &IntegerClass }, - { JvPrimClass (long), &LongClass }, - { JvPrimClass (float), &FloatClass }, - { JvPrimClass (double), &DoubleClass }, + { JvPrimClass (char), &java::lang::Character::class$ }, + { JvPrimClass (int), &java::lang::Integer::class$ }, + { JvPrimClass (long), &java::lang::Long::class$ }, + { JvPrimClass (float), &java::lang::Float::class$ }, + { JvPrimClass (double), &java::lang::Double::class$ }, { NULL, NULL } }; @@ -150,26 +143,54 @@ get_ffi_type (jclass klass) jobject java::lang::reflect::Method::invoke (jobject obj, jobjectArray args) { + using namespace java::lang::reflect; + jclass iface = NULL; + if (parameter_types == NULL) getType (); - + jmethodID meth = _Jv_FromReflectedMethod (this); - if (! java::lang::reflect::Modifier::isStatic(meth->accflags)) + + if (Modifier::isStatic(meth->accflags)) { - jclass k = obj ? obj->getClass() : NULL; - if (! obj) - throw new java::lang::NullPointerException; - if (! declaringClass->isAssignableFrom(k)) - throw new java::lang::IllegalArgumentException; - // FIXME: access checks. - - // Find the possibly overloaded method based on the runtime type - // of the object. - meth = _Jv_LookupDeclaredMethod (k, meth->name, meth->signature); + // We have to initialize a static class. It is safe to do this + // here and not in _Jv_CallAnyMethodA because JNI initializes a + // class whenever a method lookup is done. + _Jv_InitClass (declaringClass); + } + else + { + jclass objClass = JV_CLASS (obj); + if (! _Jv_IsAssignableFrom (declaringClass, objClass)) + throw new java::lang::IllegalArgumentException; + } + + // Check accessibility, if required. + if (! (Modifier::isPublic (meth->accflags) || this->isAccessible())) + { + gnu::gcj::runtime::StackTrace *t + = new gnu::gcj::runtime::StackTrace(4); + Class *caller = NULL; + try + { + for (int i = 1; !caller; i++) + { + caller = t->classAt (i); + } + } + catch (::java::lang::ArrayIndexOutOfBoundsException *e) + { + } + + if (! _Jv_CheckAccess(caller, declaringClass, meth->accflags)) + throw new IllegalAccessException; } + if (declaringClass->isInterface()) + iface = declaringClass; + return _Jv_CallAnyMethodA (obj, return_type, meth, false, - parameter_types, args); + parameter_types, args, iface); } jint @@ -206,13 +227,12 @@ java::lang::reflect::Method::getType () } exception_types - = (JArray *) JvNewObjectArray (count, - &java::lang::Class::class$, + = (JArray *) JvNewObjectArray (count, &java::lang::Class::class$, NULL); jclass *elts = elements (exception_types); for (int i = 0; i < count; ++i) - elts[i] = _Jv_FindClassFromSignature (method->throws[i]->data, - declaringClass->getClassLoader ()); + elts[i] = _Jv_FindClass (method->throws[i], + declaringClass->getClassLoaderInternal ()); } void @@ -223,8 +243,8 @@ _Jv_GetTypesFromSignature (jmethodID method, { _Jv_Utf8Const* sig = method->signature; - java::lang::ClassLoader *loader = declaringClass->getClassLoader(); - char *ptr = sig->data; + java::lang::ClassLoader *loader = declaringClass->getClassLoaderInternal(); + char *ptr = sig->chars(); int numArgs = 0; /* First just count the number of parameters. */ for (; ; ptr++) @@ -261,7 +281,7 @@ _Jv_GetTypesFromSignature (jmethodID method, JArray *args = (JArray *) JvNewObjectArray (numArgs, &java::lang::Class::class$, NULL); jclass* argPtr = elements (args); - for (ptr = sig->data; *ptr != '\0'; ptr++) + for (ptr = sig->chars(); *ptr != '\0'; ptr++) { int num_arrays = 0; jclass type; @@ -295,9 +315,8 @@ _Jv_GetTypesFromSignature (jmethodID method, break; } - // FIXME: 2'nd argument should be "current loader" while (--num_arrays >= 0) - type = _Jv_GetArrayClass (type, 0); + type = _Jv_GetArrayClass (type, loader); // ARGPTR can be NULL if we are processing the return value of a // call from Constructor. if (argPtr) @@ -314,15 +333,20 @@ _Jv_GetTypesFromSignature (jmethodID method, // to a `jvalue' (see jni.h); for a void method this should be NULL. // This function returns an exception (if one was thrown), or NULL if // the call went ok. -jthrowable +void _Jv_CallAnyMethodA (jobject obj, jclass return_type, jmethodID meth, jboolean is_constructor, + jboolean is_virtual_call, JArray *parameter_types, jvalue *args, - jvalue *result) + jvalue *result, + jboolean is_jni_call, + jclass iface) { + using namespace java::lang::reflect; + #ifdef USE_LIBFFI JvAssert (! is_constructor || ! obj); JvAssert (! is_constructor || return_type); @@ -331,7 +355,7 @@ _Jv_CallAnyMethodA (jobject obj, // constructor does need a `this' argument, but it is one we create. jboolean needs_this = false; if (is_constructor - || ! java::lang::reflect::Modifier::isStatic(meth->accflags)) + || ! Modifier::isStatic(meth->accflags)) needs_this = true; int param_count = parameter_types->length; @@ -349,60 +373,36 @@ _Jv_CallAnyMethodA (jobject obj, jclass *paramelts = elements (parameter_types); - // FIXME: at some point the compiler is going to add extra arguments - // to some functions. In particular we are going to do this for - // handling access checks in reflection. We must add these hidden - // arguments here. - // Special case for the `this' argument of a constructor. Note that // the JDK 1.2 docs specify that the new object must be allocated // before argument conversions are done. if (is_constructor) - { - // FIXME: must special-case String, arrays, maybe others here. - obj = JvAllocObject (return_type); - } - - int i = 0; - int size = 0; - if (needs_this) - { - // The `NULL' type is `Object'. - argtypes[i++] = get_ffi_type (NULL); - size += sizeof (jobject); - } - - for (int arg = 0; i < param_count; ++i, ++arg) - { - argtypes[i] = get_ffi_type (paramelts[arg]); - if (paramelts[arg]->isPrimitive()) - size += paramelts[arg]->size(); - else - size += sizeof (jobject); - } + obj = _Jv_AllocObject (return_type); + const int size_per_arg = sizeof(jvalue); ffi_cif cif; - if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, param_count, - rtype, argtypes) != FFI_OK) - { - // FIXME: throw some kind of VirtualMachineError here. - } - char *p = (char *) __builtin_alloca (size); - void **values = (void **) __builtin_alloca (param_count * sizeof (void *)); + char *p = (char *) __builtin_alloca (param_count * size_per_arg); + // Overallocate to get correct alignment. + void **values = (void **) + __builtin_alloca (param_count * sizeof (void *)); - i = 0; + int i = 0; if (needs_this) { + // The `NULL' type is `Object'. + argtypes[i] = get_ffi_type (NULL); values[i] = p; memcpy (p, &obj, sizeof (jobject)); - p += sizeof (jobject); + p += size_per_arg; ++i; } for (int arg = 0; i < param_count; ++i, ++arg) { int tsize; + + argtypes[i] = get_ffi_type (paramelts[arg]); if (paramelts[arg]->isPrimitive()) tsize = paramelts[arg]->size(); else @@ -411,38 +411,163 @@ _Jv_CallAnyMethodA (jobject obj, // Copy appropriate bits from the jvalue into the ffi array. // FIXME: we could do this copying all in one loop, above, by // over-allocating a bit. + // How do we do this without breaking big-endian platforms? values[i] = p; memcpy (p, &args[arg], tsize); - p += tsize; + p += size_per_arg; } - // FIXME: initialize class here. + if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, param_count, + rtype, argtypes) != FFI_OK) + throw new java::lang::VirtualMachineError(JvNewStringLatin1("internal error: ffi_prep_cif failed")); using namespace java::lang; using namespace java::lang::reflect; - Throwable *ex = NULL; + union + { + ffi_arg i; + jobject o; + jlong l; + jfloat f; + jdouble d; + } ffi_result; + + switch (rtype->type) + { + case FFI_TYPE_VOID: + break; + case FFI_TYPE_SINT8: + result->b = 0; + break; + case FFI_TYPE_SINT16: + result->s = 0; + break; + case FFI_TYPE_UINT16: + result->c = 0; + break; + case FFI_TYPE_SINT32: + result->i = 0; + break; + case FFI_TYPE_SINT64: + result->j = 0; + break; + case FFI_TYPE_FLOAT: + result->f = 0; + break; + case FFI_TYPE_DOUBLE: + result->d = 0; + break; + case FFI_TYPE_POINTER: + result->l = 0; + break; + default: + JvFail ("Unknown ffi_call return type"); + break; + } + + void *ncode; + + // FIXME: If a vtable index is -1 at this point it is invalid, so we + // have to use the ncode. + // + // This can happen because methods in final classes don't have + // vtable entries, but _Jv_isVirtualMethod() doesn't know that. We + // could solve this problem by allocating a vtable index for methods + // in final classes. + if (is_virtual_call + && ! Modifier::isFinal (meth->accflags) + && (_Jv_ushort)-1 != meth->index) + { + _Jv_VTable *vtable = *(_Jv_VTable **) obj; + if (iface == NULL) + { + if (is_jni_call && Modifier::isAbstract (meth->accflags)) + { + // With JNI we don't know if this is an interface call + // or a call to an abstract method. Look up the method + // by name, the slow way. + _Jv_Method *concrete_meth + = _Jv_LookupDeclaredMethod (vtable->clas, + meth->name, + meth->signature, + NULL); + if (concrete_meth == NULL + || concrete_meth->ncode == NULL + || Modifier::isAbstract(concrete_meth->accflags)) + throw new java::lang::IncompatibleClassChangeError + (_Jv_GetMethodString (vtable->clas, meth->name)); + ncode = concrete_meth->ncode; + } + else + ncode = vtable->get_method (meth->index); + } + else + ncode = _Jv_LookupInterfaceMethodIdx (vtable->clas, iface, + meth->index); + } + else + { + ncode = meth->ncode; + } try { - ffi_call (&cif, (void (*)()) meth->ncode, result, values); + ffi_call (&cif, (void (*)()) ncode, &ffi_result, values); } - catch (Throwable *ex2) + catch (Throwable *ex) { - // FIXME: this is wrong for JNI. But if we just return the - // exception, then the non-JNI cases won't be able to - // distinguish it from exceptions we might generate ourselves. - // Sigh. - ex = new InvocationTargetException (ex2); + // For JNI we just throw the real error. For reflection, we + // wrap the underlying method's exception in an + // InvocationTargetException. + if (! is_jni_call) + ex = new InvocationTargetException (ex); + throw ex; } + // Since ffi_call returns integer values promoted to a word, use + // a narrowing conversion for jbyte, jchar, etc. results. + // Note that boolean is handled either by the FFI_TYPE_SINT8 or + // FFI_TYPE_SINT32 case. if (is_constructor) result->l = obj; - - return ex; + else + { + switch (rtype->type) + { + case FFI_TYPE_VOID: + break; + case FFI_TYPE_SINT8: + result->b = (jbyte)ffi_result.i; + break; + case FFI_TYPE_SINT16: + result->s = (jshort)ffi_result.i; + break; + case FFI_TYPE_UINT16: + result->c = (jchar)ffi_result.i; + break; + case FFI_TYPE_SINT32: + result->i = (jint)ffi_result.i; + break; + case FFI_TYPE_SINT64: + result->j = (jlong)ffi_result.l; + break; + case FFI_TYPE_FLOAT: + result->f = (jfloat)ffi_result.f; + break; + case FFI_TYPE_DOUBLE: + result->d = (jdouble)ffi_result.d; + break; + case FFI_TYPE_POINTER: + result->l = (jobject)ffi_result.o; + break; + default: + JvFail ("Unknown ffi_call return type"); + break; + } + } #else - throw new java::lang::UnsupportedOperationException; - return 0; + throw new java::lang::UnsupportedOperationException(JvNewStringLatin1("reflection not available in this build")); #endif // USE_LIBFFI } @@ -454,10 +579,9 @@ _Jv_CallAnyMethodA (jobject obj, jmethodID meth, jboolean is_constructor, JArray *parameter_types, - jobjectArray args) + jobjectArray args, + jclass iface) { - // FIXME: access checks. - if (parameter_types->length == 0 && args == NULL) { // The JDK accepts this, so we do too. @@ -521,16 +645,10 @@ _Jv_CallAnyMethodA (jobject obj, } jvalue ret_value; - java::lang::Throwable *ex = _Jv_CallAnyMethodA (obj, - return_type, - meth, - is_constructor, - parameter_types, - argvals, - &ret_value); - - if (ex) - throw ex; + _Jv_CallAnyMethodA (obj, return_type, meth, is_constructor, + _Jv_isVirtualMethod (meth), + parameter_types, argvals, &ret_value, + false, iface); jobject r; #define VAL(Wrapper, Field) (new Wrapper (ret_value.Field))