diff options
Diffstat (limited to 'libjava/java/lang/reflect/natMethod.cc')
-rw-r--r-- | libjava/java/lang/reflect/natMethod.cc | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/libjava/java/lang/reflect/natMethod.cc b/libjava/java/lang/reflect/natMethod.cc new file mode 100644 index 00000000000..720bbc3d74e --- /dev/null +++ b/libjava/java/lang/reflect/natMethod.cc @@ -0,0 +1,386 @@ +// natMethod.cc - Native code for Method class. + +/* Copyright (C) 1998, 1999 Cygnus Solutions + + This file is part of libgcj. + +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 <cni.h> +#include <jvm.h> +#include <java-array.h> + +#include <java/lang/reflect/Method.h> +#include <java/lang/reflect/InvocationTargetException.h> +#include <java/lang/reflect/Modifier.h> + +#include <java/lang/Void.h> +#include <java/lang/Byte.h> +#include <java/lang/Boolean.h> +#include <java/lang/Character.h> +#include <java/lang/Short.h> +#include <java/lang/Integer.h> +#include <java/lang/Long.h> +#include <java/lang/Float.h> +#include <java/lang/Double.h> +#include <java/lang/IllegalArgumentException.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/Class.h> +#include <java-method.h> + +#define ClassClass _CL_Q34java4lang5Class +extern java::lang::Class ClassClass; + +#include <stdlib.h> + +#if 0 + +#include <ffi.h> + +#define VoidClass _CL_Q34java4lang4Void +extern java::lang::Class VoidClass; +#define ByteClass _CL_Q34java4lang4Byte +extern java::lang::Class ByteClass; +#define ShortClass _CL_Q34java4lang5Short +extern java::lang::Class ShortClass; +#define CharacterClass _CL_Q34java4lang9Character +extern java::lang::Class CharacterClass; +#define IntegerClass _CL_Q34java4lang7Integer +extern java::lang::Class IntegerClass; +#define LongClass _CL_Q34java4lang4Long +extern java::lang::Class LongClass; +#define FloatClass _CL_Q34java4lang5Float +extern java::lang::Class FloatClass; +#define DoubleClass _CL_Q34java4lang6Double +extern java::lang::Class DoubleClass; + +struct cpair +{ + jclass prim; + jclass wrap; +}; + +// This is used to determine when a primitive widening conversion is +// allowed. +static cpair primitives[] = +{ +#define VOID 0 + { JvPrimClass (void), &VoidClass }, + { JvPrimClass (byte), &ByteClass }, +#define SHORT 2 + { JvPrimClass (short), &ShortClass }, +#define CHAR 3 + { JvPrimClass (char), &CharacterClass }, + { JvPrimClass (int), &IntegerClass }, + { JvPrimClass (long), &LongClass }, + { JvPrimClass (float), &FloatClass }, + { JvPrimClass (double), &DoubleClass }, + { NULL, NULL } +}; + +static jboolean +can_widen (jclass from, jclass to) +{ + int fromx = -1, tox = -1; + + for (int i = 0; primitives[i].prim; ++i) + { + if (primitives[i].wrap == from) + fromx = i; + if (primitives[i].prim == to) + tox = i; + } + + // Can't handle a miss. + if (fromx == -1 || tox == -1) + return false; + // Can't handle Void arguments. + if (fromx == VOID || tox == VOID) + return false; + // Special-case short/char conversions. + if ((fromx == SHORT && tox == CHAR) || (fromx == CHAR && tox == SHORT)) + return false; + + return fromx <= tox; +} + +static ffi_type * +get_ffi_type (jclass klass) +{ + // A special case. + if (klass == NULL) + return &ffi_type_pointer; + + ffi_type *r; + if (klass == JvPrimClass (byte)) + r = &ffi_type_sint8; + else if (klass == JvPrimClass (short)) + r = &ffi_type_sint16; + else if (klass == JvPrimClass (int)) + r = &ffi_type_sint32; + else if (klass == JvPrimClass (long)) + r = &ffi_type_sint64; + else if (klass == JvPrimClass (float)) + r = &ffi_type_float; + else if (klass == JvPrimClass (double)) + r = &ffi_type_double; + else if (klass == JvPrimClass (boolean)) + { + // FIXME. + r = &ffi_type_sint8; + } + else if (klass == JvPrimClass (char)) + r = &ffi_type_uint16; + else + { + JvAssert (! klass->isPrimitive()); + r = &ffi_type_pointer; + } + + return r; +} + +// FIXME: the body of this method should be a separate function so +// that Constructor can use it too. +jobject +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)) + { + jclass k = obj ? obj->getClass() : NULL; + if (! obj || ! decl_class->isAssignableFrom(k)) + JvThrow (new java::lang::NullPointerException); + // FIXME: access checks. + meth = _Jv_LookupMethod (k, meth->name, meth->signature); + } + + // FIXME: access checks. + + if (parameter_types->length != args->length) + JvThrow (new java::lang::IllegalArgumentException); + + ffi_type *rtype = get_ffi_type (return_type); + ffi_type **argtypes = (ffi_type **) alloca (parameter_types->length + * sizeof (ffi_type *)); + + jobject *paramelts = elements (parameter_types); + jobject *argelts = elements (args); + + int size = 0; + for (int i = 0; i < parameter_types->length; ++i) + { + jclass k = argelts[i] ? argelts[i]->getClass() : NULL; + argtypes[i] = get_ffi_type (k); + if (paramelts[i]->isPrimitive()) + { + if (! argelts[i] + || ! k->isPrimitive () + || ! can_widen (k, paramelts[i])) + JvThrow (new java::lang::IllegalArgumentException); + size += paramelts[i]->size(); + } + else + { + if (argelts[i] && ! paramelts[i]->isAssignableFrom (k)) + JvThrow (new java::lang::IllegalArgumentException); + size += sizeof (jobject); + } + } + + ffi_cif cif; + if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, parameter_types->length, + rtype, argtypes) != FFI_OK) + { + // FIXME: throw some kind of VirtualMachineError here. + } + + char *values = (char *) alloca (size); + char *p = values; + +#define COPY(Where, What, Type) \ + do { \ + Type val = (What); \ + memcpy ((Where), &val, sizeof (Type)); \ + Where += sizeof (Type); \ + } while (0) + + for (int i = 0; i < parameter_types->length; ++i) + { + java::lang::Number *num = (java::lang::Number *) paramelts[i]; + if (paramelts[i] == JvPrimClass (byte)) + COPY (p, num->byteValue(), jbyte); + else if (paramelts[i] == JvPrimClass (short)) + COPY (p, num->shortValue(), jshort); + else if (paramelts[i] == JvPrimClass (int)) + COPY (p, num->intValue(), jint); + else if (paramelts[i] == JvPrimClass (long)) + COPY (p, num->longValue(), jlong); + else if (paramelts[i] == JvPrimClass (float)) + COPY (p, num->floatValue(), jfloat); + 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); + else if (paramelts[i] == JvPrimClass (char)) + COPY (p, ((java::lang::Character *) argelts[i])->charValue(), jchar); + else + { + JvAssert (! paramelts[i]->isPrimitive()); + COPY (p, argelts[i], jobject); + } + } + + // FIXME: exception handling. + 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)); + + if (ex) + JvThrow (new InvocationTargetException (ex)); + + jobject r; +#define VAL(Wrapper, Type) (new Wrapper (* (Type *) &ret_value)) + if (return_type == JvPrimClass (byte)) + r = VAL (java::lang::Byte, jbyte); + else if (return_type == JvPrimClass (short)) + r = VAL (java::lang::Short, jshort); + else if (return_type == JvPrimClass (int)) + r = VAL (java::lang::Integer, jint); + else if (return_type == JvPrimClass (long)) + r = VAL (java::lang::Long, jlong); + else if (return_type == JvPrimClass (float)) + r = VAL (java::lang::Float, jfloat); + else if (return_type == JvPrimClass (double)) + r = VAL (java::lang::Double, jdouble); + else if (return_type == JvPrimClass (boolean)) + r = VAL (java::lang::Boolean, jboolean); + else if (return_type == JvPrimClass (char)) + r = VAL (java::lang::Character, jchar); + else if (return_type == JvPrimClass (void)) + r = NULL; + else + { + JvAssert (! return_type->isPrimitive()); + r = VAL (java::lang::Object, jobject); + } + + 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; + } + while (--num_arrays >= 0) + type = _Jv_FindArrayClass (type); + *argPtr++ = type; + } + parameter_types = args; +} |