X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=libjava%2Fjni.cc;h=86a4dc5b2610738b6f5cc65124240564ef7df1c2;hb=7ab483efddd3684078a9353c747b5c5e56464d20;hp=ea2f03974f3636f7df1c7867608aa35e5b6ee319;hpb=89d1c15834957f4bc62db37dbf77b1f955f84b66;p=pf3gnuchains%2Fgcc-fork.git diff --git a/libjava/jni.cc b/libjava/jni.cc index ea2f03974f3..86a4dc5b261 100644 --- a/libjava/jni.cc +++ b/libjava/jni.cc @@ -1,6 +1,7 @@ // jni.cc - JNI implementation, including the jump table. -/* Copyright (C) 1998, 1999, 2000 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 + Free Software Foundation This file is part of libgcj. @@ -10,12 +11,10 @@ details. */ #include +#include #include #include -// Define this before including jni.h. -#define __GCJ_JNI_IMPL__ - #include #include #include @@ -23,13 +22,17 @@ details. */ #ifdef ENABLE_JVMPI #include #endif - +#ifdef INTERPRETER +#include +#include "jvmti-int.h" +#endif #include #include #include #include #include -#include +#include +#include #include #include #include @@ -37,28 +40,24 @@ details. */ #include #include #include -#include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include +#include -#define ClassClass _CL_Q34java4lang5Class -extern java::lang::Class ClassClass; -#define ObjectClass _CL_Q34java4lang6Object -extern java::lang::Class ObjectClass; - -#define ThrowableClass _CL_Q34java4lang9Throwable -extern java::lang::Class ThrowableClass; -#define MethodClass _CL_Q44java4lang7reflect6Method -extern java::lang::Class MethodClass; -#define ThreadGroupClass _CL_Q34java4lang11ThreadGroup -extern java::lang::Class ThreadGroupClass; -#define NativeThreadClass _CL_Q43gnu3gcj3jni12NativeThread -extern java::lang::Class ThreadGroupClass; +using namespace gcj; // This enum is used to select different template instantiations in // the invocation code. @@ -71,12 +70,12 @@ enum invocation_type }; // Forward declarations. -extern struct JNINativeInterface _Jv_JNIFunctions; -extern struct JNIInvokeInterface _Jv_JNI_InvokeFunctions; +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 32 +#define FRAME_SIZE 16 // Mark value indicating this is an overflow frame. #define MARK_NONE 0 @@ -88,12 +87,17 @@ extern struct JNIInvokeInterface _Jv_JNI_InvokeFunctions; // This structure is used to keep track of local references. struct _Jv_JNI_LocalFrame { - // This is true if this frame object represents a pushed frame (eg - // from PushLocalFrame). - int marker : 2; + // 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 : 30; + 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; @@ -102,11 +106,13 @@ struct _Jv_JNI_LocalFrame jobject vec[0]; }; -// This holds a reference count for all local and global references. -static java::util::Hashtable *ref_table; +// 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. -static JavaVM *the_vm; +JavaVM *_Jv_the_vm; #ifdef ENABLE_JVMPI // The only JVMPI interface description. @@ -120,19 +126,19 @@ jvmpiEnableEvent (jint event_type, void *) 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; } @@ -144,11 +150,11 @@ jvmpiDisableEvent (jint event_type, void *) case JVMPI_EVENT_OBJECT_ALLOC: _Jv_JVMPI_Notify_OBJECT_ALLOC = NULL; break; - + default: return JVMPI_NOT_AVAILABLE; } - + return JVMPI_SUCCESS; } #endif @@ -158,8 +164,9 @@ jvmpiDisableEvent (jint event_type, void *) void _Jv_JNI_Init (void) { - ref_table = new java::util::Hashtable; - + 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; @@ -172,7 +179,7 @@ _Jv_JNI_Init (void) // Tell the GC that a certain pointer is live. static void -mark_for_gc (jobject obj) +mark_for_gc (jobject obj, java::util::IdentityHashMap *ref_table) { JvSynchronize sync (ref_table); @@ -185,7 +192,7 @@ mark_for_gc (jobject obj) // Unmark a pointer. static void -unmark_for_gc (jobject obj) +unmark_for_gc (jobject obj, java::util::IdentityHashMap *ref_table) { JvSynchronize sync (ref_table); @@ -193,6 +200,7 @@ unmark_for_gc (jobject obj) 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 @@ -200,34 +208,81 @@ unmark_for_gc (jobject obj) 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 +static jobject JNICALL _Jv_JNI_NewGlobalRef (JNIEnv *, jobject obj) { - mark_for_gc (obj); + // This seems weird but I think it is correct. + obj = unwrap (obj); + mark_for_gc (obj, global_ref_table); return obj; } -static void +static void JNICALL _Jv_JNI_DeleteGlobalRef (JNIEnv *, jobject obj) { - unmark_for_gc (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 +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) + for (int i = 0; i < frame->size; ++i) { if (frame->vec[i] == obj) { frame->vec[i] = NULL; - unmark_for_gc (obj); + unmark_for_gc (obj, local_ref_table); return; } } @@ -239,7 +294,7 @@ _Jv_JNI_DeleteLocalRef (JNIEnv *env, jobject obj) JvAssert (0); } -static jint +static jint JNICALL _Jv_JNI_EnsureLocalCapacity (JNIEnv *env, jint size) { // It is easier to just always allocate a new frame of the requested @@ -260,14 +315,16 @@ _Jv_JNI_EnsureLocalCapacity (JNIEnv *env, jint size) 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 +static jint JNICALL _Jv_JNI_PushLocalFrame (JNIEnv *env, jint size) { jint r = _Jv_JNI_EnsureLocalCapacity (env, size); @@ -280,22 +337,33 @@ _Jv_JNI_PushLocalFrame (JNIEnv *env, jint size) return 0; } -static jobject +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; - while (frame != NULL && ! done) + 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; - break; - } + { + 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) @@ -305,34 +373,37 @@ _Jv_JNI_NewLocalRef (JNIEnv *env, jobject obj) _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); + mark_for_gc (obj, local_ref_table); return obj; } -static jobject +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]); + 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 stack-allocated frame, and we - // must not free it. However, we must be sure to clear all its - // elements, since we might conceivably reuse it. + // 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) { - memset (&rf->vec[0], 0, rf->size * sizeof (jobject)); + if (rf->allocated_p) + memset (&rf->vec[0], 0, rf->size * sizeof (jobject)); + rf->allocated_p = false; + rf = NULL; break; } @@ -340,26 +411,73 @@ _Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result, int stop) rf = n; } + // Update the local frame information. + env->locals = rf; + return result == NULL ? NULL : _Jv_JNI_NewLocalRef (env, result); } -static jobject +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) { - _Jv_JNI_PopLocalFrame (env, NULL, MARK_SYSTEM); + // 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 (env->ex) - throw env->ex; + 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. @@ -370,27 +488,34 @@ wrap_value (JNIEnv *, T value) return value; } -template<> -static jobject -wrap_value (JNIEnv *env, jobject value) +// This specialization is used for jobject, jclass, jstring, jarray, +// etc. +template +static T * +wrap_value (JNIEnv *env, T *value) { - return value == NULL ? value : _Jv_JNI_NewLocalRef (env, value); + return (value == NULL + ? value + : (T *) _Jv_JNI_NewLocalRef (env, (jobject) value)); } -static jint +static jint JNICALL _Jv_JNI_GetVersion (JNIEnv *) { - return JNI_VERSION_1_2; + return JNI_VERSION_1_4; } -static jclass -_Jv_JNI_DefineClass (JNIEnv *env, jobject loader, +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); @@ -399,7 +524,7 @@ _Jv_JNI_DefineClass (JNIEnv *env, jobject loader, java::lang::ClassLoader *l = reinterpret_cast (loader); - jclass result = l->defineClass (bytes, 0, bufLen); + jclass result = l->defineClass (sname, bytes, 0, bufLen); return (jclass) wrap_value (env, result); } catch (jthrowable t) @@ -409,7 +534,7 @@ _Jv_JNI_DefineClass (JNIEnv *env, jobject loader, } } -static jclass +static jclass JNICALL _Jv_JNI_FindClass (JNIEnv *env, const char *name) { // FIXME: assume that NAME isn't too long. @@ -424,17 +549,19 @@ _Jv_JNI_FindClass (JNIEnv *env, const char *name) // This might throw an out of memory exception. jstring n = JvNewStringUTF (s); - java::lang::ClassLoader *loader; - if (env->klass == NULL) + 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 (); } - else - loader = env->klass->getClassLoader (); r = loader->loadClass (n); + _Jv_InitClass (r); } catch (jthrowable t) { @@ -444,46 +571,50 @@ _Jv_JNI_FindClass (JNIEnv *env, const char *name) return (jclass) wrap_value (env, r); } -static jclass +static jclass JNICALL _Jv_JNI_GetSuperclass (JNIEnv *env, jclass clazz) { - return (jclass) wrap_value (env, clazz->getSuperclass ()); + return (jclass) wrap_value (env, unwrap (clazz)->getSuperclass ()); } -static jboolean -_Jv_JNI_IsAssignableFrom(JNIEnv *, jclass clazz1, jclass clazz2) +static jboolean JNICALL +_Jv_JNI_IsAssignableFrom (JNIEnv *, jclass clazz1, jclass clazz2) { - return clazz1->isAssignableFrom (clazz2); + return unwrap (clazz2)->isAssignableFrom (unwrap (clazz1)); } -static jint +static jint JNICALL _Jv_JNI_Throw (JNIEnv *env, jthrowable obj) { // We check in case the user did some funky cast. - JvAssert (obj != NULL && (&ThrowableClass)->isInstance (obj)); + obj = unwrap (obj); + JvAssert (obj != NULL && java::lang::Throwable::class$.isInstance (obj)); env->ex = obj; return 0; } -static jint +static jint JNICALL _Jv_JNI_ThrowNew (JNIEnv *env, jclass clazz, const char *message) { using namespace java::lang::reflect; - JvAssert ((&ThrowableClass)->isAssignableFrom (clazz)); + clazz = unwrap (clazz); + JvAssert (java::lang::Throwable::class$.isAssignableFrom (clazz)); int r = JNI_OK; try { JArray *argtypes - = (JArray *) JvNewObjectArray (1, &ClassClass, NULL); + = (JArray *) JvNewObjectArray (1, &java::lang::Class::class$, + NULL); jclass *elts = elements (argtypes); - elts[0] = &StringClass; + elts[0] = &java::lang::String::class$; Constructor *cons = clazz->getConstructor (argtypes); - jobjectArray values = JvNewObjectArray (1, &StringClass, NULL); + jobjectArray values = JvNewObjectArray (1, &java::lang::String::class$, + NULL); jobject *velts = elements (values); velts[0] = JvNewStringUTF (message); @@ -500,32 +631,32 @@ _Jv_JNI_ThrowNew (JNIEnv *env, jclass clazz, const char *message) return r; } -static jthrowable +static jthrowable JNICALL _Jv_JNI_ExceptionOccurred (JNIEnv *env) { return (jthrowable) wrap_value (env, env->ex); } -static void +static void JNICALL _Jv_JNI_ExceptionDescribe (JNIEnv *env) { if (env->ex != NULL) env->ex->printStackTrace(); } -static void +static void JNICALL _Jv_JNI_ExceptionClear (JNIEnv *env) { env->ex = NULL; } -static jboolean +static jboolean JNICALL _Jv_JNI_ExceptionCheck (JNIEnv *env) { return env->ex != NULL; } -static void +static void JNICALL _Jv_JNI_FatalError (JNIEnv *, const char *message) { JvFail (message); @@ -533,13 +664,13 @@ _Jv_JNI_FatalError (JNIEnv *, const char *message) -static jboolean +static jboolean JNICALL _Jv_JNI_IsSameObject (JNIEnv *, jobject obj1, jobject obj2) { - return obj1 == obj2; + return unwrap (obj1) == unwrap (obj2); } -static jobject +static jobject JNICALL _Jv_JNI_AllocObject (JNIEnv *env, jclass clazz) { jobject obj = NULL; @@ -547,14 +678,12 @@ _Jv_JNI_AllocObject (JNIEnv *env, jclass clazz) try { + clazz = unwrap (clazz); JvAssert (clazz && ! clazz->isArray ()); if (clazz->isInterface() || Modifier::isAbstract(clazz->getModifiers())) env->ex = new java::lang::InstantiationException (); else - { - // FIXME: will this work for String? - obj = JvAllocObject (clazz); - } + obj = _Jv_AllocObject (clazz); } catch (jthrowable t) { @@ -564,17 +693,18 @@ _Jv_JNI_AllocObject (JNIEnv *env, jclass clazz) return wrap_value (env, obj); } -static jclass +static jclass JNICALL _Jv_JNI_GetObjectClass (JNIEnv *env, jobject obj) { + obj = unwrap (obj); JvAssert (obj); return (jclass) wrap_value (env, obj->getClass()); } -static jboolean +static jboolean JNICALL _Jv_JNI_IsInstanceOf (JNIEnv *, jobject obj, jclass clazz) { - return clazz->isInstance(obj); + return unwrap (clazz)->isInstance(unwrap (obj)); } @@ -584,16 +714,23 @@ _Jv_JNI_IsInstanceOf (JNIEnv *, jobject obj, jclass clazz) // template -static jmethodID +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); - _Jv_Utf8Const *sig_u = _Jv_makeUtf8Const ((char *) sig, -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()); @@ -618,7 +755,11 @@ _Jv_JNI_GetAnyMethodID (JNIEnv *env, jclass clazz, clazz = clazz->getSuperclass (); } - env->ex = new java::lang::NoSuchMethodError (); + 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) { @@ -637,26 +778,35 @@ 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 = va_arg (vargs, jbyte); + values[i].b = (jbyte) va_arg (vargs, int); else if (arg_elts[i] == JvPrimClass (short)) - values[i].s = va_arg (vargs, jshort); + values[i].s = (jshort) va_arg (vargs, int); else if (arg_elts[i] == JvPrimClass (int)) - values[i].i = va_arg (vargs, jint); + values[i].i = (jint) va_arg (vargs, int); else if (arg_elts[i] == JvPrimClass (long)) - values[i].j = va_arg (vargs, jlong); + values[i].j = (jlong) va_arg (vargs, jlong); else if (arg_elts[i] == JvPrimClass (float)) - values[i].f = va_arg (vargs, jfloat); + values[i].f = (jfloat) va_arg (vargs, double); else if (arg_elts[i] == JvPrimClass (double)) - values[i].d = va_arg (vargs, jdouble); + values[i].d = (jdouble) va_arg (vargs, double); else if (arg_elts[i] == JvPrimClass (boolean)) - values[i].z = va_arg (vargs, jboolean); + values[i].z = (jboolean) va_arg (vargs, int); else if (arg_elts[i] == JvPrimClass (char)) - values[i].c = va_arg (vargs, jchar); + values[i].c = (jchar) va_arg (vargs, int); else { // An object. - values[i].l = va_arg (vargs, jobject); + values[i].l = unwrap (va_arg (vargs, jobject)); } } } @@ -664,12 +814,12 @@ array_from_valist (jvalue *values, JArray *arg_types, va_list vargs) // This can call any sort of method: virtual, "nonvirtual", static, or // constructor. template -static T +static T JNICALL _Jv_JNI_CallAnyMethodV (JNIEnv *env, jobject obj, jclass klass, jmethodID id, va_list vargs) { - if (style == normal) - id = _Jv_LookupDeclaredMethod (obj->getClass (), id->name, id->signature); + obj = unwrap (obj); + klass = unwrap (klass); jclass decl_class = klass ? klass : obj->getClass (); JvAssert (decl_class != NULL); @@ -690,15 +840,12 @@ _Jv_JNI_CallAnyMethodV (JNIEnv *env, jobject obj, jclass klass, return_type = klass; jvalue result; - jthrowable ex = _Jv_CallAnyMethodA (obj, return_type, id, - style == constructor, - arg_types, args, &result); - - if (ex != NULL) - env->ex = ex; + _Jv_CallAnyMethodA (obj, return_type, id, + style == constructor, + style == normal, + arg_types, args, &result); - // We cheat a little here. FIXME. - return wrap_value (env, * (T *) &result); + return wrap_value (env, extract_from_jvalue(result)); } catch (jthrowable t) { @@ -709,7 +856,7 @@ _Jv_JNI_CallAnyMethodV (JNIEnv *env, jobject obj, jclass klass, } template -static T +static T JNICALL _Jv_JNI_CallAnyMethod (JNIEnv *env, jobject obj, jclass klass, jmethodID method, ...) { @@ -724,12 +871,12 @@ _Jv_JNI_CallAnyMethod (JNIEnv *env, jobject obj, jclass klass, } template -static T +static T JNICALL _Jv_JNI_CallAnyMethodA (JNIEnv *env, jobject obj, jclass klass, - jmethodID id, jvalue *args) + jmethodID id, const jvalue *args) { - if (style == normal) - id = _Jv_LookupDeclaredMethod (obj->getClass (), id->name, id->signature); + obj = unwrap (obj); + klass = unwrap (klass); jclass decl_class = klass ? klass : obj->getClass (); JvAssert (decl_class != NULL); @@ -745,16 +892,24 @@ _Jv_JNI_CallAnyMethodA (JNIEnv *env, jobject obj, jclass klass, if (style == constructor) return_type = klass; - jvalue result; - jthrowable ex = _Jv_CallAnyMethodA (obj, return_type, id, - style == constructor, - arg_types, args, &result); + // 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); + } - if (ex != NULL) - env->ex = ex; + jvalue result; + _Jv_CallAnyMethodA (obj, return_type, id, + style == constructor, + style == normal, + arg_types, arg_copy, &result); - // We cheat a little here. FIXME. - return wrap_value (env, * (T *) &result); + return wrap_value (env, extract_from_jvalue(result)); } catch (jthrowable t) { @@ -765,12 +920,12 @@ _Jv_JNI_CallAnyMethodA (JNIEnv *env, jobject obj, jclass klass, } template -static void +static void JNICALL _Jv_JNI_CallAnyVoidMethodV (JNIEnv *env, jobject obj, jclass klass, jmethodID id, va_list vargs) { - if (style == normal) - id = _Jv_LookupDeclaredMethod (obj->getClass (), id->name, id->signature); + obj = unwrap (obj); + klass = unwrap (klass); jclass decl_class = klass ? klass : obj->getClass (); JvAssert (decl_class != NULL); @@ -789,12 +944,10 @@ _Jv_JNI_CallAnyVoidMethodV (JNIEnv *env, jobject obj, jclass klass, if (style == constructor) return_type = klass; - jthrowable ex = _Jv_CallAnyMethodA (obj, return_type, id, - style == constructor, - arg_types, args, NULL); - - if (ex != NULL) - env->ex = ex; + _Jv_CallAnyMethodA (obj, return_type, id, + style == constructor, + style == normal, + arg_types, args, NULL); } catch (jthrowable t) { @@ -803,7 +956,7 @@ _Jv_JNI_CallAnyVoidMethodV (JNIEnv *env, jobject obj, jclass klass, } template -static void +static void JNICALL _Jv_JNI_CallAnyVoidMethod (JNIEnv *env, jobject obj, jclass klass, jmethodID method, ...) { @@ -815,13 +968,10 @@ _Jv_JNI_CallAnyVoidMethod (JNIEnv *env, jobject obj, jclass klass, } template -static void +static void JNICALL _Jv_JNI_CallAnyVoidMethodA (JNIEnv *env, jobject obj, jclass klass, - jmethodID id, jvalue *args) + jmethodID id, const jvalue *args) { - if (style == normal) - id = _Jv_LookupDeclaredMethod (obj->getClass (), id->name, id->signature); - jclass decl_class = klass ? klass : obj->getClass (); JvAssert (decl_class != NULL); @@ -832,12 +982,21 @@ _Jv_JNI_CallAnyVoidMethodA (JNIEnv *env, jobject obj, jclass klass, _Jv_GetTypesFromSignature (id, decl_class, &arg_types, &return_type); - jthrowable ex = _Jv_CallAnyMethodA (obj, return_type, id, - style == constructor, - arg_types, args, NULL); + // 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); + } - if (ex != NULL) - env->ex = ex; + _Jv_CallAnyMethodA (obj, return_type, id, + style == constructor, + style == normal, + arg_types, args, NULL); } catch (jthrowable t) { @@ -848,8 +1007,9 @@ _Jv_JNI_CallAnyVoidMethodA (JNIEnv *env, jobject obj, jclass klass, // Functions with this signature are used to implement functions in // the CallMethod family. template -static T -_Jv_JNI_CallMethodV (JNIEnv *env, jobject obj, jmethodID id, va_list args) +static T JNICALL +_Jv_JNI_CallMethodV (JNIEnv *env, jobject obj, + jmethodID id, va_list args) { return _Jv_JNI_CallAnyMethodV (env, obj, NULL, id, args); } @@ -857,7 +1017,7 @@ _Jv_JNI_CallMethodV (JNIEnv *env, jobject obj, jmethodID id, va_list args) // Functions with this signature are used to implement functions in // the CallMethod family. template -static T +static T JNICALL _Jv_JNI_CallMethod (JNIEnv *env, jobject obj, jmethodID id, ...) { va_list args; @@ -873,19 +1033,21 @@ _Jv_JNI_CallMethod (JNIEnv *env, jobject obj, jmethodID id, ...) // Functions with this signature are used to implement functions in // the CallMethod family. template -static T -_Jv_JNI_CallMethodA (JNIEnv *env, jobject obj, jmethodID id, jvalue *args) +static T JNICALL +_Jv_JNI_CallMethodA (JNIEnv *env, jobject obj, + jmethodID id, const jvalue *args) { return _Jv_JNI_CallAnyMethodA (env, obj, NULL, id, args); } -static void -_Jv_JNI_CallVoidMethodV (JNIEnv *env, jobject obj, jmethodID id, va_list args) +static void JNICALL +_Jv_JNI_CallVoidMethodV (JNIEnv *env, jobject obj, + jmethodID id, va_list args) { _Jv_JNI_CallAnyVoidMethodV (env, obj, NULL, id, args); } -static void +static void JNICALL _Jv_JNI_CallVoidMethod (JNIEnv *env, jobject obj, jmethodID id, ...) { va_list args; @@ -895,8 +1057,9 @@ _Jv_JNI_CallVoidMethod (JNIEnv *env, jobject obj, jmethodID id, ...) va_end (args); } -static void -_Jv_JNI_CallVoidMethodA (JNIEnv *env, jobject obj, jmethodID id, jvalue *args) +static void JNICALL +_Jv_JNI_CallVoidMethodA (JNIEnv *env, jobject obj, + jmethodID id, const jvalue *args) { _Jv_JNI_CallAnyVoidMethodA (env, obj, NULL, id, args); } @@ -904,12 +1067,12 @@ _Jv_JNI_CallVoidMethodA (JNIEnv *env, jobject obj, jmethodID id, jvalue *args) // Functions with this signature are used to implement functions in // the CallStaticMethod family. template -static T +static T JNICALL _Jv_JNI_CallStaticMethodV (JNIEnv *env, jclass klass, jmethodID id, va_list args) { JvAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC)); - JvAssert ((&ClassClass)->isInstance (klass)); + JvAssert (java::lang::Class::class$.isInstance (unwrap (klass))); return _Jv_JNI_CallAnyMethodV (env, NULL, klass, id, args); } @@ -917,14 +1080,15 @@ _Jv_JNI_CallStaticMethodV (JNIEnv *env, jclass klass, // Functions with this signature are used to implement functions in // the CallStaticMethod family. template -static T -_Jv_JNI_CallStaticMethod (JNIEnv *env, jclass klass, jmethodID id, ...) +static T JNICALL +_Jv_JNI_CallStaticMethod (JNIEnv *env, jclass klass, + jmethodID id, ...) { va_list args; T result; JvAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC)); - JvAssert ((&ClassClass)->isInstance (klass)); + JvAssert (java::lang::Class::class$.isInstance (unwrap (klass))); va_start (args, id); result = _Jv_JNI_CallAnyMethodV (env, NULL, klass, @@ -937,25 +1101,26 @@ _Jv_JNI_CallStaticMethod (JNIEnv *env, jclass klass, jmethodID id, ...) // Functions with this signature are used to implement functions in // the CallStaticMethod family. template -static T +static T JNICALL _Jv_JNI_CallStaticMethodA (JNIEnv *env, jclass klass, jmethodID id, - jvalue *args) + const jvalue *args) { JvAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC)); - JvAssert ((&ClassClass)->isInstance (klass)); + JvAssert (java::lang::Class::class$.isInstance (unwrap (klass))); return _Jv_JNI_CallAnyMethodA (env, NULL, klass, id, args); } -static void -_Jv_JNI_CallStaticVoidMethodV (JNIEnv *env, jclass klass, jmethodID id, - va_list args) +static void JNICALL +_Jv_JNI_CallStaticVoidMethodV (JNIEnv *env, jclass klass, + jmethodID id, va_list args) { _Jv_JNI_CallAnyVoidMethodV (env, NULL, klass, id, args); } -static void -_Jv_JNI_CallStaticVoidMethod (JNIEnv *env, jclass klass, jmethodID id, ...) +static void JNICALL +_Jv_JNI_CallStaticVoidMethod (JNIEnv *env, jclass klass, + jmethodID id, ...) { va_list args; @@ -964,36 +1129,36 @@ _Jv_JNI_CallStaticVoidMethod (JNIEnv *env, jclass klass, jmethodID id, ...) va_end (args); } -static void -_Jv_JNI_CallStaticVoidMethodA (JNIEnv *env, jclass klass, jmethodID id, - jvalue *args) +static void JNICALL +_Jv_JNI_CallStaticVoidMethodA (JNIEnv *env, jclass klass, + jmethodID id, const jvalue *args) { _Jv_JNI_CallAnyVoidMethodA (env, NULL, klass, id, args); } -static jobject +static jobject JNICALL _Jv_JNI_NewObjectV (JNIEnv *env, jclass klass, jmethodID id, va_list args) { JvAssert (klass && ! klass->isArray ()); - JvAssert (! strcmp (id->name->data, "") - && id->signature->length > 2 - && id->signature->data[0] == '(' - && ! strcmp (&id->signature->data[id->signature->length - 2], + JvAssert (! strcmp (id->name->chars(), "") + && id->signature->len() > 2 + && id->signature->chars()[0] == '(' + && ! strcmp (&id->signature->chars()[id->signature->len() - 2], ")V")); return _Jv_JNI_CallAnyMethodV (env, NULL, klass, id, args); } -static jobject +static jobject JNICALL _Jv_JNI_NewObject (JNIEnv *env, jclass klass, jmethodID id, ...) { JvAssert (klass && ! klass->isArray ()); - JvAssert (! strcmp (id->name->data, "") - && id->signature->length > 2 - && id->signature->data[0] == '(' - && ! strcmp (&id->signature->data[id->signature->length - 2], + JvAssert (! strcmp (id->name->chars(), "") + && id->signature->len() > 2 + && id->signature->chars()[0] == '(' + && ! strcmp (&id->signature->chars()[id->signature->len() - 2], ")V")); va_list args; @@ -1007,15 +1172,15 @@ _Jv_JNI_NewObject (JNIEnv *env, jclass klass, jmethodID id, ...) return result; } -static jobject +static jobject JNICALL _Jv_JNI_NewObjectA (JNIEnv *env, jclass klass, jmethodID id, - jvalue *args) + const jvalue *args) { JvAssert (klass && ! klass->isArray ()); - JvAssert (! strcmp (id->name->data, "") - && id->signature->length > 2 - && id->signature->data[0] == '(' - && ! strcmp (&id->signature->data[id->signature->length - 2], + JvAssert (! strcmp (id->name->chars(), "") + && id->signature->len() > 2 + && id->signature->chars()[0] == '(' + && ! strcmp (&id->signature->chars()[id->signature->len() - 2], ")V")); return _Jv_JNI_CallAnyMethodA (env, NULL, klass, @@ -1025,47 +1190,56 @@ _Jv_JNI_NewObjectA (JNIEnv *env, jclass klass, jmethodID id, template -static T -_Jv_JNI_GetField (JNIEnv *env, jobject obj, jfieldID field) +static T JNICALL +_Jv_JNI_GetField (JNIEnv *env, jobject obj, jfieldID field) { + obj = unwrap (obj); JvAssert (obj); T *ptr = (T *) ((char *) obj + field->getOffset ()); return wrap_value (env, *ptr); } template -static void +static void JNICALL _Jv_JNI_SetField (JNIEnv *, jobject obj, jfieldID field, T value) { + obj = unwrap (obj); + value = unwrap (value); + JvAssert (obj); T *ptr = (T *) ((char *) obj + field->getOffset ()); *ptr = value; } template -static jfieldID +static jfieldID JNICALL _Jv_JNI_GetAnyFieldID (JNIEnv *env, jclass clazz, const char *name, const char *sig) { try { + clazz = unwrap (clazz); + _Jv_InitClass (clazz); _Jv_Utf8Const *a_name = _Jv_makeUtf8Const ((char *) name, -1); - jclass field_class = NULL; - if (sig[0] == '[') - field_class = _Jv_FindClassFromSignature ((char *) sig, NULL); - else - { - _Jv_Utf8Const *sig_u = _Jv_makeUtf8Const ((char *) sig, -1); - field_class = _Jv_FindClass (sig_u, NULL); - } - - // FIXME: what if field_class == NULL? + // 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]; + java::lang::ClassLoader *loader = clazz->getClassLoaderInternal (); + jclass field_class = _Jv_FindClassFromSignature ((char *) s, loader); + if (! field_class) + throw new java::lang::ClassNotFoundException(JvNewStringUTF(s)); while (clazz != NULL) { + // We acquire the class lock so that fields aren't resolved + // while we are running. + JvSynchronize sync (clazz); + jint count = (is_static ? JvNumStaticFields (clazz) : JvNumInstanceFields (clazz)); @@ -1074,12 +1248,11 @@ _Jv_JNI_GetAnyFieldID (JNIEnv *env, jclass clazz, : JvGetFirstInstanceField (clazz)); for (jint i = 0; i < count; ++i) { - // The field is resolved as a side effect of class - // initialization. - JvAssert (field->isResolved ()); - _Jv_Utf8Const *f_name = field->getNameUtf8Const(clazz); + // The field might be resolved or it might not be. It + // is much simpler to always resolve it. + _Jv_Linker::resolve_field (field, loader); if (_Jv_equalUtf8Consts (f_name, a_name) && field->getClass() == field_class) return field; @@ -1100,7 +1273,7 @@ _Jv_JNI_GetAnyFieldID (JNIEnv *env, jclass clazz, } template -static T +static T JNICALL _Jv_JNI_GetStaticField (JNIEnv *env, jclass, jfieldID field) { T *ptr = (T *) field->u.addr; @@ -1108,14 +1281,15 @@ _Jv_JNI_GetStaticField (JNIEnv *env, jclass, jfieldID field) } template -static void +static void JNICALL _Jv_JNI_SetStaticField (JNIEnv *, jclass, jfieldID field, T value) { + value = unwrap (value); T *ptr = (T *) field->u.addr; *ptr = value; } -static jstring +static jstring JNICALL _Jv_JNI_NewString (JNIEnv *env, const jchar *unichars, jsize len) { try @@ -1130,33 +1304,37 @@ _Jv_JNI_NewString (JNIEnv *env, const jchar *unichars, jsize len) } } -static jsize +static jsize JNICALL _Jv_JNI_GetStringLength (JNIEnv *, jstring string) { - return string->length(); + return unwrap (string)->length(); } -static const jchar * +static const jchar * JNICALL _Jv_JNI_GetStringChars (JNIEnv *, jstring string, jboolean *isCopy) { + string = unwrap (string); jchar *result = _Jv_GetStringChars (string); - mark_for_gc (string); + mark_for_gc (string, global_ref_table); if (isCopy) *isCopy = false; return (const jchar *) result; } -static void +static void JNICALL _Jv_JNI_ReleaseStringChars (JNIEnv *, jstring string, const jchar *) { - unmark_for_gc (string); + unmark_for_gc (unwrap (string), global_ref_table); } -static jstring +static jstring JNICALL _Jv_JNI_NewStringUTF (JNIEnv *env, const char *bytes) { try { + // For compatibility with the JDK. + if (!bytes) + return NULL; jstring result = JvNewStringUTF (bytes); return (jstring) wrap_value (env, result); } @@ -1167,20 +1345,24 @@ _Jv_JNI_NewStringUTF (JNIEnv *env, const char *bytes) } } -static jsize +static jsize JNICALL _Jv_JNI_GetStringUTFLength (JNIEnv *, jstring string) { - return JvGetStringUTFLength (string); + return JvGetStringUTFLength (unwrap (string)); } -static const char * -_Jv_JNI_GetStringUTFChars (JNIEnv *env, jstring string, jboolean *isCopy) +static const char * JNICALL +_Jv_JNI_GetStringUTFChars (JNIEnv *env, jstring string, + jboolean *isCopy) { - jsize len = JvGetStringUTFLength (string); try { + string = unwrap (string); + if (string == NULL) + return NULL; + jsize len = JvGetStringUTFLength (string); char *r = (char *) _Jv_Malloc (len + 1); - JvGetStringUTFRegion (string, 0, len, r); + JvGetStringUTFRegion (string, 0, string->length(), r); r[len] = '\0'; if (isCopy) @@ -1195,16 +1377,17 @@ _Jv_JNI_GetStringUTFChars (JNIEnv *env, jstring string, jboolean *isCopy) } } -static void +static void JNICALL _Jv_JNI_ReleaseStringUTFChars (JNIEnv *, jstring, const char *utf) { _Jv_Free ((void *) utf); } -static void -_Jv_JNI_GetStringRegion (JNIEnv *env, jstring string, jsize start, jsize len, - jchar *buf) +static void JNICALL +_Jv_JNI_GetStringRegion (JNIEnv *env, jstring string, jsize start, + jsize len, jchar *buf) { + string = unwrap (string); jchar *result = _Jv_GetStringChars (string); if (start < 0 || start > string->length () || len < 0 || start + len > string->length ()) @@ -1222,10 +1405,12 @@ _Jv_JNI_GetStringRegion (JNIEnv *env, jstring string, jsize start, jsize len, memcpy (buf, &result[start], len * sizeof (jchar)); } -static void +static void JNICALL _Jv_JNI_GetStringUTFRegion (JNIEnv *env, jstring str, jsize start, jsize len, char *buf) { + str = unwrap (str); + if (start < 0 || start > str->length () || len < 0 || start + len > str->length ()) { @@ -1242,35 +1427,39 @@ _Jv_JNI_GetStringUTFRegion (JNIEnv *env, jstring str, jsize start, _Jv_GetStringUTFRegion (str, start, len, buf); } -static const jchar * +static const jchar * JNICALL _Jv_JNI_GetStringCritical (JNIEnv *, jstring str, jboolean *isCopy) { - jchar *result = _Jv_GetStringChars (str); + jchar *result = _Jv_GetStringChars (unwrap (str)); if (isCopy) *isCopy = false; return result; } -static void +static void JNICALL _Jv_JNI_ReleaseStringCritical (JNIEnv *, jstring, const jchar *) { // Nothing. } -static jsize +static jsize JNICALL _Jv_JNI_GetArrayLength (JNIEnv *, jarray array) { - return array->length; + return unwrap (array)->length; } -static jarray -_Jv_JNI_NewObjectArray (JNIEnv *env, jsize length, jclass elementClass, - jobject init) +static jobjectArray JNICALL +_Jv_JNI_NewObjectArray (JNIEnv *env, jsize length, + jclass elementClass, jobject init) { try { + elementClass = unwrap (elementClass); + init = unwrap (init); + + _Jv_CheckCast (elementClass, init); jarray result = JvNewObjectArray (length, elementClass, init); - return (jarray) wrap_value (env, result); + return (jobjectArray) wrap_value (env, result); } catch (jthrowable t) { @@ -1279,20 +1468,28 @@ _Jv_JNI_NewObjectArray (JNIEnv *env, jsize length, jclass elementClass, } } -static jobject -_Jv_JNI_GetObjectArrayElement (JNIEnv *env, jobjectArray array, jsize index) +static jobject JNICALL +_Jv_JNI_GetObjectArrayElement (JNIEnv *env, jobjectArray array, + jsize index) { - jobject *elts = elements (array); + if ((unsigned) index >= (unsigned) array->length) + _Jv_ThrowBadArrayIndex (index); + jobject *elts = elements (unwrap (array)); return wrap_value (env, elts[index]); } -static void -_Jv_JNI_SetObjectArrayElement (JNIEnv *env, jobjectArray array, jsize index, - jobject value) +static void JNICALL +_Jv_JNI_SetObjectArrayElement (JNIEnv *env, jobjectArray array, + jsize index, jobject value) { try { + array = unwrap (array); + value = unwrap (value); + _Jv_CheckArrayStore (array, value); + if ((unsigned) index >= (unsigned) array->length) + _Jv_ThrowBadArrayIndex (index); jobject *elts = elements (array); elts[index] = value; } @@ -1303,7 +1500,7 @@ _Jv_JNI_SetObjectArrayElement (JNIEnv *env, jobjectArray array, jsize index, } template -static JArray * +static JArray * JNICALL _Jv_JNI_NewPrimitiveArray (JNIEnv *env, jsize length) { try @@ -1317,39 +1514,50 @@ _Jv_JNI_NewPrimitiveArray (JNIEnv *env, jsize length) } } -template -static T * -_Jv_JNI_GetPrimitiveArrayElements (JNIEnv *, JArray *array, +template +static T * JNICALL +_Jv_JNI_GetPrimitiveArrayElements (JNIEnv *env, JArray *array, jboolean *isCopy) { + array = unwrap (array); + if (! _Jv_JNI_check_types (env, array, K)) + return NULL; T *elts = elements (array); if (isCopy) { // We elect never to copy. *isCopy = false; } - mark_for_gc (array); + mark_for_gc (array, global_ref_table); return elts; } -template -static void -_Jv_JNI_ReleasePrimitiveArrayElements (JNIEnv *, JArray *array, +template +static void JNICALL +_Jv_JNI_ReleasePrimitiveArrayElements (JNIEnv *env, JArray *array, T *, jint /* mode */) { + array = unwrap (array); + _Jv_JNI_check_types (env, array, K); // Note that we ignore MODE. We can do this because we never copy // the array elements. My reading of the JNI documentation is that // this is an option for the implementor. - unmark_for_gc (array); + unmark_for_gc (array, global_ref_table); } -template -static void +template +static void JNICALL _Jv_JNI_GetPrimitiveArrayRegion (JNIEnv *env, JArray *array, jsize start, jsize len, T *buf) { - if (start < 0 || len >= array->length || start + len >= array->length) + array = unwrap (array); + if (! _Jv_JNI_check_types (env, array, K)) + return; + + // The cast to unsigned lets us save a comparison. + if (start < 0 || len < 0 + || (unsigned long) (start + len) > (unsigned long) array->length) { try { @@ -1369,12 +1577,18 @@ _Jv_JNI_GetPrimitiveArrayRegion (JNIEnv *env, JArray *array, } } -template -static void -_Jv_JNI_SetPrimitiveArrayRegion (JNIEnv *env, JArray *array, - jsize start, jsize len, T *buf) +template +static void JNICALL +_Jv_JNI_SetPrimitiveArrayRegion (JNIEnv *env, JArray *array, + jsize start, jsize len, const T *buf) { - if (start < 0 || len >= array->length || start + len >= array->length) + array = unwrap (array); + if (! _Jv_JNI_check_types (env, array, K)) + return; + + // The cast to unsigned lets us save a comparison. + if (start < 0 || len < 0 + || (unsigned long) (start + len) > (unsigned long) array->length) { try { @@ -1393,10 +1607,11 @@ _Jv_JNI_SetPrimitiveArrayRegion (JNIEnv *env, JArray *array, } } -static void * +static void * JNICALL _Jv_JNI_GetPrimitiveArrayCritical (JNIEnv *, jarray array, jboolean *isCopy) { + array = unwrap (array); // FIXME: does this work? jclass klass = array->getClass()->getComponentType(); JvAssert (klass->isPrimitive ()); @@ -1406,18 +1621,19 @@ _Jv_JNI_GetPrimitiveArrayCritical (JNIEnv *, jarray array, return r; } -static void +static void JNICALL _Jv_JNI_ReleasePrimitiveArrayCritical (JNIEnv *, jarray, void *, jint) { // Nothing. } -static jint +static jint JNICALL _Jv_JNI_MonitorEnter (JNIEnv *env, jobject obj) { try { - return _Jv_MonitorEnter (obj); + _Jv_MonitorEnter (unwrap (obj)); + return 0; } catch (jthrowable t) { @@ -1426,12 +1642,13 @@ _Jv_JNI_MonitorEnter (JNIEnv *env, jobject obj) return JNI_ERR; } -static jint +static jint JNICALL _Jv_JNI_MonitorExit (JNIEnv *env, jobject obj) { try { - return _Jv_MonitorExit (obj); + _Jv_MonitorExit (unwrap (obj)); + return 0; } catch (jthrowable t) { @@ -1441,12 +1658,13 @@ _Jv_JNI_MonitorExit (JNIEnv *env, jobject obj) } // JDK 1.2 -jobject +jobject JNICALL _Jv_JNI_ToReflectedField (JNIEnv *env, jclass cls, jfieldID fieldID, jboolean) { try { + cls = unwrap (cls); java::lang::reflect::Field *field = new java::lang::reflect::Field(); field->declaringClass = cls; field->offset = (char*) fieldID - (char *) cls->fields; @@ -1461,25 +1679,24 @@ _Jv_JNI_ToReflectedField (JNIEnv *env, jclass cls, jfieldID fieldID, } // JDK 1.2 -static jfieldID +static jfieldID JNICALL _Jv_JNI_FromReflectedField (JNIEnv *, jobject f) { using namespace java::lang::reflect; + f = unwrap (f); Field *field = reinterpret_cast (f); return _Jv_FromReflectedField (field); } -jobject +jobject JNICALL _Jv_JNI_ToReflectedMethod (JNIEnv *env, jclass klass, jmethodID id, jboolean) { using namespace java::lang::reflect; - // FIXME. - static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("", 6); - jobject result = NULL; + klass = unwrap (klass); try { @@ -1507,29 +1724,231 @@ _Jv_JNI_ToReflectedMethod (JNIEnv *env, jclass klass, jmethodID id, return wrap_value (env, result); } -static jmethodID +static jmethodID JNICALL _Jv_JNI_FromReflectedMethod (JNIEnv *, jobject method) { using namespace java::lang::reflect; - if ((&MethodClass)->isInstance (method)) + method = unwrap (method); + if (Method::class$.isInstance (method)) return _Jv_FromReflectedMethod (reinterpret_cast (method)); return _Jv_FromReflectedConstructor (reinterpret_cast (method)); } -static jint -_Jv_JNI_RegisterNatives (JNIEnv *env, jclass k, - const JNINativeMethod *methods, - jint nMethods) +// JDK 1.2. +jweak JNICALL +_Jv_JNI_NewWeakGlobalRef (JNIEnv *env, jobject obj) { -#ifdef INTERPRETER - // For now, this only matters for interpreted methods. FIXME. - if (! _Jv_IsInterpretedClass (k)) + using namespace gnu::gcj::runtime; + JNIWeakRef *ref = NULL; + + try { - // FIXME: throw exception. - return JNI_ERR; + // This seems weird but I think it is correct. + obj = unwrap (obj); + ref = new JNIWeakRef (obj); + mark_for_gc (ref, global_ref_table); } - _Jv_InterpClass *klass = reinterpret_cast<_Jv_InterpClass *> (k); + catch (jthrowable t) + { + env->ex = t; + } + + return reinterpret_cast (ref); +} + +void JNICALL +_Jv_JNI_DeleteWeakGlobalRef (JNIEnv *, jweak obj) +{ + // JDK compatibility. + if (obj == NULL) + return; + + using namespace gnu::gcj::runtime; + JNIWeakRef *ref = reinterpret_cast (obj); + unmark_for_gc (ref, global_ref_table); + ref->clear (); +} + + + +// Direct byte buffers. + +static jobject JNICALL +_Jv_JNI_NewDirectByteBuffer (JNIEnv *, void *address, jlong length) +{ + using namespace gnu::gcj; + using namespace java::nio; + return new DirectByteBufferImpl$ReadWrite + (reinterpret_cast (address), length); +} + +static void * JNICALL +_Jv_JNI_GetDirectBufferAddress (JNIEnv *, jobject buffer) +{ + using namespace java::nio; + if (! _Jv_IsInstanceOf (buffer, &Buffer::class$)) + return NULL; + Buffer *tmp = static_cast (buffer); + return reinterpret_cast (tmp->address); +} + +static jlong JNICALL +_Jv_JNI_GetDirectBufferCapacity (JNIEnv *, jobject buffer) +{ + using namespace java::nio; + if (! _Jv_IsInstanceOf (buffer, &Buffer::class$)) + return -1; + Buffer *tmp = static_cast (buffer); + if (tmp->address == NULL) + return -1; + return tmp->capacity(); +} + +static jobjectRefType JNICALL +_Jv_JNI_GetObjectRefType (JNIEnv *, MAYBE_UNUSED jobject object) +{ + JvFail("GetObjectRefType not implemented"); + return JNIInvalidRefType; +} + + + +struct NativeMethodCacheEntry : public JNINativeMethod +{ + char *className; +}; + +// Hash table of native methods. +static NativeMethodCacheEntry *nathash; +// Number of slots used. +static int nathash_count = 0; +// Number of slots available. Must be power of 2. +static int nathash_size = 0; + +#define DELETED_ENTRY ((char *) (~0)) + +// Compute a hash value for a native method descriptor. +static int +hash (const NativeMethodCacheEntry *method) +{ + char *ptr; + int hash = 0; + + ptr = method->className; + while (*ptr) + hash = (31 * hash) + *ptr++; + + ptr = method->name; + while (*ptr) + hash = (31 * hash) + *ptr++; + + ptr = method->signature; + while (*ptr) + hash = (31 * hash) + *ptr++; + + return hash; +} + +// Find the slot where a native method goes. +static NativeMethodCacheEntry * +nathash_find_slot (const NativeMethodCacheEntry *method) +{ + jint h = hash (method); + int step = (h ^ (h >> 16)) | 1; + int w = h & (nathash_size - 1); + int del = -1; + + for (;;) + { + NativeMethodCacheEntry *slotp = &nathash[w]; + if (slotp->name == NULL) + { + if (del >= 0) + return &nathash[del]; + else + return slotp; + } + else if (slotp->name == DELETED_ENTRY) + del = w; + else if (! strcmp (slotp->name, method->name) + && ! strcmp (slotp->signature, method->signature) + && ! strcmp (slotp->className, method->className)) + return slotp; + w = (w + step) & (nathash_size - 1); + } +} + +// Find a method. Return NULL if it isn't in the hash table. +static void * +nathash_find (NativeMethodCacheEntry *method) +{ + if (nathash == NULL) + return NULL; + NativeMethodCacheEntry *slot = nathash_find_slot (method); + if (slot->name == NULL || slot->name == DELETED_ENTRY) + return NULL; + return slot->fnPtr; +} + +static void +natrehash () +{ + if (nathash == NULL) + { + nathash_size = 1024; + nathash = + (NativeMethodCacheEntry *) _Jv_AllocBytes (nathash_size + * sizeof (NativeMethodCacheEntry)); + } + else + { + int savesize = nathash_size; + NativeMethodCacheEntry *savehash = nathash; + nathash_size *= 2; + nathash = + (NativeMethodCacheEntry *) _Jv_AllocBytes (nathash_size + * sizeof (NativeMethodCacheEntry)); + + for (int i = 0; i < savesize; ++i) + { + if (savehash[i].name != NULL && savehash[i].name != DELETED_ENTRY) + { + NativeMethodCacheEntry *slot = nathash_find_slot (&savehash[i]); + *slot = savehash[i]; + } + } + } +} + +static void +nathash_add (const NativeMethodCacheEntry *method) +{ + if (3 * nathash_count >= 2 * nathash_size) + natrehash (); + NativeMethodCacheEntry *slot = nathash_find_slot (method); + // If the slot has a real entry in it, then there is no work to do. + if (slot->name != NULL && slot->name != DELETED_ENTRY) + return; + // FIXME: memory leak? + slot->name = strdup (method->name); + slot->className = strdup (method->className); + // This was already strduped in _Jv_JNI_RegisterNatives. + slot->signature = method->signature; + slot->fnPtr = method->fnPtr; +} + +static jint JNICALL +_Jv_JNI_RegisterNatives (JNIEnv *env, jclass klass, + const JNINativeMethod *methods, + jint nMethods) +{ + // Synchronize while we do the work. This must match + // synchronization in some other functions that manipulate or use + // the nathash table. + JvSynchronize sync (global_ref_table); + + NativeMethodCacheEntry dottedMethod; // Look at each descriptor given us, and find the corresponding // method in the class. @@ -1537,23 +1956,37 @@ _Jv_JNI_RegisterNatives (JNIEnv *env, jclass k, { bool found = false; - _Jv_MethodBase **imeths = _Jv_GetFirstMethod (klass); + _Jv_Method *imeths = JvGetFirstMethod (klass); for (int i = 0; i < JvNumMethods (klass); ++i) { - _Jv_MethodBase *meth = imeths[i]; - _Jv_Method *self = meth->get_method (); + _Jv_Method *self = &imeths[i]; + + // Copy this JNINativeMethod and do a slash to dot + // conversion on the signature. + dottedMethod.name = methods[j].name; + // FIXME: we leak a little memory here if the method + // is not found. + dottedMethod.signature = strdup (methods[j].signature); + dottedMethod.fnPtr = methods[j].fnPtr; + dottedMethod.className = _Jv_GetClassNameUtf8 (klass)->chars(); + char *c = dottedMethod.signature; + while (*c) + { + if (*c == '/') + *c = '.'; + c++; + } - if (! strcmp (self->name->data, methods[j].name) - && ! strcmp (self->signature->data, methods[j].signature)) + if (! strcmp (self->name->chars (), dottedMethod.name) + && ! strcmp (self->signature->chars (), dottedMethod.signature)) { - if (! (self->accflags - & java::lang::reflect::Modifier::NATIVE)) + if (! (self->accflags & java::lang::reflect::Modifier::NATIVE)) break; // Found a match that is native. - _Jv_JNIMethod *jmeth = reinterpret_cast<_Jv_JNIMethod *> (meth); - jmeth->set_function (methods[i].fnPtr); found = true; + nathash_add (&dottedMethod); + break; } } @@ -1563,7 +1996,7 @@ _Jv_JNI_RegisterNatives (JNIEnv *env, jclass k, jstring m = JvNewStringUTF (methods[j].name); try { - env->ex =new java::lang::NoSuchMethodError (m); + env->ex = new java::lang::NoSuchMethodError (m); } catch (jthrowable t) { @@ -1574,21 +2007,17 @@ _Jv_JNI_RegisterNatives (JNIEnv *env, jclass k, } return JNI_OK; -#else /* INTERPRETER */ - return JNI_ERR; -#endif /* INTERPRETER */ } -static jint +static jint JNICALL _Jv_JNI_UnregisterNatives (JNIEnv *, jclass) { + // FIXME -- we could implement this. return JNI_ERR; } -#ifdef INTERPRETER - // Add a character to the buffer, encoding properly. static void add_char (char *buf, jchar c, int *here) @@ -1608,11 +2037,14 @@ add_char (char *buf, jchar c, int *here) buf[(*here)++] = '_'; buf[(*here)++] = '3'; } - else if (c == '/') + + // Also check for `.' here because we might be passed an internal + // qualified class name like `foo.bar'. + else if (c == '/' || c == '.') buf[(*here)++] = '_'; else if ((c >= '0' && c <= '9') - || (c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z')) + || (c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z')) buf[(*here)++] = (char) c; else { @@ -1622,7 +2054,7 @@ add_char (char *buf, jchar c, int *here) for (int i = 0; i < 4; ++i) { int val = c & 0x0f; - buf[(*here) + 4 - i] = (val > 10) ? ('a' + val - 10) : ('0' + val); + buf[(*here) + 3 - i] = (val > 10) ? ('a' + val - 10) : ('0' + val); c >>= 4; } *here += 4; @@ -1649,8 +2081,8 @@ mangled_name (jclass klass, _Jv_Utf8Const *func_name, // Don't use add_char because we need a literal `_'. buf[here++] = '_'; - const unsigned char *fn = (const unsigned char *) func_name->data; - const unsigned char *limit = fn + func_name->length; + const unsigned char *fn = (const unsigned char *) func_name->chars (); + const unsigned char *limit = fn + func_name->len (); for (int i = 0; ; ++i) { int ch = UTF8_GET (fn, limit); @@ -1664,8 +2096,8 @@ mangled_name (jclass klass, _Jv_Utf8Const *func_name, buf[here++] = '_'; buf[here++] = '_'; - const unsigned char *sig = (const unsigned char *) signature->data; - limit = sig + signature->length; + const unsigned char *sig = (const unsigned char *) signature->chars (); + limit = sig + signature->len (); JvAssert (sig[0] == '('); ++sig; while (1) @@ -1679,73 +2111,200 @@ mangled_name (jclass klass, _Jv_Utf8Const *func_name, buf[here] = '\0'; } -// Return the current thread's JNIEnv; if one does not exist, create -// it. Also create a new system frame for use. This is `extern "C"' -// because the compiler calls it. -extern "C" JNIEnv * -_Jv_GetJNIEnvNewFrame (jclass klass) +JNIEnv * +_Jv_GetJNIEnvNewFrameWithLoader (::java::lang::ClassLoader *loader) { JNIEnv *env = _Jv_GetCurrentJNIEnv (); - if (env == NULL) + if (__builtin_expect (env == NULL, false)) { env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv)); - env->p = &_Jv_JNIFunctions; - env->ex = NULL; - env->klass = klass; + env->functions = &_Jv_JNIFunctions; env->locals = NULL; + // We set env->ex below. + + // Set up the bottom, reusable frame. + env->bottom_locals = (_Jv_JNI_LocalFrame *) + _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame) + + (FRAME_SIZE + * sizeof (jobject))); + + env->bottom_locals->marker = MARK_SYSTEM; + env->bottom_locals->size = FRAME_SIZE; + env->bottom_locals->next = NULL; + env->bottom_locals->allocated_p = false; + // We set the klass field below. + memset (&env->bottom_locals->vec[0], 0, + env->bottom_locals->size * sizeof (jobject)); _Jv_SetCurrentJNIEnv (env); } - _Jv_JNI_LocalFrame *frame - = (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame) - + (FRAME_SIZE - * sizeof (jobject))); + // If we're in a simple JNI call (non-nested), we can just reuse the + // locals frame we allocated many calls ago, back when the env was first + // built, above. - frame->marker = MARK_SYSTEM; - frame->size = FRAME_SIZE; - frame->next = env->locals; - env->locals = frame; + if (__builtin_expect (env->locals == NULL, true)) + { + env->locals = env->bottom_locals; + env->locals->loader = loader; + } + else + { + // Alternatively, we might be re-entering JNI, in which case we can't + // reuse the bottom_locals frame, because it is already underneath + // us. So we need to make a new one. + _Jv_JNI_LocalFrame *frame + = (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame) + + (FRAME_SIZE + * sizeof (jobject))); + + frame->marker = MARK_SYSTEM; + frame->size = FRAME_SIZE; + frame->allocated_p = false; + frame->next = env->locals; + frame->loader = loader; - for (int i = 0; i < frame->size; ++i) - frame->vec[i] = NULL; + memset (&frame->vec[0], 0, + frame->size * sizeof (jobject)); + + env->locals = frame; + } + + env->ex = NULL; return env; } +// Return the current thread's JNIEnv; if one does not exist, create +// it. Also create a new system frame for use. This is `extern "C"' +// because the compiler calls it. +extern "C" JNIEnv * +_Jv_GetJNIEnvNewFrame (jclass klass) +{ + return _Jv_GetJNIEnvNewFrameWithLoader (klass->getClassLoaderInternal()); +} + +// Destroy the env's reusable resources. This is called from the thread +// destructor "finalize_native" in natThread.cc +void +_Jv_FreeJNIEnv (_Jv_JNIEnv *env) +{ + if (env == NULL) + return; + + if (env->bottom_locals != NULL) + _Jv_Free (env->bottom_locals); + + _Jv_Free (env); +} + // Return the function which implements a particular JNI method. If // we can't find the function, we throw the appropriate exception. // This is `extern "C"' because the compiler uses it. extern "C" void * _Jv_LookupJNIMethod (jclass klass, _Jv_Utf8Const *name, - _Jv_Utf8Const *signature) + _Jv_Utf8Const *signature, MAYBE_UNUSED int args_size) { - char buf[10 + 6 * (name->length + signature->length)]; + int name_length = name->len(); + int sig_length = signature->len(); + char buf[10 + 6 * (name_length + sig_length) + 12]; int long_start; void *function; - mangled_name (klass, name, signature, buf, &long_start); - char c = buf[long_start]; - buf[long_start] = '\0'; - function = _Jv_FindSymbolInExecutable (buf); + // Synchronize on something convenient. Right now we use the hash. + JvSynchronize sync (global_ref_table); + + // First see if we have an override in the hash table. + strncpy (buf, name->chars (), name_length); + buf[name_length] = '\0'; + strncpy (buf + name_length + 1, signature->chars (), sig_length); + buf[name_length + sig_length + 1] = '\0'; + NativeMethodCacheEntry meth; + meth.name = buf; + meth.signature = buf + name_length + 1; + meth.className = _Jv_GetClassNameUtf8(klass)->chars(); + function = nathash_find (&meth); + if (function != NULL) + return function; + + // If there was no override, then look in the symbol table. + buf[0] = '_'; + mangled_name (klass, name, signature, buf + 1, &long_start); + char c = buf[long_start + 1]; + buf[long_start + 1] = '\0'; + + function = _Jv_FindSymbolInExecutable (buf + 1); +#ifdef WIN32 + // On Win32, we use the "stdcall" calling convention (see JNICALL + // in jni.h). + // + // For a function named 'fooBar' that takes 'nn' bytes as arguments, + // by default, MinGW GCC exports it as 'fooBar@nn', MSVC exports it + // as '_fooBar@nn' and Borland C exports it as 'fooBar'. We try to + // take care of all these variations here. + + char asz_buf[12]; /* '@' + '2147483647' (32-bit INT_MAX) + '\0' */ + char long_nm_sv[11]; /* Ditto, except for the '\0'. */ + if (function == NULL) { - buf[long_start] = c; + // We have tried searching for the 'fooBar' form (BCC) - now + // try the others. + + // First, save the part of the long name that will be damaged + // by appending '@nn'. + memcpy (long_nm_sv, (buf + long_start + 1 + 1), sizeof (long_nm_sv)); + + sprintf (asz_buf, "@%d", args_size); + strcat (buf, asz_buf); + + // Search for the '_fooBar@nn' form (MSVC). function = _Jv_FindSymbolInExecutable (buf); + + if (function == NULL) + { + // Search for the 'fooBar@nn' form (MinGW GCC). + function = _Jv_FindSymbolInExecutable (buf + 1); + } + } +#endif /* WIN32 */ + + if (function == NULL) + { + buf[long_start + 1] = c; +#ifdef WIN32 + // Restore the part of the long name that was damaged by + // appending the '@nn'. + memcpy ((buf + long_start + 1 + 1), long_nm_sv, sizeof (long_nm_sv)); +#endif /* WIN32 */ + function = _Jv_FindSymbolInExecutable (buf + 1); if (function == NULL) { - jstring str = JvNewStringUTF (name->data); - JvThrow (new java::lang::AbstractMethodError (str)); +#ifdef WIN32 + strcat (buf, asz_buf); + function = _Jv_FindSymbolInExecutable (buf); + if (function == NULL) + function = _Jv_FindSymbolInExecutable (buf + 1); + + if (function == NULL) +#endif /* WIN32 */ + { + jstring str = JvNewStringUTF (name->chars ()); + throw new java::lang::UnsatisfiedLinkError (str); + } } } return function; } +#ifdef INTERPRETER + // This function is the stub which is used to turn an ordinary (CNI) // method call into a JNI call. void -_Jv_JNIMethod::call (ffi_cif *, void *ret, ffi_raw *args, void *__this) +_Jv_JNIMethod::call (ffi_cif *, void *ret, INTERP_FFI_RAW_TYPE *args, + void *__this) { _Jv_JNIMethod* _this = (_Jv_JNIMethod *) __this; @@ -1758,13 +2317,28 @@ _Jv_JNIMethod::call (ffi_cif *, void *ret, ffi_raw *args, void *__this) // We cache the value that we find, of course, but if we don't find // a value we don't cache that fact -- we might subsequently load a // library which finds the function in question. - if (_this->function == NULL) - _this->function = _Jv_LookupJNIMethod (_this->defining_class, - _this->self->name, - _this->self->signature); - - JvAssert (_this->args_raw_size % sizeof (ffi_raw) == 0); - ffi_raw real_args[2 + _this->args_raw_size / sizeof (ffi_raw)]; + { + // Synchronize on a convenient object to ensure sanity in case two + // threads reach this point for the same function at the same + // time. + JvSynchronize sync (global_ref_table); + if (_this->function == NULL) + { + int args_size = sizeof (JNIEnv *) + _this->args_raw_size; + + if (_this->self->accflags & java::lang::reflect::Modifier::STATIC) + args_size += sizeof (_this->defining_class); + + _this->function = _Jv_LookupJNIMethod (_this->defining_class, + _this->self->name, + _this->self->signature, + args_size); + } + } + + JvAssert (_this->args_raw_size % sizeof (INTERP_FFI_RAW_TYPE) == 0); + INTERP_FFI_RAW_TYPE + real_args[2 + _this->args_raw_size / sizeof (INTERP_FFI_RAW_TYPE)]; int offset = 0; // First argument is always the environment pointer. @@ -1775,12 +2349,42 @@ _Jv_JNIMethod::call (ffi_cif *, void *ret, ffi_raw *args, void *__this) if ((_this->self->accflags & java::lang::reflect::Modifier::STATIC)) real_args[offset++].ptr = _this->defining_class; + // In libgcj, the callee synchronizes. + jobject sync = NULL; + if ((_this->self->accflags & java::lang::reflect::Modifier::SYNCHRONIZED)) + { + if ((_this->self->accflags & java::lang::reflect::Modifier::STATIC)) + sync = _this->defining_class; + else + sync = (jobject) args[0].ptr; + _Jv_MonitorEnter (sync); + } + // Copy over passed-in arguments. memcpy (&real_args[offset], args, _this->args_raw_size); + + // Add a frame to the composite (interpreted + JNI) call stack + java::lang::Thread *thread = java::lang::Thread::currentThread(); + _Jv_NativeFrame nat_frame (_this, thread); // The actual call to the JNI function. - ffi_raw_call (&_this->jni_cif, (void (*) (...)) _this->function, +#if FFI_NATIVE_RAW_API + ffi_raw_call (&_this->jni_cif, (void (*)()) _this->function, ret, real_args); +#else + ffi_java_raw_call (&_this->jni_cif, (void (*)()) _this->function, + ret, real_args); +#endif + + // We might need to unwrap a JNI weak reference here. + if (_this->jni_cif.rtype == &ffi_type_pointer) + { + _Jv_value *val = (_Jv_value *) ret; + val->object_value = unwrap (val->object_value); + } + + if (sync != NULL) + _Jv_MonitorExit (sync); _Jv_JNI_PopSystemFrame (env); } @@ -1795,7 +2399,8 @@ _Jv_JNIMethod::call (ffi_cif *, void *ret, ffi_raw *args, void *__this) // An internal helper function. static jint -_Jv_JNI_AttachCurrentThread (JavaVM *, jstring name, void **penv, void *args) +_Jv_JNI_AttachCurrentThread (JavaVM *, jstring name, void **penv, + void *args, jboolean is_daemon) { JavaVMAttachArgs *attach = reinterpret_cast (args); java::lang::ThreadGroup *group = NULL; @@ -1803,33 +2408,48 @@ _Jv_JNI_AttachCurrentThread (JavaVM *, jstring name, void **penv, void *args) if (attach) { // FIXME: do we really want to support 1.1? - if (attach->version != JNI_VERSION_1_2 + if (attach->version != JNI_VERSION_1_4 + && attach->version != JNI_VERSION_1_2 && attach->version != JNI_VERSION_1_1) return JNI_EVERSION; - JvAssert ((&ThreadGroupClass)->isInstance (attach->group)); + JvAssert (java::lang::ThreadGroup::class$.isInstance (attach->group)); group = reinterpret_cast (attach->group); } // Attaching an already-attached thread is a no-op. - if (_Jv_GetCurrentJNIEnv () != NULL) - return 0; + JNIEnv *env = _Jv_GetCurrentJNIEnv (); + if (env != NULL) + { + *penv = reinterpret_cast (env); + return 0; + } - JNIEnv *env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv)); + env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv)); if (env == NULL) return JNI_ERR; - env->p = &_Jv_JNIFunctions; + env->functions = &_Jv_JNIFunctions; env->ex = NULL; - env->klass = NULL; - env->locals + env->bottom_locals = (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame) + (FRAME_SIZE * sizeof (jobject))); + env->locals = env->bottom_locals; if (env->locals == NULL) { _Jv_Free (env); return JNI_ERR; } + + env->locals->allocated_p = false; + env->locals->marker = MARK_SYSTEM; + env->locals->size = FRAME_SIZE; + env->locals->loader = NULL; + env->locals->next = NULL; + + for (int i = 0; i < env->locals->size; ++i) + env->locals->vec[i] = NULL; + *penv = reinterpret_cast (env); // This thread might already be a Java thread -- this function might @@ -1838,7 +2458,10 @@ _Jv_JNI_AttachCurrentThread (JavaVM *, jstring name, void **penv, void *args) { try { - (void) new gnu::gcj::jni::NativeThread (group, name); + if (is_daemon) + _Jv_AttachCurrentThreadAsDaemon (name, group); + else + _Jv_AttachCurrentThread (name, group); } catch (jthrowable t) { @@ -1851,18 +2474,30 @@ _Jv_JNI_AttachCurrentThread (JavaVM *, jstring name, void **penv, void *args) } // This is the one actually used by JNI. -static jint +jint JNICALL _Jv_JNI_AttachCurrentThread (JavaVM *vm, void **penv, void *args) { - return _Jv_JNI_AttachCurrentThread (vm, NULL, penv, args); + return _Jv_JNI_AttachCurrentThread (vm, NULL, penv, args, false); } -static jint +static jint JNICALL +_Jv_JNI_AttachCurrentThreadAsDaemon (JavaVM *vm, void **penv, + void *args) +{ + return _Jv_JNI_AttachCurrentThread (vm, NULL, penv, args, true); +} + +static jint JNICALL _Jv_JNI_DestroyJavaVM (JavaVM *vm) { - JvAssert (the_vm && vm == the_vm); + JvAssert (_Jv_the_vm && vm == _Jv_the_vm); + + union + { + JNIEnv *env; + void *env_p; + }; - JNIEnv *env; if (_Jv_ThreadCurrent () != NULL) { jstring main_name; @@ -1876,10 +2511,8 @@ _Jv_JNI_DestroyJavaVM (JavaVM *vm) return JNI_ERR; } - jint r = _Jv_JNI_AttachCurrentThread (vm, - main_name, - reinterpret_cast (&env), - NULL); + jint r = _Jv_JNI_AttachCurrentThread (vm, main_name, &env_p, + NULL, false); if (r < 0) return r; } @@ -1892,31 +2525,14 @@ _Jv_JNI_DestroyJavaVM (JavaVM *vm) return JNI_ERR; } -static jint +jint JNICALL _Jv_JNI_DetachCurrentThread (JavaVM *) { - java::lang::Thread *t = _Jv_ThreadCurrent (); - if (t == NULL) - return JNI_EDETACHED; - - // FIXME: we only allow threads attached via AttachCurrentThread to - // be detached. I have no idea how we could implement detaching - // other threads, given the requirement that we must release all the - // monitors. That just seems evil. - JvAssert ((&NativeThreadClass)->isInstance (t)); - - // FIXME: release the monitors. We'll take this to mean all - // monitors acquired via the JNI interface. This means we have to - // keep track of them. - - gnu::gcj::jni::NativeThread *nt - = reinterpret_cast (t); - nt->finish (); - - return 0; + jint code = _Jv_DetachCurrentThread (); + return code ? JNI_EDETACHED : 0; } -static jint +static jint JNICALL _Jv_JNI_GetEnv (JavaVM *, void **penv, jint version) { if (_Jv_ThreadCurrent () == NULL) @@ -1934,8 +2550,18 @@ _Jv_JNI_GetEnv (JavaVM *, void **penv, jint version) } #endif +#ifdef INTERPRETER + // Handle JVMTI requests + if (version == JVMTI_VERSION_1_0) + { + *penv = (void *) _Jv_GetJVMTIEnv (); + return 0; + } +#endif + // FIXME: do we really want to support 1.1? - if (version != JNI_VERSION_1_2 && version != JNI_VERSION_1_1) + if (version != JNI_VERSION_1_4 && version != JNI_VERSION_1_2 + && version != JNI_VERSION_1_1) { *penv = NULL; return JNI_EVERSION; @@ -1945,111 +2571,16 @@ _Jv_JNI_GetEnv (JavaVM *, void **penv, jint version) return 0; } -jint -JNI_GetDefaultJavaVMInitArgs (void *args) -{ - jint version = * (jint *) args; - // Here we only support 1.2. - if (version != JNI_VERSION_1_2) - return JNI_EVERSION; - - JavaVMInitArgs *ia = reinterpret_cast (args); - ia->version = JNI_VERSION_1_2; - ia->nOptions = 0; - ia->options = NULL; - ia->ignoreUnrecognized = true; - - return 0; -} - -jint -JNI_CreateJavaVM (JavaVM **vm, void **penv, void *args) -{ - JvAssert (! the_vm); - // FIXME: synchronize - JavaVM *nvm = (JavaVM *) _Jv_MallocUnchecked (sizeof (JavaVM)); - if (nvm == NULL) - return JNI_ERR; - nvm->functions = &_Jv_JNI_InvokeFunctions; - - // Parse the arguments. - if (args != NULL) - { - jint version = * (jint *) args; - // We only support 1.2. - if (version != JNI_VERSION_1_2) - return JNI_EVERSION; - JavaVMInitArgs *ia = reinterpret_cast (args); - for (int i = 0; i < ia->nOptions; ++i) - { - if (! strcmp (ia->options[i].optionString, "vfprintf") - || ! strcmp (ia->options[i].optionString, "exit") - || ! strcmp (ia->options[i].optionString, "abort")) - { - // We are required to recognize these, but for now we - // don't handle them in any way. FIXME. - continue; - } - else if (! strncmp (ia->options[i].optionString, - "-verbose", sizeof ("-verbose") - 1)) - { - // We don't do anything with this option either. We - // might want to make sure the argument is valid, but we - // don't really care all that much for now. - continue; - } - else if (! strncmp (ia->options[i].optionString, "-D", 2)) - { - // FIXME. - continue; - } - else if (ia->ignoreUnrecognized) - { - if (ia->options[i].optionString[0] == '_' - || ! strncmp (ia->options[i].optionString, "-X", 2)) - continue; - } - - return JNI_ERR; - } - } - - jint r =_Jv_JNI_AttachCurrentThread (nvm, penv, NULL); - if (r < 0) - return r; - - the_vm = nvm; - *vm = the_vm; - return 0; -} - -jint -JNI_GetCreatedJavaVMs (JavaVM **vm_buffer, jsize buf_len, jsize *n_vms) -{ - if (buf_len <= 0) - return JNI_ERR; - - // We only support a single VM. - if (the_vm != NULL) - { - vm_buffer[0] = the_vm; - *n_vms = 1; - } - else - *n_vms = 0; - return 0; -} - JavaVM * _Jv_GetJavaVM () { // FIXME: synchronize - if (! the_vm) + if (! _Jv_the_vm) { JavaVM *nvm = (JavaVM *) _Jv_MallocUnchecked (sizeof (JavaVM)); if (nvm != NULL) nvm->functions = &_Jv_JNI_InvokeFunctions; - the_vm = nvm; + _Jv_the_vm = nvm; } // If this is a Java thread, we want to make sure it has an @@ -2057,13 +2588,13 @@ _Jv_GetJavaVM () if (_Jv_ThreadCurrent () != NULL) { void *ignore; - _Jv_JNI_AttachCurrentThread (the_vm, &ignore, NULL); + _Jv_JNI_AttachCurrentThread (_Jv_the_vm, &ignore, NULL); } - return the_vm; + return _Jv_the_vm; } -static jint +static jint JNICALL _Jv_JNI_GetJavaVM (JNIEnv *, JavaVM **vm) { *vm = _Jv_GetJavaVM (); @@ -2072,256 +2603,294 @@ _Jv_JNI_GetJavaVM (JNIEnv *, JavaVM **vm) -#define NOT_IMPL NULL #define RESERVED NULL -struct JNINativeInterface _Jv_JNIFunctions = +struct JNINativeInterface_ _Jv_JNIFunctions = { RESERVED, RESERVED, RESERVED, RESERVED, - _Jv_JNI_GetVersion, - _Jv_JNI_DefineClass, - _Jv_JNI_FindClass, - _Jv_JNI_FromReflectedMethod, - _Jv_JNI_FromReflectedField, - _Jv_JNI_ToReflectedMethod, - _Jv_JNI_GetSuperclass, - _Jv_JNI_IsAssignableFrom, - _Jv_JNI_ToReflectedField, - _Jv_JNI_Throw, - _Jv_JNI_ThrowNew, - _Jv_JNI_ExceptionOccurred, - _Jv_JNI_ExceptionDescribe, - _Jv_JNI_ExceptionClear, - _Jv_JNI_FatalError, - - _Jv_JNI_PushLocalFrame, - _Jv_JNI_PopLocalFrame, - _Jv_JNI_NewGlobalRef, - _Jv_JNI_DeleteGlobalRef, - _Jv_JNI_DeleteLocalRef, - - _Jv_JNI_IsSameObject, - - _Jv_JNI_NewLocalRef, - _Jv_JNI_EnsureLocalCapacity, - - _Jv_JNI_AllocObject, - _Jv_JNI_NewObject, - _Jv_JNI_NewObjectV, - _Jv_JNI_NewObjectA, - _Jv_JNI_GetObjectClass, - _Jv_JNI_IsInstanceOf, - _Jv_JNI_GetAnyMethodID, - - _Jv_JNI_CallMethod, - _Jv_JNI_CallMethodV, - _Jv_JNI_CallMethodA, - _Jv_JNI_CallMethod, - _Jv_JNI_CallMethodV, - _Jv_JNI_CallMethodA, - _Jv_JNI_CallMethod, - _Jv_JNI_CallMethodV, - _Jv_JNI_CallMethodA, - _Jv_JNI_CallMethod, - _Jv_JNI_CallMethodV, - _Jv_JNI_CallMethodA, - _Jv_JNI_CallMethod, - _Jv_JNI_CallMethodV, - _Jv_JNI_CallMethodA, - _Jv_JNI_CallMethod, - _Jv_JNI_CallMethodV, - _Jv_JNI_CallMethodA, - _Jv_JNI_CallMethod, - _Jv_JNI_CallMethodV, - _Jv_JNI_CallMethodA, - _Jv_JNI_CallMethod, - _Jv_JNI_CallMethodV, - _Jv_JNI_CallMethodA, - _Jv_JNI_CallMethod, - _Jv_JNI_CallMethodV, - _Jv_JNI_CallMethodA, - _Jv_JNI_CallVoidMethod, - _Jv_JNI_CallVoidMethodV, - _Jv_JNI_CallVoidMethodA, + _Jv_JNI_GetVersion, // GetVersion + _Jv_JNI_DefineClass, // DefineClass + _Jv_JNI_FindClass, // FindClass + _Jv_JNI_FromReflectedMethod, // FromReflectedMethod + _Jv_JNI_FromReflectedField, // FromReflectedField + _Jv_JNI_ToReflectedMethod, // ToReflectedMethod + _Jv_JNI_GetSuperclass, // GetSuperclass + _Jv_JNI_IsAssignableFrom, // IsAssignableFrom + _Jv_JNI_ToReflectedField, // ToReflectedField + _Jv_JNI_Throw, // Throw + _Jv_JNI_ThrowNew, // ThrowNew + _Jv_JNI_ExceptionOccurred, // ExceptionOccurred + _Jv_JNI_ExceptionDescribe, // ExceptionDescribe + _Jv_JNI_ExceptionClear, // ExceptionClear + _Jv_JNI_FatalError, // FatalError + + _Jv_JNI_PushLocalFrame, // PushLocalFrame + _Jv_JNI_PopLocalFrame, // PopLocalFrame + _Jv_JNI_NewGlobalRef, // NewGlobalRef + _Jv_JNI_DeleteGlobalRef, // DeleteGlobalRef + _Jv_JNI_DeleteLocalRef, // DeleteLocalRef + + _Jv_JNI_IsSameObject, // IsSameObject + + _Jv_JNI_NewLocalRef, // NewLocalRef + _Jv_JNI_EnsureLocalCapacity, // EnsureLocalCapacity + + _Jv_JNI_AllocObject, // AllocObject + _Jv_JNI_NewObject, // NewObject + _Jv_JNI_NewObjectV, // NewObjectV + _Jv_JNI_NewObjectA, // NewObjectA + _Jv_JNI_GetObjectClass, // GetObjectClass + _Jv_JNI_IsInstanceOf, // IsInstanceOf + _Jv_JNI_GetAnyMethodID, // GetMethodID + + _Jv_JNI_CallMethod, // CallObjectMethod + _Jv_JNI_CallMethodV, // CallObjectMethodV + _Jv_JNI_CallMethodA, // CallObjectMethodA + _Jv_JNI_CallMethod, // CallBooleanMethod + _Jv_JNI_CallMethodV, // CallBooleanMethodV + _Jv_JNI_CallMethodA, // CallBooleanMethodA + _Jv_JNI_CallMethod, // CallByteMethod + _Jv_JNI_CallMethodV, // CallByteMethodV + _Jv_JNI_CallMethodA, // CallByteMethodA + _Jv_JNI_CallMethod, // CallCharMethod + _Jv_JNI_CallMethodV, // CallCharMethodV + _Jv_JNI_CallMethodA, // CallCharMethodA + _Jv_JNI_CallMethod, // CallShortMethod + _Jv_JNI_CallMethodV, // CallShortMethodV + _Jv_JNI_CallMethodA, // CallShortMethodA + _Jv_JNI_CallMethod, // CallIntMethod + _Jv_JNI_CallMethodV, // CallIntMethodV + _Jv_JNI_CallMethodA, // CallIntMethodA + _Jv_JNI_CallMethod, // CallLongMethod + _Jv_JNI_CallMethodV, // CallLongMethodV + _Jv_JNI_CallMethodA, // CallLongMethodA + _Jv_JNI_CallMethod, // CallFloatMethod + _Jv_JNI_CallMethodV, // CallFloatMethodV + _Jv_JNI_CallMethodA, // CallFloatMethodA + _Jv_JNI_CallMethod, // CallDoubleMethod + _Jv_JNI_CallMethodV, // CallDoubleMethodV + _Jv_JNI_CallMethodA, // CallDoubleMethodA + _Jv_JNI_CallVoidMethod, // CallVoidMethod + _Jv_JNI_CallVoidMethodV, // CallVoidMethodV + _Jv_JNI_CallVoidMethodA, // CallVoidMethodA // Nonvirtual method invocation functions follow. - _Jv_JNI_CallAnyMethod, - _Jv_JNI_CallAnyMethodV, - _Jv_JNI_CallAnyMethodA, - _Jv_JNI_CallAnyMethod, - _Jv_JNI_CallAnyMethodV, - _Jv_JNI_CallAnyMethodA, - _Jv_JNI_CallAnyMethod, - _Jv_JNI_CallAnyMethodV, - _Jv_JNI_CallAnyMethodA, - _Jv_JNI_CallAnyMethod, - _Jv_JNI_CallAnyMethodV, - _Jv_JNI_CallAnyMethodA, - _Jv_JNI_CallAnyMethod, - _Jv_JNI_CallAnyMethodV, - _Jv_JNI_CallAnyMethodA, - _Jv_JNI_CallAnyMethod, - _Jv_JNI_CallAnyMethodV, - _Jv_JNI_CallAnyMethodA, - _Jv_JNI_CallAnyMethod, - _Jv_JNI_CallAnyMethodV, - _Jv_JNI_CallAnyMethodA, - _Jv_JNI_CallAnyMethod, - _Jv_JNI_CallAnyMethodV, - _Jv_JNI_CallAnyMethodA, - _Jv_JNI_CallAnyMethod, - _Jv_JNI_CallAnyMethodV, - _Jv_JNI_CallAnyMethodA, - _Jv_JNI_CallAnyVoidMethod, - _Jv_JNI_CallAnyVoidMethodV, - _Jv_JNI_CallAnyVoidMethodA, - - _Jv_JNI_GetAnyFieldID, - _Jv_JNI_GetField, - _Jv_JNI_GetField, - _Jv_JNI_GetField, - _Jv_JNI_GetField, - _Jv_JNI_GetField, - _Jv_JNI_GetField, - _Jv_JNI_GetField, - _Jv_JNI_GetField, - _Jv_JNI_GetField, - _Jv_JNI_SetField, - _Jv_JNI_SetField, - _Jv_JNI_SetField, - _Jv_JNI_SetField, - _Jv_JNI_SetField, - _Jv_JNI_SetField, - _Jv_JNI_SetField, - _Jv_JNI_SetField, - _Jv_JNI_SetField, - _Jv_JNI_GetAnyMethodID, - - _Jv_JNI_CallStaticMethod, - _Jv_JNI_CallStaticMethodV, - _Jv_JNI_CallStaticMethodA, - _Jv_JNI_CallStaticMethod, - _Jv_JNI_CallStaticMethodV, - _Jv_JNI_CallStaticMethodA, - _Jv_JNI_CallStaticMethod, - _Jv_JNI_CallStaticMethodV, - _Jv_JNI_CallStaticMethodA, - _Jv_JNI_CallStaticMethod, - _Jv_JNI_CallStaticMethodV, - _Jv_JNI_CallStaticMethodA, - _Jv_JNI_CallStaticMethod, - _Jv_JNI_CallStaticMethodV, - _Jv_JNI_CallStaticMethodA, - _Jv_JNI_CallStaticMethod, - _Jv_JNI_CallStaticMethodV, - _Jv_JNI_CallStaticMethodA, - _Jv_JNI_CallStaticMethod, - _Jv_JNI_CallStaticMethodV, - _Jv_JNI_CallStaticMethodA, - _Jv_JNI_CallStaticMethod, - _Jv_JNI_CallStaticMethodV, - _Jv_JNI_CallStaticMethodA, - _Jv_JNI_CallStaticMethod, - _Jv_JNI_CallStaticMethodV, - _Jv_JNI_CallStaticMethodA, - _Jv_JNI_CallStaticVoidMethod, - _Jv_JNI_CallStaticVoidMethodV, - _Jv_JNI_CallStaticVoidMethodA, - - _Jv_JNI_GetAnyFieldID, - _Jv_JNI_GetStaticField, - _Jv_JNI_GetStaticField, - _Jv_JNI_GetStaticField, - _Jv_JNI_GetStaticField, - _Jv_JNI_GetStaticField, - _Jv_JNI_GetStaticField, - _Jv_JNI_GetStaticField, - _Jv_JNI_GetStaticField, - _Jv_JNI_GetStaticField, - _Jv_JNI_SetStaticField, - _Jv_JNI_SetStaticField, - _Jv_JNI_SetStaticField, - _Jv_JNI_SetStaticField, - _Jv_JNI_SetStaticField, - _Jv_JNI_SetStaticField, - _Jv_JNI_SetStaticField, - _Jv_JNI_SetStaticField, - _Jv_JNI_SetStaticField, - _Jv_JNI_NewString, - _Jv_JNI_GetStringLength, - _Jv_JNI_GetStringChars, - _Jv_JNI_ReleaseStringChars, - _Jv_JNI_NewStringUTF, - _Jv_JNI_GetStringUTFLength, - _Jv_JNI_GetStringUTFChars, - _Jv_JNI_ReleaseStringUTFChars, - _Jv_JNI_GetArrayLength, - _Jv_JNI_NewObjectArray, - _Jv_JNI_GetObjectArrayElement, - _Jv_JNI_SetObjectArrayElement, + _Jv_JNI_CallAnyMethod, // CallNonvirtualObjectMethod + _Jv_JNI_CallAnyMethodV, // CallNonvirtualObjectMethodV + _Jv_JNI_CallAnyMethodA, // CallNonvirtualObjectMethodA + _Jv_JNI_CallAnyMethod, // CallNonvirtualBooleanMethod + _Jv_JNI_CallAnyMethodV, // CallNonvirtualBooleanMethodV + _Jv_JNI_CallAnyMethodA, // CallNonvirtualBooleanMethodA + _Jv_JNI_CallAnyMethod, // CallNonvirtualByteMethod + _Jv_JNI_CallAnyMethodV, // CallNonvirtualByteMethodV + _Jv_JNI_CallAnyMethodA, // CallNonvirtualByteMethodA + _Jv_JNI_CallAnyMethod, // CallNonvirtualCharMethod + _Jv_JNI_CallAnyMethodV, // CallNonvirtualCharMethodV + _Jv_JNI_CallAnyMethodA, // CallNonvirtualCharMethodA + _Jv_JNI_CallAnyMethod, // CallNonvirtualShortMethod + _Jv_JNI_CallAnyMethodV, // CallNonvirtualShortMethodV + _Jv_JNI_CallAnyMethodA, // CallNonvirtualShortMethodA + _Jv_JNI_CallAnyMethod, // CallNonvirtualIntMethod + _Jv_JNI_CallAnyMethodV, // CallNonvirtualIntMethodV + _Jv_JNI_CallAnyMethodA, // CallNonvirtualIntMethodA + _Jv_JNI_CallAnyMethod, // CallNonvirtualLongMethod + _Jv_JNI_CallAnyMethodV, // CallNonvirtualLongMethodV + _Jv_JNI_CallAnyMethodA, // CallNonvirtualLongMethodA + _Jv_JNI_CallAnyMethod, // CallNonvirtualFloatMethod + _Jv_JNI_CallAnyMethodV, // CallNonvirtualFloatMethodV + _Jv_JNI_CallAnyMethodA, // CallNonvirtualFloatMethodA + _Jv_JNI_CallAnyMethod, // CallNonvirtualDoubleMethod + _Jv_JNI_CallAnyMethodV, // CallNonvirtualDoubleMethodV + _Jv_JNI_CallAnyMethodA, // CallNonvirtualDoubleMethodA + _Jv_JNI_CallAnyVoidMethod, // CallNonvirtualVoidMethod + _Jv_JNI_CallAnyVoidMethodV, // CallNonvirtualVoidMethodV + _Jv_JNI_CallAnyVoidMethodA, // CallNonvirtualVoidMethodA + + _Jv_JNI_GetAnyFieldID, // GetFieldID + _Jv_JNI_GetField, // GetObjectField + _Jv_JNI_GetField, // GetBooleanField + _Jv_JNI_GetField, // GetByteField + _Jv_JNI_GetField, // GetCharField + _Jv_JNI_GetField, // GetShortField + _Jv_JNI_GetField, // GetIntField + _Jv_JNI_GetField, // GetLongField + _Jv_JNI_GetField, // GetFloatField + _Jv_JNI_GetField, // GetDoubleField + _Jv_JNI_SetField, // SetObjectField + _Jv_JNI_SetField, // SetBooleanField + _Jv_JNI_SetField, // SetByteField + _Jv_JNI_SetField, // SetCharField + _Jv_JNI_SetField, // SetShortField + _Jv_JNI_SetField, // SetIntField + _Jv_JNI_SetField, // SetLongField + _Jv_JNI_SetField, // SetFloatField + _Jv_JNI_SetField, // SetDoubleField + _Jv_JNI_GetAnyMethodID, // GetStaticMethodID + + _Jv_JNI_CallStaticMethod, // CallStaticObjectMethod + _Jv_JNI_CallStaticMethodV, // CallStaticObjectMethodV + _Jv_JNI_CallStaticMethodA, // CallStaticObjectMethodA + _Jv_JNI_CallStaticMethod, // CallStaticBooleanMethod + _Jv_JNI_CallStaticMethodV, // CallStaticBooleanMethodV + _Jv_JNI_CallStaticMethodA, // CallStaticBooleanMethodA + _Jv_JNI_CallStaticMethod, // CallStaticByteMethod + _Jv_JNI_CallStaticMethodV, // CallStaticByteMethodV + _Jv_JNI_CallStaticMethodA, // CallStaticByteMethodA + _Jv_JNI_CallStaticMethod, // CallStaticCharMethod + _Jv_JNI_CallStaticMethodV, // CallStaticCharMethodV + _Jv_JNI_CallStaticMethodA, // CallStaticCharMethodA + _Jv_JNI_CallStaticMethod, // CallStaticShortMethod + _Jv_JNI_CallStaticMethodV, // CallStaticShortMethodV + _Jv_JNI_CallStaticMethodA, // CallStaticShortMethodA + _Jv_JNI_CallStaticMethod, // CallStaticIntMethod + _Jv_JNI_CallStaticMethodV, // CallStaticIntMethodV + _Jv_JNI_CallStaticMethodA, // CallStaticIntMethodA + _Jv_JNI_CallStaticMethod, // CallStaticLongMethod + _Jv_JNI_CallStaticMethodV, // CallStaticLongMethodV + _Jv_JNI_CallStaticMethodA, // CallStaticLongMethodA + _Jv_JNI_CallStaticMethod, // CallStaticFloatMethod + _Jv_JNI_CallStaticMethodV, // CallStaticFloatMethodV + _Jv_JNI_CallStaticMethodA, // CallStaticFloatMethodA + _Jv_JNI_CallStaticMethod, // CallStaticDoubleMethod + _Jv_JNI_CallStaticMethodV, // CallStaticDoubleMethodV + _Jv_JNI_CallStaticMethodA, // CallStaticDoubleMethodA + _Jv_JNI_CallStaticVoidMethod, // CallStaticVoidMethod + _Jv_JNI_CallStaticVoidMethodV, // CallStaticVoidMethodV + _Jv_JNI_CallStaticVoidMethodA, // CallStaticVoidMethodA + + _Jv_JNI_GetAnyFieldID, // GetStaticFieldID + _Jv_JNI_GetStaticField, // GetStaticObjectField + _Jv_JNI_GetStaticField, // GetStaticBooleanField + _Jv_JNI_GetStaticField, // GetStaticByteField + _Jv_JNI_GetStaticField, // GetStaticCharField + _Jv_JNI_GetStaticField, // GetStaticShortField + _Jv_JNI_GetStaticField, // GetStaticIntField + _Jv_JNI_GetStaticField, // GetStaticLongField + _Jv_JNI_GetStaticField, // GetStaticFloatField + _Jv_JNI_GetStaticField, // GetStaticDoubleField + _Jv_JNI_SetStaticField, // SetStaticObjectField + _Jv_JNI_SetStaticField, // SetStaticBooleanField + _Jv_JNI_SetStaticField, // SetStaticByteField + _Jv_JNI_SetStaticField, // SetStaticCharField + _Jv_JNI_SetStaticField, // SetStaticShortField + _Jv_JNI_SetStaticField, // SetStaticIntField + _Jv_JNI_SetStaticField, // SetStaticLongField + _Jv_JNI_SetStaticField, // SetStaticFloatField + _Jv_JNI_SetStaticField, // SetStaticDoubleField + _Jv_JNI_NewString, // NewString + _Jv_JNI_GetStringLength, // GetStringLength + _Jv_JNI_GetStringChars, // GetStringChars + _Jv_JNI_ReleaseStringChars, // ReleaseStringChars + _Jv_JNI_NewStringUTF, // NewStringUTF + _Jv_JNI_GetStringUTFLength, // GetStringUTFLength + _Jv_JNI_GetStringUTFChars, // GetStringUTFChars + _Jv_JNI_ReleaseStringUTFChars, // ReleaseStringUTFChars + _Jv_JNI_GetArrayLength, // GetArrayLength + _Jv_JNI_NewObjectArray, // NewObjectArray + _Jv_JNI_GetObjectArrayElement, // GetObjectArrayElement + _Jv_JNI_SetObjectArrayElement, // SetObjectArrayElement _Jv_JNI_NewPrimitiveArray, - _Jv_JNI_NewPrimitiveArray, - _Jv_JNI_NewPrimitiveArray, - _Jv_JNI_NewPrimitiveArray, - _Jv_JNI_NewPrimitiveArray, - _Jv_JNI_NewPrimitiveArray, - _Jv_JNI_NewPrimitiveArray, - _Jv_JNI_NewPrimitiveArray, - _Jv_JNI_GetPrimitiveArrayElements, - _Jv_JNI_GetPrimitiveArrayElements, - _Jv_JNI_GetPrimitiveArrayElements, - _Jv_JNI_GetPrimitiveArrayElements, - _Jv_JNI_GetPrimitiveArrayElements, - _Jv_JNI_GetPrimitiveArrayElements, - _Jv_JNI_GetPrimitiveArrayElements, - _Jv_JNI_GetPrimitiveArrayElements, - _Jv_JNI_ReleasePrimitiveArrayElements, - _Jv_JNI_ReleasePrimitiveArrayElements, - _Jv_JNI_ReleasePrimitiveArrayElements, - _Jv_JNI_ReleasePrimitiveArrayElements, - _Jv_JNI_ReleasePrimitiveArrayElements, - _Jv_JNI_ReleasePrimitiveArrayElements, - _Jv_JNI_ReleasePrimitiveArrayElements, - _Jv_JNI_ReleasePrimitiveArrayElements, - _Jv_JNI_GetPrimitiveArrayRegion, - _Jv_JNI_GetPrimitiveArrayRegion, - _Jv_JNI_GetPrimitiveArrayRegion, - _Jv_JNI_GetPrimitiveArrayRegion, - _Jv_JNI_GetPrimitiveArrayRegion, - _Jv_JNI_GetPrimitiveArrayRegion, - _Jv_JNI_GetPrimitiveArrayRegion, - _Jv_JNI_GetPrimitiveArrayRegion, - _Jv_JNI_SetPrimitiveArrayRegion, - _Jv_JNI_SetPrimitiveArrayRegion, - _Jv_JNI_SetPrimitiveArrayRegion, - _Jv_JNI_SetPrimitiveArrayRegion, - _Jv_JNI_SetPrimitiveArrayRegion, - _Jv_JNI_SetPrimitiveArrayRegion, - _Jv_JNI_SetPrimitiveArrayRegion, - _Jv_JNI_SetPrimitiveArrayRegion, - _Jv_JNI_RegisterNatives, - _Jv_JNI_UnregisterNatives, - _Jv_JNI_MonitorEnter, - _Jv_JNI_MonitorExit, - _Jv_JNI_GetJavaVM, - - _Jv_JNI_GetStringRegion, - _Jv_JNI_GetStringUTFRegion, - _Jv_JNI_GetPrimitiveArrayCritical, - _Jv_JNI_ReleasePrimitiveArrayCritical, - _Jv_JNI_GetStringCritical, - _Jv_JNI_ReleaseStringCritical, - - NOT_IMPL /* newweakglobalref */, - NOT_IMPL /* deleteweakglobalref */, - - _Jv_JNI_ExceptionCheck + // NewBooleanArray + _Jv_JNI_NewPrimitiveArray, // NewByteArray + _Jv_JNI_NewPrimitiveArray, // NewCharArray + _Jv_JNI_NewPrimitiveArray, // NewShortArray + _Jv_JNI_NewPrimitiveArray, // NewIntArray + _Jv_JNI_NewPrimitiveArray, // NewLongArray + _Jv_JNI_NewPrimitiveArray, // NewFloatArray + _Jv_JNI_NewPrimitiveArray, // NewDoubleArray + _Jv_JNI_GetPrimitiveArrayElements, + // GetBooleanArrayElements + _Jv_JNI_GetPrimitiveArrayElements, + // GetByteArrayElements + _Jv_JNI_GetPrimitiveArrayElements, + // GetCharArrayElements + _Jv_JNI_GetPrimitiveArrayElements, + // GetShortArrayElements + _Jv_JNI_GetPrimitiveArrayElements, + // GetIntArrayElements + _Jv_JNI_GetPrimitiveArrayElements, + // GetLongArrayElements + _Jv_JNI_GetPrimitiveArrayElements, + // GetFloatArrayElements + _Jv_JNI_GetPrimitiveArrayElements, + // GetDoubleArrayElements + _Jv_JNI_ReleasePrimitiveArrayElements, + // ReleaseBooleanArrayElements + _Jv_JNI_ReleasePrimitiveArrayElements, + // ReleaseByteArrayElements + _Jv_JNI_ReleasePrimitiveArrayElements, + // ReleaseCharArrayElements + _Jv_JNI_ReleasePrimitiveArrayElements, + // ReleaseShortArrayElements + _Jv_JNI_ReleasePrimitiveArrayElements, + // ReleaseIntArrayElements + _Jv_JNI_ReleasePrimitiveArrayElements, + // ReleaseLongArrayElements + _Jv_JNI_ReleasePrimitiveArrayElements, + // ReleaseFloatArrayElements + _Jv_JNI_ReleasePrimitiveArrayElements, + // ReleaseDoubleArrayElements + _Jv_JNI_GetPrimitiveArrayRegion, + // GetBooleanArrayRegion + _Jv_JNI_GetPrimitiveArrayRegion, + // GetByteArrayRegion + _Jv_JNI_GetPrimitiveArrayRegion, + // GetCharArrayRegion + _Jv_JNI_GetPrimitiveArrayRegion, + // GetShortArrayRegion + _Jv_JNI_GetPrimitiveArrayRegion, + // GetIntArrayRegion + _Jv_JNI_GetPrimitiveArrayRegion, + // GetLongArrayRegion + _Jv_JNI_GetPrimitiveArrayRegion, + // GetFloatArrayRegion + _Jv_JNI_GetPrimitiveArrayRegion, + // GetDoubleArrayRegion + _Jv_JNI_SetPrimitiveArrayRegion, + // SetBooleanArrayRegion + _Jv_JNI_SetPrimitiveArrayRegion, + // SetByteArrayRegion + _Jv_JNI_SetPrimitiveArrayRegion, + // SetCharArrayRegion + _Jv_JNI_SetPrimitiveArrayRegion, + // SetShortArrayRegion + _Jv_JNI_SetPrimitiveArrayRegion, + // SetIntArrayRegion + _Jv_JNI_SetPrimitiveArrayRegion, + // SetLongArrayRegion + _Jv_JNI_SetPrimitiveArrayRegion, + // SetFloatArrayRegion + _Jv_JNI_SetPrimitiveArrayRegion, + // SetDoubleArrayRegion + _Jv_JNI_RegisterNatives, // RegisterNatives + _Jv_JNI_UnregisterNatives, // UnregisterNatives + _Jv_JNI_MonitorEnter, // MonitorEnter + _Jv_JNI_MonitorExit, // MonitorExit + _Jv_JNI_GetJavaVM, // GetJavaVM + + _Jv_JNI_GetStringRegion, // GetStringRegion + _Jv_JNI_GetStringUTFRegion, // GetStringUTFRegion + _Jv_JNI_GetPrimitiveArrayCritical, // GetPrimitiveArrayCritical + _Jv_JNI_ReleasePrimitiveArrayCritical, // ReleasePrimitiveArrayCritical + _Jv_JNI_GetStringCritical, // GetStringCritical + _Jv_JNI_ReleaseStringCritical, // ReleaseStringCritical + + _Jv_JNI_NewWeakGlobalRef, // NewWeakGlobalRef + _Jv_JNI_DeleteWeakGlobalRef, // DeleteWeakGlobalRef + + _Jv_JNI_ExceptionCheck, // ExceptionCheck + + _Jv_JNI_NewDirectByteBuffer, // NewDirectByteBuffer + _Jv_JNI_GetDirectBufferAddress, // GetDirectBufferAddress + _Jv_JNI_GetDirectBufferCapacity, // GetDirectBufferCapacity + + _Jv_JNI_GetObjectRefType // GetObjectRefType }; -struct JNIInvokeInterface _Jv_JNI_InvokeFunctions = +struct JNIInvokeInterface_ _Jv_JNI_InvokeFunctions = { RESERVED, RESERVED, @@ -2330,5 +2899,6 @@ struct JNIInvokeInterface _Jv_JNI_InvokeFunctions = _Jv_JNI_DestroyJavaVM, _Jv_JNI_AttachCurrentThread, _Jv_JNI_DetachCurrentThread, - _Jv_JNI_GetEnv + _Jv_JNI_GetEnv, + _Jv_JNI_AttachCurrentThreadAsDaemon };