📄 natmethod.cc
字号:
// natMethod.cc - Native code for Method class./* Copyright (C) 1998, 1999, 2000, 2001 , 2002, 2003, 2004, 2005 Free Software Foundation This file is part of libgcj.This software is copyrighted work licensed under the terms of theLibgcj License. Please consult the file "LIBGCJ_LICENSE" fordetails. */#include <config.h>#include <gcj/cni.h>#include <jvm.h>#include <jni.h>#include <java-stack.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>#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/IllegalAccessException.h>#include <java/lang/IllegalArgumentException.h>#include <java/lang/IncompatibleClassChangeError.h>#include <java/lang/NullPointerException.h>#include <java/lang/ArrayIndexOutOfBoundsException.h>#include <java/lang/VirtualMachineError.h>#include <java/lang/Class.h>#include <gcj/method.h>#include <gnu/gcj/RawData.h>#include <java/lang/NoClassDefFoundError.h>#include <stdlib.h>#if USE_LIBFFI#include <ffi.h>#else#include <java/lang/UnsupportedOperationException.h>#endifstruct cpair{ jclass prim; jclass wrap;};// This is used to determine when a primitive widening conversion is// allowed.static cpair primitives[] ={#define BOOLEAN 0 { JvPrimClass (boolean), &java::lang::Boolean::class$ }, { JvPrimClass (byte), &java::lang::Byte::class$ },#define SHORT 2 { JvPrimClass (short), &java::lang::Short::class$ },#define CHAR 3 { 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 }};static inline jbooleancan_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; // Boolean arguments may not be widened. if (fromx == BOOLEAN && tox != BOOLEAN) return false; // Nothing promotes to char. if (tox == CHAR && fromx != CHAR) return false; return fromx <= tox;}#ifdef USE_LIBFFIstatic inline 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)) { // On some platforms a bool is a byte, on others an int. if (sizeof (jboolean) == sizeof (jbyte)) r = &ffi_type_sint8; else { JvAssert (sizeof (jboolean) == sizeof (jint)); r = &ffi_type_sint32; } } else if (klass == JvPrimClass (char)) r = &ffi_type_uint16; else { JvAssert (! klass->isPrimitive()); r = &ffi_type_pointer; } return r;}#endif // USE_LIBFFIjobjectjava::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 (Modifier::isStatic(meth->accflags)) { // 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 (objClass, declaringClass)) throw new java::lang::IllegalArgumentException; } // Check accessibility, if required. if (! (Modifier::isPublic (meth->accflags) || this->isAccessible())) { Class *caller = _Jv_StackTrace::GetCallingClass (&Method::class$); 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, iface);}jintjava::lang::reflect::Method::getModifiers (){ // Ignore all unknown flags. return _Jv_FromReflectedMethod (this)->accflags & Modifier::ALL_FLAGS;}jstringjava::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. */voidjava::lang::reflect::Method::getType (){ _Jv_Method *method = _Jv_FromReflectedMethod (this); _Jv_GetTypesFromSignature (method, declaringClass, ¶meter_types, &return_type); int count = 0; if (method->throws != NULL) { while (method->throws[count] != NULL) ++count; } exception_types = (JArray<jclass> *) JvNewObjectArray (count, &java::lang::Class::class$, NULL); jclass *elts = elements (exception_types); for (int i = 0; i < count; ++i) elts[i] = _Jv_FindClass (method->throws[i], declaringClass->getClassLoaderInternal ());}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->getClassLoaderInternal(); char *ptr = sig->chars(); int numArgs = 0; /* First just count the number of parameters. */ // FIXME: should do some validation here, e.g., that there is only // one return type. 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, &java::lang::Class::class$, NULL); jclass* argPtr = elements (args); for (ptr = sig->chars(); *ptr != '\0'; ptr++) { if (*ptr == '(') continue; if (*ptr == ')') { argPtr = return_type_out; continue; } char *end_ptr; jclass type = _Jv_FindClassFromSignature (ptr, loader, &end_ptr); if (type == NULL) // FIXME: This isn't ideal. throw new java::lang::NoClassDefFoundError (sig->toString()); // ARGPTR can be NULL if we are processing the return value of a // call from Constructor. if (argPtr) *argPtr++ = type; ptr = end_ptr; } *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. RESULT is a pointer// 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.void_Jv_CallAnyMethodA (jobject obj, jclass return_type, jmethodID meth, jboolean is_constructor, jboolean is_virtual_call, JArray<jclass> *parameter_types, jvalue *args, 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); // See whether call needs an object as the first argument. A // constructor does need a `this' argument, but it is one we create.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -