summaryrefslogtreecommitdiff
path: root/libjava/java/lang/reflect/natMethod.cc
diff options
context:
space:
mode:
authortromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4>2000-01-04 08:46:52 +0000
committertromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4>2000-01-04 08:46:52 +0000
commit01496bfd073f3efb830f8567a8072ecb8e3e9a57 (patch)
treeb6bce78d53cdae8796dafac92444a6291ac4777a /libjava/java/lang/reflect/natMethod.cc
parent5520494e09ac793d2be0ebc4ef420c47a765b1f0 (diff)
downloadgcc-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.cc364
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,
+ &parameter_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;
-}