diff options
author | tromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-01-04 08:46:52 +0000 |
---|---|---|
committer | tromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-01-04 08:46:52 +0000 |
commit | 01496bfd073f3efb830f8567a8072ecb8e3e9a57 (patch) | |
tree | b6bce78d53cdae8796dafac92444a6291ac4777a /libjava/java/lang/reflect/natMethod.cc | |
parent | 5520494e09ac793d2be0ebc4ef420c47a765b1f0 (diff) | |
download | gcc-01496bfd073f3efb830f8567a8072ecb8e3e9a57.tar.gz |
2000-01-04 Tom Tromey <tromey@cygnus.com>
* java/lang/reflect/natConstructor.cc (newInstance): Pass
declaring class as return_type argument to
_Jv_CallNonvirtualMethodA.
* java/lang/reflect/natMethod.cc (_Jv_CallNonvirtualMethodA): In
constructor case, create object and use it as `this' argument.
* java/lang/Class.h (_getConstructors): Declare.
(_getFields): Declare.
* java/lang/Class.java (getConstructors): Wrote.
(_getConstructors): New native method.
(getDeclaredConstructors): Wrote.
(_getFields): Declare new native method.
* java/lang/natClass.cc (_Jv_LookupInterfaceMethod): Removed
incorrect comment.
(getMethod): Work correctly when class is primitive.
(getDeclaredMethods): Likewise. Compute offset using `method',
not `mptr'.
(getDeclaredMethod): Likewise.
(getConstructor): Wrote.
(ConstructorClass): New define.
(getDeclaredConstructor): Wrote.
(_getConstructors): New method.
(_getFields): New method.
(getFields): Wrote.
* Makefile.in: Rebuilt.
* Makefile.am (AM_CXXFLAGS): Added -D_GNU_SOURCE.
* prims.cc: Remove `#pragma implementation'.
* gcj/array.h: Remove `#pragma interface'.
* prims.cc (_Jv_equaln): New function.
* java/lang/Class.java (getSignature): Declare.
* resolve.cc (_Jv_LookupDeclaredMethod): Moved to natClass.cc.
* java/lang/natClass.cc (_Jv_LookupDeclaredMethod): Moved from
resolve.cc.
(getSignature): New method.
(getDeclaredMethod): Wrote.
(getMethod): Wrote.
Include StringBuffer.h.
* java/lang/Class.h (Class): Added _Jv_FromReflectedConstructor
as a friend. Unconditionally declare _Jv_LookupDeclaredMethod as
a friend.
(getSignature): Declare.
* include/jvm.h (_Jv_GetTypesFromSignature): Declare.
(_Jv_equaln): Declare.
(_Jv_CallNonvirtualMethodA): Declare.
* Makefile.in: Rebuilt.
* Makefile.am (nat_source_files): Added natConstructor.cc.
(java/lang/reflect/Constructor.h): New target.
* java/lang/reflect/natConstructor.cc: New file.
* java/lang/reflect/Constructor.java (newInstance): Now native.
(declaringClass): Renamed from decl_class.
(offset): Renamed from index.
(getType): New native method.
(getModifiers): Now native.
(getParameterTypes): Call getType if required.
(hashCode): Include hash code from declaring class.
(modifiers): Removed.
(toString): Call getType if required.
* gcj/method.h (_Jv_FromReflectedConstructor): New function.
* java/lang/reflect/natMethod.cc (hack_call): New method.
Removed `#if 0' around FFI code.
Include <gnu/gcj/RawData.h>.
(invoke): Use _Jv_CallNonvirtualMethodA. Throw
IllegalArgumentException when argument object and class disagree.
(_Jv_GetTypesFromSignature): New function.
(getType): Use it.
(ObjectClass): New define.
(_Jv_CallNonvirtualMethodA): New function.
* java/lang/reflect/Method.java (hack_trampoline): New method.
(hack_call): New native method.
1999-12-21 Per Bothner <per@bothner.com>
* java/lang/natClass.cc (getDeclaredMethods): Correctly compute
offset in new Method.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@31199 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava/java/lang/reflect/natMethod.cc')
-rw-r--r-- | libjava/java/lang/reflect/natMethod.cc | 364 |
1 files changed, 228 insertions, 136 deletions
diff --git a/libjava/java/lang/reflect/natMethod.cc b/libjava/java/lang/reflect/natMethod.cc index 0130ac4243f..5635b9fe33d 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 Cygnus Solutions +/* Copyright (C) 1998, 1999, 2000 Cygnus Solutions This file is part of libgcj. @@ -8,14 +8,13 @@ This software is copyrighted work licensed under the terms of the Libgcj License. Please consult the file "LIBGCJ_LICENSE" for details. */ -// This is about 90% done. Search for FIXME to see what remains. - #include <config.h> #include <gcj/cni.h> #include <jvm.h> #include <java/lang/reflect/Method.h> +#include <java/lang/reflect/Constructor.h> #include <java/lang/reflect/InvocationTargetException.h> #include <java/lang/reflect/Modifier.h> @@ -32,14 +31,15 @@ details. */ #include <java/lang/NullPointerException.h> #include <java/lang/Class.h> #include <gcj/method.h> +#include <gnu/gcj/RawData.h> +#define ObjectClass _CL_Q34java4lang6Object +extern java::lang::Class ObjectClass; #define ClassClass _CL_Q34java4lang5Class extern java::lang::Class ClassClass; #include <stdlib.h> -#if 0 - #include <ffi.h> #define VoidClass _CL_Q34java4lang4Void @@ -145,37 +145,225 @@ get_ffi_type (jclass klass) return r; } -// FIXME: the body of this method should be a separate function so -// that Constructor can use it too. +// Actually perform an FFI call. +void +java::lang::reflect::Method::hack_call (gnu::gcj::RawData *rcif, + gnu::gcj::RawData *rmethod, + gnu::gcj::RawData *rret_value, + gnu::gcj::RawData *rvalues) +{ + ffi_cif *cif = (ffi_cif *) rcif; + void (*method) (...) = (void (*) (...)) rmethod; + void *ret_value = (void *) rret_value; + void **values = (void **) rvalues; + + ffi_call (cif, method, ret_value, values); +} + jobject -java::lang::reflect::Method::invoke (jobject obj, - jobjectArray args) +java::lang::reflect::Method::invoke (jobject obj, jobjectArray args) { - // FIXME: we need to be a friend of Class here. - _Jv_Method *meth = decl_class->methods[index]; - if (! java::lang::reflect::Modifier::isStatic(modifiers)) + if (parameter_types == NULL) + getType (); + + jmethodID meth = _Jv_FromReflectedMethod (this); + if (! java::lang::reflect::Modifier::isStatic(meth->accflags)) { jclass k = obj ? obj->getClass() : NULL; - if (! obj || ! decl_class->isAssignableFrom(k)) + if (! obj) JvThrow (new java::lang::NullPointerException); + if (! declaringClass->isAssignableFrom(k)) + JvThrow (new java::lang::IllegalArgumentException); // FIXME: access checks. - meth = _Jv_LookupMethod (k, meth->name, meth->signature); + + // Find the possibly overloaded method based on the runtime type + // of the object. + meth = _Jv_LookupDeclaredMethod (k, meth->name, meth->signature); } + return _Jv_CallNonvirtualMethodA (obj, return_type, meth, false, + parameter_types, args); +} + +jint +java::lang::reflect::Method::getModifiers () +{ + return _Jv_FromReflectedMethod (this)->accflags; +} + +jstring +java::lang::reflect::Method::getName () +{ + if (name == NULL) + name = _Jv_NewStringUtf8Const (_Jv_FromReflectedMethod (this)->name); + return name; +} + +/* Internal method to set return_type and parameter_types fields. */ + +void +java::lang::reflect::Method::getType () +{ + _Jv_GetTypesFromSignature (_Jv_FromReflectedMethod (this), + declaringClass, + ¶meter_types, + &return_type); +} + +void +_Jv_GetTypesFromSignature (jmethodID method, + jclass declaringClass, + JArray<jclass> **arg_types_out, + jclass *return_type_out) +{ + + _Jv_Utf8Const* sig = method->signature; + java::lang::ClassLoader *loader = declaringClass->getClassLoader(); + char *ptr = sig->data; + int numArgs = 0; + /* First just count the number of parameters. */ + for (; ; ptr++) + { + switch (*ptr) + { + case 0: + case ')': + case 'V': + break; + case '[': + case '(': + continue; + case 'B': + case 'C': + case 'D': + case 'F': + case 'S': + case 'I': + case 'J': + case 'Z': + numArgs++; + continue; + case 'L': + numArgs++; + do + ptr++; + while (*ptr != ';' && ptr[1] != '\0'); + continue; + } + break; + } + + JArray<jclass> *args = (JArray<jclass> *) + JvNewObjectArray (numArgs, &ClassClass, NULL); + jclass* argPtr = elements (args); + for (ptr = sig->data; *ptr != '\0'; ptr++) + { + int num_arrays = 0; + jclass type; + for (; *ptr == '['; ptr++) + num_arrays++; + switch (*ptr) + { + default: + return; + case ')': + argPtr = return_type_out; + continue; + case '(': + continue; + case 'V': + case 'B': + case 'C': + case 'D': + case 'F': + case 'S': + case 'I': + case 'J': + case 'Z': + type = _Jv_FindClassFromSignature(ptr, loader); + break; + case 'L': + type = _Jv_FindClassFromSignature(ptr, loader); + do + ptr++; + while (*ptr != ';' && ptr[1] != '\0'); + break; + } + + // FIXME: 2'nd argument should be "current loader" + while (--num_arrays >= 0) + type = _Jv_FindArrayClass (type, 0); + // ARGPTR can be NULL if we are processing the return value of a + // call from Constructor. + if (argPtr) + *argPtr++ = type; + } + *arg_types_out = args; +} + +// This is a very rough analog of the JNI CallNonvirtual<type>MethodA +// functions. It handles both Methods and Constructors, and it can +// handle any return type. In the Constructor case, the `obj' +// argument is unused and should be NULL; also, the `return_type' is +// the class that the constructor will construct. +jobject +_Jv_CallNonvirtualMethodA (jobject obj, + jclass return_type, + jmethodID meth, + jboolean is_constructor, + JArray<jclass> *parameter_types, + jobjectArray args) +{ + JvAssert (! is_constructor || ! obj); + JvAssert (! is_constructor || ! return_type); + // FIXME: access checks. if (parameter_types->length != args->length) JvThrow (new java::lang::IllegalArgumentException); + // See whether call needs an object as the first argument. A + // 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)) + needs_this = true; + + int param_count = parameter_types->length; + if (needs_this) + ++param_count; + ffi_type *rtype = get_ffi_type (return_type); - ffi_type **argtypes = (ffi_type **) alloca (parameter_types->length + ffi_type **argtypes = (ffi_type **) alloca (param_count * sizeof (ffi_type *)); - jobject *paramelts = elements (parameter_types); + jclass *paramelts = elements (parameter_types); jobject *argelts = elements (args); + // 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; - for (int i = 0; i < parameter_types->length; ++i) + if (needs_this) + { + // The `NULL' type is `Object'. + argtypes[i++] = get_ffi_type (NULL); + size += sizeof (jobject); + } + + for (; i < param_count; ++i) { jclass k = argelts[i] ? argelts[i]->getClass() : NULL; argtypes[i] = get_ffi_type (k); @@ -196,7 +384,7 @@ java::lang::reflect::Method::invoke (jobject obj, } ffi_cif cif; - if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, parameter_types->length, + if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, param_count, rtype, argtypes) != FFI_OK) { // FIXME: throw some kind of VirtualMachineError here. @@ -212,7 +400,14 @@ java::lang::reflect::Method::invoke (jobject obj, Where += sizeof (Type); \ } while (0) - for (int i = 0; i < parameter_types->length; ++i) + i = 0; + if (needs_this) + { + COPY (p, obj, jobject); + ++i; + } + + for (; i < param_count; ++i) { java::lang::Number *num = (java::lang::Number *) paramelts[i]; if (paramelts[i] == JvPrimClass (byte)) @@ -228,7 +423,8 @@ java::lang::reflect::Method::invoke (jobject obj, else if (paramelts[i] == JvPrimClass (double)) COPY (p, num->doubleValue(), jdouble); else if (paramelts[i] == JvPrimClass (boolean)) - COPY (p, ((java::lang::Boolean *) argelts[i])->booleanValue(), jboolean); + COPY (p, ((java::lang::Boolean *) argelts[i])->booleanValue(), + jboolean); else if (paramelts[i] == JvPrimClass (char)) COPY (p, ((java::lang::Character *) argelts[i])->charValue(), jchar); else @@ -238,11 +434,17 @@ java::lang::reflect::Method::invoke (jobject obj, } } - // FIXME: exception handling. + // FIXME: initialize class here. + + // Largest possible value. Hopefully it is aligned! + jdouble ret_value; java::lang::Throwable *ex; - jdouble ret_value; // Largest possible value. Hopefully - // it is aligned! - ex = TRAMP_CALL (ffi_call (&cif, meth->ncode, &ret_value, (void *) values)); + using namespace java::lang; + using namespace java::lang::reflect; + ex = Method::hack_trampoline ((gnu::gcj::RawData *) &cif, + (gnu::gcj::RawData *) meth->ncode, + (gnu::gcj::RawData *) &ret_value, + (gnu::gcj::RawData *) values); if (ex) JvThrow (new InvocationTargetException (ex)); @@ -269,119 +471,9 @@ java::lang::reflect::Method::invoke (jobject obj, r = NULL; else { - JvAssert (! return_type->isPrimitive()); - r = VAL (java::lang::Object, jobject); + JvAssert (return_type == NULL || ! return_type->isPrimitive()); + r = * (Object **) &ret_value; } return r; } - -#else /* 0 */ - -jobject -java::lang::reflect::Method::invoke (jobject, jobjectArray) -{ - JvFail ("not enabled yet"); -} - -#endif /* 0 */ - -jint -java::lang::reflect::Method::getModifiers () -{ - return _Jv_FromReflectedMethod (this)->accflags; -} - -jstring -java::lang::reflect::Method::getName () -{ - if (name == NULL) - name = _Jv_NewStringUtf8Const (_Jv_FromReflectedMethod (this)->name); - return name; -} - -/* Internal method to set return_type and parameter_types fields. */ - -void -java::lang::reflect::Method::getType () -{ - _Jv_Utf8Const* sig = _Jv_FromReflectedMethod (this)->signature; - java::lang::ClassLoader *loader = declaringClass->getClassLoader(); - char *ptr = sig->data; - int numArgs = 0; - /* First just count the number of parameters. */ - for (; ; ptr++) - { - switch (*ptr) - { - case 0: - case ')': - case 'V': - break; - case '[': - case '(': - continue; - case 'B': - case 'C': - case 'D': - case 'F': - case 'S': - case 'I': - case 'J': - case 'Z': - numArgs++; - continue; - case 'L': - numArgs++; - do - ptr++; - while (*ptr != ';' && ptr[1] != '\0'); - continue; - } - break; - } - - JArray<jclass> *args = (JArray<jclass> *) - JvNewObjectArray (numArgs, &ClassClass, NULL); - jclass* argPtr = elements (args); - for (ptr = sig->data; *ptr != '\0'; ptr++) - { - int num_arrays = 0; - jclass type; - for (; *ptr == '['; ptr++) - num_arrays++; - switch (*ptr) - { - default: - return; - case ')': - argPtr = &return_type; - continue; - case '(': - continue; - case 'V': - case 'B': - case 'C': - case 'D': - case 'F': - case 'S': - case 'I': - case 'J': - case 'Z': - type = _Jv_FindClassFromSignature(ptr, loader); - break; - case 'L': - type = _Jv_FindClassFromSignature(ptr, loader); - do - ptr++; - while (*ptr != ';' && ptr[1] != '\0'); - break; - } - - // FIXME: 2'nd argument should be "current loader" - while (--num_arrays >= 0) - type = _Jv_FindArrayClass (type, 0); - *argPtr++ = type; - } - parameter_types = args; -} |