From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- libjava/jni.cc | 2904 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2904 insertions(+) create mode 100644 libjava/jni.cc (limited to 'libjava/jni.cc') diff --git a/libjava/jni.cc b/libjava/jni.cc new file mode 100644 index 000000000..86a4dc5b2 --- /dev/null +++ b/libjava/jni.cc @@ -0,0 +1,2904 @@ +// jni.cc - JNI implementation, including the jump table. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 + Free Software Foundation + + 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. */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#ifdef ENABLE_JVMPI +#include +#endif +#ifdef INTERPRETER +#include +#include "jvmti-int.h" +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +using namespace gcj; + +// This enum is used to select different template instantiations in +// the invocation code. +enum invocation_type +{ + normal, + nonvirtual, + static_type, + constructor +}; + +// Forward declarations. +extern struct JNINativeInterface_ _Jv_JNIFunctions; +extern struct JNIInvokeInterface_ _Jv_JNI_InvokeFunctions; + +// Number of slots in the default frame. The VM must allow at least +// 16. +#define FRAME_SIZE 16 + +// Mark value indicating this is an overflow frame. +#define MARK_NONE 0 +// Mark value indicating this is a user frame. +#define MARK_USER 1 +// Mark value indicating this is a system frame. +#define MARK_SYSTEM 2 + +// This structure is used to keep track of local references. +struct _Jv_JNI_LocalFrame +{ + // This is one of the MARK_ constants. + unsigned char marker; + + // Flag to indicate some locals were allocated. + bool allocated_p; + + // Number of elements in frame. + int size; + + // The class loader of the JNI method that allocated this frame. + ::java::lang::ClassLoader *loader; + + // Next frame in chain. + _Jv_JNI_LocalFrame *next; + + // The elements. These are allocated using the C "struct hack". + jobject vec[0]; +}; + +// This holds a reference count for all local references. +static java::util::IdentityHashMap *local_ref_table; +// This holds a reference count for all global references. +static java::util::IdentityHashMap *global_ref_table; + +// The only VM. +JavaVM *_Jv_the_vm; + +#ifdef ENABLE_JVMPI +// The only JVMPI interface description. +static JVMPI_Interface _Jv_JVMPI_Interface; + +static jint +jvmpiEnableEvent (jint event_type, void *) +{ + switch (event_type) + { + case JVMPI_EVENT_OBJECT_ALLOC: + _Jv_JVMPI_Notify_OBJECT_ALLOC = _Jv_JVMPI_Interface.NotifyEvent; + break; + + case JVMPI_EVENT_THREAD_START: + _Jv_JVMPI_Notify_THREAD_START = _Jv_JVMPI_Interface.NotifyEvent; + break; + + case JVMPI_EVENT_THREAD_END: + _Jv_JVMPI_Notify_THREAD_END = _Jv_JVMPI_Interface.NotifyEvent; + break; + + default: + return JVMPI_NOT_AVAILABLE; + } + + return JVMPI_SUCCESS; +} + +static jint +jvmpiDisableEvent (jint event_type, void *) +{ + switch (event_type) + { + case JVMPI_EVENT_OBJECT_ALLOC: + _Jv_JVMPI_Notify_OBJECT_ALLOC = NULL; + break; + + default: + return JVMPI_NOT_AVAILABLE; + } + + return JVMPI_SUCCESS; +} +#endif + + + +void +_Jv_JNI_Init (void) +{ + local_ref_table = new java::util::IdentityHashMap; + global_ref_table = new java::util::IdentityHashMap; + +#ifdef ENABLE_JVMPI + _Jv_JVMPI_Interface.version = 1; + _Jv_JVMPI_Interface.EnableEvent = &jvmpiEnableEvent; + _Jv_JVMPI_Interface.DisableEvent = &jvmpiDisableEvent; + _Jv_JVMPI_Interface.EnableGC = &_Jv_EnableGC; + _Jv_JVMPI_Interface.DisableGC = &_Jv_DisableGC; + _Jv_JVMPI_Interface.RunGC = &_Jv_RunGC; +#endif +} + +// Tell the GC that a certain pointer is live. +static void +mark_for_gc (jobject obj, java::util::IdentityHashMap *ref_table) +{ + JvSynchronize sync (ref_table); + + using namespace java::lang; + Integer *refcount = (Integer *) ref_table->get (obj); + jint val = (refcount == NULL) ? 0 : refcount->intValue (); + // FIXME: what about out of memory error? + ref_table->put (obj, new Integer (val + 1)); +} + +// Unmark a pointer. +static void +unmark_for_gc (jobject obj, java::util::IdentityHashMap *ref_table) +{ + JvSynchronize sync (ref_table); + + using namespace java::lang; + Integer *refcount = (Integer *) ref_table->get (obj); + JvAssert (refcount); + jint val = refcount->intValue () - 1; + JvAssert (val >= 0); + if (val == 0) + ref_table->remove (obj); + else + // FIXME: what about out of memory error? + ref_table->put (obj, new Integer (val)); +} + +// "Unwrap" some random non-reference type. This exists to simplify +// other template functions. +template +static T +unwrap (T val) +{ + return val; +} + +// Unwrap a weak reference, if required. +template +static T * +unwrap (T *obj) +{ + using namespace gnu::gcj::runtime; + // We can compare the class directly because JNIWeakRef is `final'. + // Doing it this way is much faster. + if (obj == NULL || obj->getClass () != &JNIWeakRef::class$) + return obj; + JNIWeakRef *wr = reinterpret_cast (obj); + return reinterpret_cast (wr->get ()); +} + +jobject +_Jv_UnwrapJNIweakReference (jobject obj) +{ + return unwrap (obj); +} + + + +static jobject JNICALL +_Jv_JNI_NewGlobalRef (JNIEnv *, jobject obj) +{ + // This seems weird but I think it is correct. + obj = unwrap (obj); + mark_for_gc (obj, global_ref_table); + return obj; +} + +static void JNICALL +_Jv_JNI_DeleteGlobalRef (JNIEnv *, jobject obj) +{ + // This seems weird but I think it is correct. + obj = unwrap (obj); + + // NULL is ok here -- the JNI specification doesn't say so, but this + // is a no-op. + if (! obj) + return; + + unmark_for_gc (obj, global_ref_table); +} + +static void JNICALL +_Jv_JNI_DeleteLocalRef (JNIEnv *env, jobject obj) +{ + _Jv_JNI_LocalFrame *frame; + + // This seems weird but I think it is correct. + obj = unwrap (obj); + + // NULL is ok here -- the JNI specification doesn't say so, but this + // is a no-op. + if (! obj) + return; + + for (frame = env->locals; frame != NULL; frame = frame->next) + { + for (int i = 0; i < frame->size; ++i) + { + if (frame->vec[i] == obj) + { + frame->vec[i] = NULL; + unmark_for_gc (obj, local_ref_table); + return; + } + } + + // Don't go past a marked frame. + JvAssert (frame->marker == MARK_NONE); + } + + JvAssert (0); +} + +static jint JNICALL +_Jv_JNI_EnsureLocalCapacity (JNIEnv *env, jint size) +{ + // It is easier to just always allocate a new frame of the requested + // size. This isn't the most efficient thing, but for now we don't + // care. Note that _Jv_JNI_PushLocalFrame relies on this right now. + + _Jv_JNI_LocalFrame *frame; + try + { + frame = (_Jv_JNI_LocalFrame *) _Jv_Malloc (sizeof (_Jv_JNI_LocalFrame) + + size * sizeof (jobject)); + } + catch (jthrowable t) + { + env->ex = t; + return JNI_ERR; + } + + frame->marker = MARK_NONE; + frame->size = size; + frame->allocated_p = false; + memset (&frame->vec[0], 0, size * sizeof (jobject)); + frame->loader = env->locals->loader; + frame->next = env->locals; + env->locals = frame; + + return 0; +} + +static jint JNICALL +_Jv_JNI_PushLocalFrame (JNIEnv *env, jint size) +{ + jint r = _Jv_JNI_EnsureLocalCapacity (env, size); + if (r < 0) + return r; + + // The new frame is on top. + env->locals->marker = MARK_USER; + + return 0; +} + +static jobject JNICALL +_Jv_JNI_NewLocalRef (JNIEnv *env, jobject obj) +{ + // This seems weird but I think it is correct. + obj = unwrap (obj); + + // Try to find an open slot somewhere in the topmost frame. + _Jv_JNI_LocalFrame *frame = env->locals; + bool done = false, set = false; + for (; frame != NULL && ! done; frame = frame->next) + { + for (int i = 0; i < frame->size; ++i) + { + if (frame->vec[i] == NULL) + { + set = true; + done = true; + frame->vec[i] = obj; + frame->allocated_p = true; + break; + } + } + + // If we found a slot, or if the frame we just searched is the + // mark frame, then we are done. + if (done || frame == NULL || frame->marker != MARK_NONE) + break; + } + + if (! set) + { + // No slots, so we allocate a new frame. According to the spec + // we could just die here. FIXME: return value. + _Jv_JNI_EnsureLocalCapacity (env, 16); + // We know the first element of the new frame will be ok. + env->locals->vec[0] = obj; + env->locals->allocated_p = true; + } + + mark_for_gc (obj, local_ref_table); + return obj; +} + +static jobject JNICALL +_Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result, int stop) +{ + _Jv_JNI_LocalFrame *rf = env->locals; + + bool done = false; + while (rf != NULL && ! done) + { + for (int i = 0; i < rf->size; ++i) + if (rf->vec[i] != NULL) + unmark_for_gc (rf->vec[i], local_ref_table); + + // If the frame we just freed is the marker frame, we are done. + done = (rf->marker == stop); + + _Jv_JNI_LocalFrame *n = rf->next; + // When N==NULL, we've reached the reusable bottom_locals, and we must + // not free it. However, we must be sure to clear all its elements. + if (n == NULL) + { + if (rf->allocated_p) + memset (&rf->vec[0], 0, rf->size * sizeof (jobject)); + rf->allocated_p = false; + rf = NULL; + break; + } + + _Jv_Free (rf); + rf = n; + } + + // Update the local frame information. + env->locals = rf; + + return result == NULL ? NULL : _Jv_JNI_NewLocalRef (env, result); +} + +static jobject JNICALL +_Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result) +{ + return _Jv_JNI_PopLocalFrame (env, result, MARK_USER); +} + +// Make sure an array's type is compatible with the type of the +// destination. +template +static bool +_Jv_JNI_check_types (JNIEnv *env, JArray *array, jclass K) +{ + jclass klass = array->getClass()->getComponentType(); + if (__builtin_expect (klass != K, false)) + { + env->ex = new java::lang::IllegalAccessError (); + return false; + } + else + return true; +} + +// Pop a `system' frame from the stack. This is `extern "C"' as it is +// used by the compiler. +extern "C" void +_Jv_JNI_PopSystemFrame (JNIEnv *env) +{ + // Only enter slow path when we're not at the bottom, or there have been + // allocations. Usually this is false and we can just null out the locals + // field. + + if (__builtin_expect ((env->locals->next + || env->locals->allocated_p), false)) + _Jv_JNI_PopLocalFrame (env, NULL, MARK_SYSTEM); + else + env->locals = NULL; + +#ifdef INTERPRETER + if (__builtin_expect (env->ex != NULL, false)) + { + jthrowable t = env->ex; + env->ex = NULL; + if (JVMTI_REQUESTED_EVENT (Exception)) + _Jv_ReportJVMTIExceptionThrow (t); + throw t; + } +#endif +} + +template T extract_from_jvalue(jvalue const & t); +template<> jboolean extract_from_jvalue(jvalue const & jv) { return jv.z; } +template<> jbyte extract_from_jvalue(jvalue const & jv) { return jv.b; } +template<> jchar extract_from_jvalue(jvalue const & jv) { return jv.c; } +template<> jshort extract_from_jvalue(jvalue const & jv) { return jv.s; } +template<> jint extract_from_jvalue(jvalue const & jv) { return jv.i; } +template<> jlong extract_from_jvalue(jvalue const & jv) { return jv.j; } +template<> jfloat extract_from_jvalue(jvalue const & jv) { return jv.f; } +template<> jdouble extract_from_jvalue(jvalue const & jv) { return jv.d; } +template<> jobject extract_from_jvalue(jvalue const & jv) { return jv.l; } + + +// This function is used from other template functions. It wraps the +// return value appropriately; we specialize it so that object returns +// are turned into local references. +template +static T +wrap_value (JNIEnv *, T value) +{ + return value; +} + +// This specialization is used for jobject, jclass, jstring, jarray, +// etc. +template +static T * +wrap_value (JNIEnv *env, T *value) +{ + return (value == NULL + ? value + : (T *) _Jv_JNI_NewLocalRef (env, (jobject) value)); +} + + + +static jint JNICALL +_Jv_JNI_GetVersion (JNIEnv *) +{ + return JNI_VERSION_1_4; +} + +static jclass JNICALL +_Jv_JNI_DefineClass (JNIEnv *env, const char *name, jobject loader, + const jbyte *buf, jsize bufLen) +{ + try + { + loader = unwrap (loader); + + jstring sname = JvNewStringUTF (name); + jbyteArray bytes = JvNewByteArray (bufLen); + + jbyte *elts = elements (bytes); + memcpy (elts, buf, bufLen * sizeof (jbyte)); + + java::lang::ClassLoader *l + = reinterpret_cast (loader); + + jclass result = l->defineClass (sname, bytes, 0, bufLen); + return (jclass) wrap_value (env, result); + } + catch (jthrowable t) + { + env->ex = t; + return NULL; + } +} + +static jclass JNICALL +_Jv_JNI_FindClass (JNIEnv *env, const char *name) +{ + // FIXME: assume that NAME isn't too long. + int len = strlen (name); + char s[len + 1]; + for (int i = 0; i <= len; ++i) + s[i] = (name[i] == '/') ? '.' : name[i]; + + jclass r = NULL; + try + { + // This might throw an out of memory exception. + jstring n = JvNewStringUTF (s); + + java::lang::ClassLoader *loader = NULL; + if (env->locals->loader != NULL) + loader = env->locals->loader; + + if (loader == NULL) + { + // FIXME: should use getBaseClassLoader, but we don't have that + // yet. + loader = java::lang::ClassLoader::getSystemClassLoader (); + } + + r = loader->loadClass (n); + _Jv_InitClass (r); + } + catch (jthrowable t) + { + env->ex = t; + } + + return (jclass) wrap_value (env, r); +} + +static jclass JNICALL +_Jv_JNI_GetSuperclass (JNIEnv *env, jclass clazz) +{ + return (jclass) wrap_value (env, unwrap (clazz)->getSuperclass ()); +} + +static jboolean JNICALL +_Jv_JNI_IsAssignableFrom (JNIEnv *, jclass clazz1, jclass clazz2) +{ + return unwrap (clazz2)->isAssignableFrom (unwrap (clazz1)); +} + +static jint JNICALL +_Jv_JNI_Throw (JNIEnv *env, jthrowable obj) +{ + // We check in case the user did some funky cast. + obj = unwrap (obj); + JvAssert (obj != NULL && java::lang::Throwable::class$.isInstance (obj)); + env->ex = obj; + return 0; +} + +static jint JNICALL +_Jv_JNI_ThrowNew (JNIEnv *env, jclass clazz, const char *message) +{ + using namespace java::lang::reflect; + + clazz = unwrap (clazz); + JvAssert (java::lang::Throwable::class$.isAssignableFrom (clazz)); + + int r = JNI_OK; + try + { + JArray *argtypes + = (JArray *) JvNewObjectArray (1, &java::lang::Class::class$, + NULL); + + jclass *elts = elements (argtypes); + elts[0] = &java::lang::String::class$; + + Constructor *cons = clazz->getConstructor (argtypes); + + jobjectArray values = JvNewObjectArray (1, &java::lang::String::class$, + NULL); + jobject *velts = elements (values); + velts[0] = JvNewStringUTF (message); + + jobject obj = cons->newInstance (values); + + env->ex = reinterpret_cast (obj); + } + catch (jthrowable t) + { + env->ex = t; + r = JNI_ERR; + } + + return r; +} + +static jthrowable JNICALL +_Jv_JNI_ExceptionOccurred (JNIEnv *env) +{ + return (jthrowable) wrap_value (env, env->ex); +} + +static void JNICALL +_Jv_JNI_ExceptionDescribe (JNIEnv *env) +{ + if (env->ex != NULL) + env->ex->printStackTrace(); +} + +static void JNICALL +_Jv_JNI_ExceptionClear (JNIEnv *env) +{ + env->ex = NULL; +} + +static jboolean JNICALL +_Jv_JNI_ExceptionCheck (JNIEnv *env) +{ + return env->ex != NULL; +} + +static void JNICALL +_Jv_JNI_FatalError (JNIEnv *, const char *message) +{ + JvFail (message); +} + + + +static jboolean JNICALL +_Jv_JNI_IsSameObject (JNIEnv *, jobject obj1, jobject obj2) +{ + return unwrap (obj1) == unwrap (obj2); +} + +static jobject JNICALL +_Jv_JNI_AllocObject (JNIEnv *env, jclass clazz) +{ + jobject obj = NULL; + using namespace java::lang::reflect; + + try + { + clazz = unwrap (clazz); + JvAssert (clazz && ! clazz->isArray ()); + if (clazz->isInterface() || Modifier::isAbstract(clazz->getModifiers())) + env->ex = new java::lang::InstantiationException (); + else + obj = _Jv_AllocObject (clazz); + } + catch (jthrowable t) + { + env->ex = t; + } + + return wrap_value (env, obj); +} + +static jclass JNICALL +_Jv_JNI_GetObjectClass (JNIEnv *env, jobject obj) +{ + obj = unwrap (obj); + JvAssert (obj); + return (jclass) wrap_value (env, obj->getClass()); +} + +static jboolean JNICALL +_Jv_JNI_IsInstanceOf (JNIEnv *, jobject obj, jclass clazz) +{ + return unwrap (clazz)->isInstance(unwrap (obj)); +} + + + +// +// This section concerns method invocation. +// + +template +static jmethodID JNICALL +_Jv_JNI_GetAnyMethodID (JNIEnv *env, jclass clazz, + const char *name, const char *sig) +{ + try + { + clazz = unwrap (clazz); + _Jv_InitClass (clazz); + + _Jv_Utf8Const *name_u = _Jv_makeUtf8Const ((char *) name, -1); + + // FIXME: assume that SIG isn't too long. + int len = strlen (sig); + char s[len + 1]; + for (int i = 0; i <= len; ++i) + s[i] = (sig[i] == '/') ? '.' : sig[i]; + _Jv_Utf8Const *sig_u = _Jv_makeUtf8Const ((char *) s, -1); + + JvAssert (! clazz->isPrimitive()); + + using namespace java::lang::reflect; + + while (clazz != NULL) + { + jint count = JvNumMethods (clazz); + jmethodID meth = JvGetFirstMethod (clazz); + + for (jint i = 0; i < count; ++i) + { + if (((is_static && Modifier::isStatic (meth->accflags)) + || (! is_static && ! Modifier::isStatic (meth->accflags))) + && _Jv_equalUtf8Consts (meth->name, name_u) + && _Jv_equalUtf8Consts (meth->signature, sig_u)) + return meth; + + meth = meth->getNextMethod(); + } + + clazz = clazz->getSuperclass (); + } + + java::lang::StringBuffer *name_sig = + new java::lang::StringBuffer (JvNewStringUTF (name)); + name_sig->append ((jchar) ' '); + name_sig->append (JvNewStringUTF (s)); + env->ex = new java::lang::NoSuchMethodError (name_sig->toString ()); + } + catch (jthrowable t) + { + env->ex = t; + } + + return NULL; +} + +// This is a helper function which turns a va_list into an array of +// `jvalue's. It needs signature information in order to do its work. +// The array of values must already be allocated. +static void +array_from_valist (jvalue *values, JArray *arg_types, va_list vargs) +{ + jclass *arg_elts = elements (arg_types); + for (int i = 0; i < arg_types->length; ++i) + { + // Here we assume that sizeof(int) >= sizeof(jint), because we + // use `int' when decoding the varargs. Likewise for + // float, and double. Also we assume that sizeof(jlong) >= + // sizeof(int), i.e. that jlong values are not further + // promoted. + JvAssert (sizeof (int) >= sizeof (jint)); + JvAssert (sizeof (jlong) >= sizeof (int)); + JvAssert (sizeof (double) >= sizeof (jfloat)); + JvAssert (sizeof (double) >= sizeof (jdouble)); + if (arg_elts[i] == JvPrimClass (byte)) + values[i].b = (jbyte) va_arg (vargs, int); + else if (arg_elts[i] == JvPrimClass (short)) + values[i].s = (jshort) va_arg (vargs, int); + else if (arg_elts[i] == JvPrimClass (int)) + values[i].i = (jint) va_arg (vargs, int); + else if (arg_elts[i] == JvPrimClass (long)) + values[i].j = (jlong) va_arg (vargs, jlong); + else if (arg_elts[i] == JvPrimClass (float)) + values[i].f = (jfloat) va_arg (vargs, double); + else if (arg_elts[i] == JvPrimClass (double)) + values[i].d = (jdouble) va_arg (vargs, double); + else if (arg_elts[i] == JvPrimClass (boolean)) + values[i].z = (jboolean) va_arg (vargs, int); + else if (arg_elts[i] == JvPrimClass (char)) + values[i].c = (jchar) va_arg (vargs, int); + else + { + // An object. + values[i].l = unwrap (va_arg (vargs, jobject)); + } + } +} + +// This can call any sort of method: virtual, "nonvirtual", static, or +// constructor. +template +static T JNICALL +_Jv_JNI_CallAnyMethodV (JNIEnv *env, jobject obj, jclass klass, + jmethodID id, va_list vargs) +{ + obj = unwrap (obj); + klass = unwrap (klass); + + jclass decl_class = klass ? klass : obj->getClass (); + JvAssert (decl_class != NULL); + + jclass return_type; + JArray *arg_types; + + try + { + _Jv_GetTypesFromSignature (id, decl_class, + &arg_types, &return_type); + + jvalue args[arg_types->length]; + array_from_valist (args, arg_types, vargs); + + // For constructors we need to pass the Class we are instantiating. + if (style == constructor) + return_type = klass; + + jvalue result; + _Jv_CallAnyMethodA (obj, return_type, id, + style == constructor, + style == normal, + arg_types, args, &result); + + return wrap_value (env, extract_from_jvalue(result)); + } + catch (jthrowable t) + { + env->ex = t; + } + + return wrap_value (env, (T) 0); +} + +template +static T JNICALL +_Jv_JNI_CallAnyMethod (JNIEnv *env, jobject obj, jclass klass, + jmethodID method, ...) +{ + va_list args; + T result; + + va_start (args, method); + result = _Jv_JNI_CallAnyMethodV (env, obj, klass, method, args); + va_end (args); + + return result; +} + +template +static T JNICALL +_Jv_JNI_CallAnyMethodA (JNIEnv *env, jobject obj, jclass klass, + jmethodID id, const jvalue *args) +{ + obj = unwrap (obj); + klass = unwrap (klass); + + jclass decl_class = klass ? klass : obj->getClass (); + JvAssert (decl_class != NULL); + + jclass return_type; + JArray *arg_types; + try + { + _Jv_GetTypesFromSignature (id, decl_class, + &arg_types, &return_type); + + // For constructors we need to pass the Class we are instantiating. + if (style == constructor) + return_type = klass; + + // Unwrap arguments as required. Eww. + jclass *type_elts = elements (arg_types); + jvalue arg_copy[arg_types->length]; + for (int i = 0; i < arg_types->length; ++i) + { + if (type_elts[i]->isPrimitive ()) + arg_copy[i] = args[i]; + else + arg_copy[i].l = unwrap (args[i].l); + } + + jvalue result; + _Jv_CallAnyMethodA (obj, return_type, id, + style == constructor, + style == normal, + arg_types, arg_copy, &result); + + return wrap_value (env, extract_from_jvalue(result)); + } + catch (jthrowable t) + { + env->ex = t; + } + + return wrap_value (env, (T) 0); +} + +template +static void JNICALL +_Jv_JNI_CallAnyVoidMethodV (JNIEnv *env, jobject obj, jclass klass, + jmethodID id, va_list vargs) +{ + obj = unwrap (obj); + klass = unwrap (klass); + + jclass decl_class = klass ? klass : obj->getClass (); + JvAssert (decl_class != NULL); + + jclass return_type; + JArray *arg_types; + try + { + _Jv_GetTypesFromSignature (id, decl_class, + &arg_types, &return_type); + + jvalue args[arg_types->length]; + array_from_valist (args, arg_types, vargs); + + // For constructors we need to pass the Class we are instantiating. + if (style == constructor) + return_type = klass; + + _Jv_CallAnyMethodA (obj, return_type, id, + style == constructor, + style == normal, + arg_types, args, NULL); + } + catch (jthrowable t) + { + env->ex = t; + } +} + +template +static void JNICALL +_Jv_JNI_CallAnyVoidMethod (JNIEnv *env, jobject obj, jclass klass, + jmethodID method, ...) +{ + va_list args; + + va_start (args, method); + _Jv_JNI_CallAnyVoidMethodV