X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=libjava%2Fjni.cc;h=62a96ce9c6f69eff90b1f469476c6f50eaeec9bd;hb=f064ebd17debbb055d5cb445176fea22ea1eedbb;hp=6beb6f7f8a49474dd9d8af132fa56b2c854fdfa9;hpb=bf1967d63c238862df52d7823dbfd4abc9d5c647;p=pf3gnuchains%2Fgcc-fork.git diff --git a/libjava/jni.cc b/libjava/jni.cc index 6beb6f7f8a4..62a96ce9c6f 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 Red Hat, Inc. +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation This file is part of libgcj. @@ -10,23 +11,25 @@ details. */ #include +#include #include #include -// Define this before including jni.h. -#define __GCJ_JNI_IMPL__ - #include #include #include #include +#ifdef ENABLE_JVMPI +#include +#endif #include #include #include #include #include -#include +#include +#include #include #include #include @@ -34,28 +37,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. @@ -73,17 +72,27 @@ 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 +// 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 true if this frame object represents a pushed frame (eg // from PushLocalFrame). - int marker : 1; + int marker; + + // Flag to indicate some locals were allocated. + int allocated_p; // Number of elements in frame. - int size : 31; + int size; // Next frame in chain. _Jv_JNI_LocalFrame *next; @@ -92,35 +101,93 @@ 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; +#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) { - 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; + _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) +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) +unmark_for_gc (jobject obj, java::util::IdentityHashMap *ref_table) { JvSynchronize sync (ref_table); @@ -128,70 +195,111 @@ 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 + // 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 +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); + 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); + 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; } } // Don't go past a marked frame. - JvAssert (! frame->marker); + JvAssert (frame->marker == MARK_NONE); } 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 // 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 - = (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame) - + size * sizeof (jobject)); - if (frame == NULL) + _Jv_JNI_LocalFrame *frame; + try + { + frame = (_Jv_JNI_LocalFrame *) _Jv_Malloc (sizeof (_Jv_JNI_LocalFrame) + + size * sizeof (jobject)); + } + catch (jthrowable t) { - // FIXME: exception processing. - env->ex = new java::lang::OutOfMemoryError; + env->ex = t; return JNI_ERR; } - frame->marker = true; + frame->marker = MARK_NONE; frame->size = size; + frame->allocated_p = 0; memset (&frame->vec[0], 0, size * sizeof (jobject)); frame->next = env->locals; env->locals = frame; @@ -199,7 +307,7 @@ _Jv_JNI_EnsureLocalCapacity (JNIEnv *env, jint size) return 0; } -static jint +static jint JNICALL _Jv_JNI_PushLocalFrame (JNIEnv *env, jint size) { jint r = _Jv_JNI_EnsureLocalCapacity (env, size); @@ -207,27 +315,38 @@ _Jv_JNI_PushLocalFrame (JNIEnv *env, jint size) return r; // The new frame is on top. - env->locals->marker = true; + env->locals->marker = MARK_USER; 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 = 1; + 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) @@ -237,34 +356,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 = 1; } - mark_for_gc (obj); + mark_for_gc (obj, local_ref_table); return obj; } -static jobject -_Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result) +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; + 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 = 0; + rf = NULL; break; } @@ -272,9 +394,69 @@ _Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result) 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; + + if (__builtin_expect (env->ex != NULL, false)) + { + jthrowable t = env->ex; + env->ex = NULL; + throw t; + } +} + +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. @@ -285,38 +467,53 @@ 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) { - jbyteArray bytes = JvNewByteArray (bufLen); - jbyte *elts = elements (bytes); - memcpy (elts, buf, bufLen * sizeof (jbyte)); + try + { + loader = unwrap (loader); + + jstring sname = JvNewStringUTF (name); + jbyteArray bytes = JvNewByteArray (bufLen); - java::lang::ClassLoader *l - = reinterpret_cast (loader); + jbyte *elts = elements (bytes); + memcpy (elts, buf, bufLen * sizeof (jbyte)); - // FIXME: exception processing. - jclass result = l->defineClass (bytes, 0, bufLen); - return (jclass) wrap_value (env, result); + 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 +static jclass JNICALL _Jv_JNI_FindClass (JNIEnv *env, const char *name) { // FIXME: assume that NAME isn't too long. @@ -324,98 +521,120 @@ _Jv_JNI_FindClass (JNIEnv *env, const char *name) char s[len + 1]; for (int i = 0; i <= len; ++i) s[i] = (name[i] == '/') ? '.' : name[i]; - jstring n = JvNewStringUTF (s); - java::lang::ClassLoader *loader; - if (env->klass == NULL) + jclass r = NULL; + try { - // FIXME: should use getBaseClassLoader, but we don't have that - // yet. - loader = java::lang::ClassLoader::getSystemClassLoader (); - } - else - loader = env->klass->getClassLoader (); + // This might throw an out of memory exception. + jstring n = JvNewStringUTF (s); - // FIXME: exception processing. - jclass r = loader->findClass (n); + java::lang::ClassLoader *loader = NULL; + if (env->klass != NULL) + loader = env->klass->getClassLoaderInternal (); + + if (loader == NULL) + { + // FIXME: should use getBaseClassLoader, but we don't have that + // yet. + loader = java::lang::ClassLoader::getSystemClassLoader (); + } + + r = loader->loadClass (n); + } + catch (jthrowable t) + { + env->ex = t; + } 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)); - JArray *argtypes - = (JArray *) JvNewObjectArray (1, &ClassClass, NULL); + int r = JNI_OK; + try + { + JArray *argtypes + = (JArray *) JvNewObjectArray (1, &java::lang::Class::class$, + NULL); - jclass *elts = elements (argtypes); - elts[0] = &StringClass; + jclass *elts = elements (argtypes); + elts[0] = &java::lang::String::class$; - // FIXME: exception processing. - Constructor *cons = clazz->getConstructor (argtypes); + Constructor *cons = clazz->getConstructor (argtypes); - jobjectArray values = JvNewObjectArray (1, &StringClass, NULL); - jobject *velts = elements (values); - velts[0] = JvNewStringUTF (message); + jobjectArray values = JvNewObjectArray (1, &java::lang::String::class$, + NULL); + jobject *velts = elements (values); + velts[0] = JvNewStringUTF (message); - // FIXME: exception processing. - jobject obj = cons->newInstance (values); + jobject obj = cons->newInstance (values); - env->ex = reinterpret_cast (obj); - return 0; + env->ex = reinterpret_cast (obj); + } + catch (jthrowable t) + { + env->ex = t; + r = JNI_ERR; + } + + 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); @@ -423,42 +642,47 @@ _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; using namespace java::lang::reflect; - JvAssert (clazz && ! clazz->isArray ()); - if (clazz->isInterface() || Modifier::isAbstract(clazz->getModifiers())) - env->ex = new java::lang::InstantiationException (); - else + 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) { - // FIXME: exception processing. - // FIXME: will this work for String? - obj = JvAllocObject (clazz); + env->ex = t; } 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)); } @@ -468,40 +692,57 @@ _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) { - // FIXME: exception processing. - _Jv_InitClass (clazz); + 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); + _Jv_Utf8Const *name_u = _Jv_makeUtf8Const ((char *) name, -1); - JvAssert (! clazz->isPrimitive()); + // 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); - using namespace java::lang::reflect; + JvAssert (! clazz->isPrimitive()); - while (clazz != NULL) - { - jint count = JvNumMethods (clazz); - jmethodID meth = JvGetFirstMethod (clazz); + using namespace java::lang::reflect; - for (jint i = 0; i < count; ++i) + while (clazz != NULL) { - 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; + jint count = JvNumMethods (clazz); + jmethodID meth = JvGetFirstMethod (clazz); - meth = meth->getNextMethod(); + 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 (); } - clazz = clazz->getSuperclass (); + java::lang::StringBuffer *name_sig = + new java::lang::StringBuffer (JvNewStringUTF (name)); + name_sig->append ((jchar) ' ')->append (JvNewStringUTF (s)); + env->ex = new java::lang::NoSuchMethodError (name_sig->toString ()); + } + catch (jthrowable t) + { + env->ex = t; } - env->ex = new java::lang::NoSuchMethodError (); return NULL; } @@ -514,26 +755,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)); } } } @@ -541,39 +791,49 @@ 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); jclass return_type; JArray *arg_types; - // FIXME: exception processing. - _Jv_GetTypesFromSignature (id, decl_class, - &arg_types, &return_type); - jvalue args[arg_types->length]; - array_from_valist (args, arg_types, vargs); + try + { + _Jv_GetTypesFromSignature (id, decl_class, + &arg_types, &return_type); + + jvalue args[arg_types->length]; + array_from_valist (args, arg_types, vargs); - jvalue result; - jthrowable ex = _Jv_CallAnyMethodA (obj, return_type, id, - style == constructor, - arg_types, args, &result); + // For constructors we need to pass the Class we are instantiating. + if (style == constructor) + return_type = klass; - if (ex != NULL) - env->ex = ex; + 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; + } - // We cheat a little here. FIXME. - return wrap_value (env, * (T *) &result); + return wrap_value (env, (T) 0); } template -static T +static T JNICALL _Jv_JNI_CallAnyMethod (JNIEnv *env, jobject obj, jclass klass, jmethodID method, ...) { @@ -588,64 +848,92 @@ _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) { - 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); jclass return_type; JArray *arg_types; - // FIXME: exception processing. - _Jv_GetTypesFromSignature (id, decl_class, - &arg_types, &return_type); + 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; - jthrowable ex = _Jv_CallAnyMethodA (obj, return_type, id, - style == constructor, - arg_types, args, &result); + jvalue result; + _Jv_CallAnyMethodA (obj, return_type, id, + style == constructor, + style == normal, + arg_types, arg_copy, &result); - if (ex != NULL) - env->ex = ex; + return wrap_value (env, extract_from_jvalue(result)); + } + catch (jthrowable t) + { + env->ex = t; + } - // We cheat a little here. FIXME. - return wrap_value (env, * (T *) &result); + return wrap_value (env, (T) 0); } 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); jclass return_type; JArray *arg_types; - // FIXME: exception processing. - _Jv_GetTypesFromSignature (id, decl_class, - &arg_types, &return_type); + try + { + _Jv_GetTypesFromSignature (id, decl_class, + &arg_types, &return_type); - jvalue args[arg_types->length]; - array_from_valist (args, arg_types, vargs); + jvalue args[arg_types->length]; + array_from_valist (args, arg_types, vargs); - jthrowable ex = _Jv_CallAnyMethodA (obj, return_type, id, - style == constructor, - arg_types, args, NULL); + // For constructors we need to pass the Class we are instantiating. + if (style == constructor) + return_type = klass; - if (ex != NULL) - env->ex = ex; + _Jv_CallAnyMethodA (obj, return_type, id, + style == constructor, + style == normal, + arg_types, args, NULL); + } + catch (jthrowable t) + { + env->ex = t; + } } template -static void +static void JNICALL _Jv_JNI_CallAnyVoidMethod (JNIEnv *env, jobject obj, jclass klass, jmethodID method, ...) { @@ -657,35 +945,48 @@ _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) { - if (style == normal) - id = _Jv_LookupDeclaredMethod (obj->getClass (), id->name, id->signature); - jclass decl_class = klass ? klass : obj->getClass (); JvAssert (decl_class != NULL); jclass return_type; JArray *arg_types; - // FIXME: exception processing. - _Jv_GetTypesFromSignature (id, decl_class, - &arg_types, &return_type); + try + { + _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) + { + env->ex = t; + } } // 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); } @@ -693,7 +994,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; @@ -709,19 +1010,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, 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; @@ -731,8 +1034,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, jvalue *args) { _Jv_JNI_CallAnyVoidMethodA (env, obj, NULL, id, args); } @@ -740,22 +1044,29 @@ _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 (java::lang::Class::class$.isInstance (unwrap (klass))); + return _Jv_JNI_CallAnyMethodV (env, NULL, klass, id, args); } // 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 (java::lang::Class::class$.isInstance (unwrap (klass))); + va_start (args, id); result = _Jv_JNI_CallAnyMethodV (env, NULL, klass, id, args); @@ -767,22 +1078,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) { + JvAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC)); + 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; @@ -791,30 +1106,37 @@ _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, 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, "") - && ! strcmp (id->signature->data, "()V")); + 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, "") - && ! strcmp (id->signature->data, "()V")); + 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; jobject result; @@ -827,13 +1149,17 @@ _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) { JvAssert (klass && ! klass->isArray ()); - JvAssert (! strcmp (id->name->data, "") - && ! strcmp (id->signature->data, "()V")); + 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, id, args); } @@ -841,76 +1167,90 @@ _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) { - // FIXME: exception processing. - _Jv_InitClass (clazz); + try + { + clazz = unwrap (clazz); - _Jv_Utf8Const *a_name = _Jv_makeUtf8Const ((char *) name, -1); + _Jv_InitClass (clazz); - 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); - } + _Jv_Utf8Const *a_name = _Jv_makeUtf8Const ((char *) name, -1); - // 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) - { - jint count = (is_static - ? JvNumStaticFields (clazz) - : JvNumInstanceFields (clazz)); - jfieldID field = (is_static - ? JvGetFirstStaticField (clazz) - : JvGetFirstInstanceField (clazz)); - for (jint i = 0; i < count; ++i) + while (clazz != NULL) { - // The field is resolved as a side effect of class - // initialization. - JvAssert (field->isResolved ()); + // 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)); + jfieldID field = (is_static + ? JvGetFirstStaticField (clazz) + : JvGetFirstInstanceField (clazz)); + for (jint i = 0; i < count; ++i) + { + _Jv_Utf8Const *f_name = field->getNameUtf8Const(clazz); - _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; - if (_Jv_equalUtf8Consts (f_name, a_name) - && field->getClass() == field_class) - return field; + field = field->getNextField (); + } - field = field->getNextField (); + clazz = clazz->getSuperclass (); } - clazz = clazz->getSuperclass (); + env->ex = new java::lang::NoSuchFieldError (); + } + catch (jthrowable t) + { + env->ex = t; } - - env->ex = new java::lang::NoSuchFieldError (); return NULL; } template -static T +static T JNICALL _Jv_JNI_GetStaticField (JNIEnv *env, jclass, jfieldID field) { T *ptr = (T *) field->u.addr; @@ -918,192 +1258,291 @@ _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) { - // FIXME: exception processing. - jstring r = _Jv_NewString (unichars, len); - return (jstring) wrap_value (env, r); + try + { + jstring r = _Jv_NewString (unichars, len); + return (jstring) wrap_value (env, r); + } + catch (jthrowable t) + { + env->ex = t; + return NULL; + } } -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) { - // FIXME: exception processing. - jstring result = JvNewStringUTF (bytes); - return (jstring) wrap_value (env, result); + try + { + jstring result = JvNewStringUTF (bytes); + return (jstring) wrap_value (env, result); + } + catch (jthrowable t) + { + env->ex = t; + return NULL; + } } -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 *, jstring string, jboolean *isCopy) +static const char * JNICALL +_Jv_JNI_GetStringUTFChars (JNIEnv *env, jstring string, + jboolean *isCopy) { - jsize len = JvGetStringUTFLength (string); - // FIXME: exception processing. - char *r = (char *) _Jv_Malloc (len + 1); - JvGetStringUTFRegion (string, 0, len, r); - r[len] = '\0'; - - if (isCopy) - *isCopy = true; - - return (const char *) r; + try + { + string = unwrap (string); + if (string == NULL) + return NULL; + jsize len = JvGetStringUTFLength (string); + char *r = (char *) _Jv_Malloc (len + 1); + JvGetStringUTFRegion (string, 0, string->length(), r); + r[len] = '\0'; + + if (isCopy) + *isCopy = true; + + return (const char *) r; + } + catch (jthrowable t) + { + env->ex = t; + return NULL; + } } -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 ()) - env->ex = new java::lang::StringIndexOutOfBoundsException (); + { + try + { + env->ex = new java::lang::StringIndexOutOfBoundsException (); + } + catch (jthrowable t) + { + env->ex = t; + } + } else 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 ()) - env->ex = new java::lang::StringIndexOutOfBoundsException (); + { + try + { + env->ex = new java::lang::StringIndexOutOfBoundsException (); + } + catch (jthrowable t) + { + env->ex = t; + } + } else _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) { - // FIXME: exception processing. - jarray result = JvNewObjectArray (length, elementClass, init); - return (jarray) wrap_value (env, result); + try + { + elementClass = unwrap (elementClass); + init = unwrap (init); + + _Jv_CheckCast (elementClass, init); + jarray result = JvNewObjectArray (length, elementClass, init); + return (jobjectArray) wrap_value (env, result); + } + catch (jthrowable t) + { + env->ex = t; + return NULL; + } } -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 *, jobjectArray array, jsize index, - jobject value) +static void JNICALL +_Jv_JNI_SetObjectArrayElement (JNIEnv *env, jobjectArray array, + jsize index, jobject value) { - // FIXME: exception processing. - _Jv_CheckArrayStore (array, value); - jobject *elts = elements (array); - elts[index] = 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; + } + catch (jthrowable t) + { + env->ex = t; + } } template -static JArray * +static JArray * JNICALL _Jv_JNI_NewPrimitiveArray (JNIEnv *env, jsize length) { - // FIXME: exception processing. - return (JArray *) wrap_value (env, _Jv_NewPrimArray (K, length)); + try + { + return (JArray *) wrap_value (env, _Jv_NewPrimArray (K, length)); + } + catch (jthrowable t) + { + env->ex = t; + return NULL; + } } -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) { - // FIXME: index. - env->ex = new java::lang::ArrayIndexOutOfBoundsException (); + try + { + // FIXME: index. + env->ex = new java::lang::ArrayIndexOutOfBoundsException (); + } + catch (jthrowable t) + { + // Could have thown out of memory error. + env->ex = t; + } } else { @@ -1112,15 +1551,28 @@ _Jv_JNI_GetPrimitiveArrayRegion (JNIEnv *env, JArray *array, } } -template -static void -_Jv_JNI_SetPrimitiveArrayRegion (JNIEnv *env, JArray *array, +template +static void JNICALL +_Jv_JNI_SetPrimitiveArrayRegion (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) { - // FIXME: index. - env->ex = new java::lang::ArrayIndexOutOfBoundsException (); + try + { + // FIXME: index. + env->ex = new java::lang::ArrayIndexOutOfBoundsException (); + } + catch (jthrowable t) + { + env->ex = t; + } } else { @@ -1129,10 +1581,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 ()); @@ -1142,93 +1595,377 @@ _Jv_JNI_GetPrimitiveArrayCritical (JNIEnv *, jarray array, return r; } -static void +static void JNICALL _Jv_JNI_ReleasePrimitiveArrayCritical (JNIEnv *, jarray, void *, jint) { // Nothing. } -static jint -_Jv_JNI_MonitorEnter (JNIEnv *, jobject obj) +static jint JNICALL +_Jv_JNI_MonitorEnter (JNIEnv *env, jobject obj) { - // FIXME: exception processing. - jint r = _Jv_MonitorEnter (obj); - return r; + try + { + _Jv_MonitorEnter (unwrap (obj)); + return 0; + } + catch (jthrowable t) + { + env->ex = t; + } + return JNI_ERR; } -static jint -_Jv_JNI_MonitorExit (JNIEnv *, jobject obj) +static jint JNICALL +_Jv_JNI_MonitorExit (JNIEnv *env, jobject obj) { - // FIXME: exception processing. - jint r = _Jv_MonitorExit (obj); - return r; + try + { + _Jv_MonitorExit (unwrap (obj)); + return 0; + } + catch (jthrowable t) + { + env->ex = t; + } + return JNI_ERR; } // JDK 1.2 -jobject +jobject JNICALL _Jv_JNI_ToReflectedField (JNIEnv *env, jclass cls, jfieldID fieldID, jboolean) { - // FIXME: exception processing. - java::lang::reflect::Field *field = new java::lang::reflect::Field(); - field->declaringClass = cls; - field->offset = (char*) fieldID - (char *) cls->fields; - field->name = _Jv_NewStringUtf8Const (fieldID->getNameUtf8Const (cls)); - return wrap_value (env, field); + try + { + cls = unwrap (cls); + java::lang::reflect::Field *field = new java::lang::reflect::Field(); + field->declaringClass = cls; + field->offset = (char*) fieldID - (char *) cls->fields; + field->name = _Jv_NewStringUtf8Const (fieldID->getNameUtf8Const (cls)); + return wrap_value (env, field); + } + catch (jthrowable t) + { + env->ex = t; + } + return NULL; } // 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); - jobject result; - if (_Jv_equalUtf8Consts (id->name, init_name)) + try { - // A constructor. - Constructor *cons = new Constructor (); - cons->offset = (char *) id - (char *) &klass->methods; - cons->declaringClass = klass; - result = cons; + if (_Jv_equalUtf8Consts (id->name, init_name)) + { + // A constructor. + Constructor *cons = new Constructor (); + cons->offset = (char *) id - (char *) &klass->methods; + cons->declaringClass = klass; + result = cons; + } + else + { + Method *meth = new Method (); + meth->offset = (char *) id - (char *) &klass->methods; + meth->declaringClass = klass; + result = meth; + } } - else + catch (jthrowable t) { - Method *meth = new Method (); - meth->offset = (char *) id - (char *) &klass->methods; - meth->declaringClass = klass; - result = meth; + env->ex = t; } 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)); } +// JDK 1.2. +jweak JNICALL +_Jv_JNI_NewWeakGlobalRef (JNIEnv *env, jobject obj) +{ + using namespace gnu::gcj::runtime; + JNIWeakRef *ref = NULL; + + try + { + // This seems weird but I think it is correct. + obj = unwrap (obj); + ref = new JNIWeakRef (obj); + mark_for_gc (ref, global_ref_table); + } + catch (jthrowable t) + { + env->ex = t; + } + + return reinterpret_cast (ref); +} + +void JNICALL +_Jv_JNI_DeleteWeakGlobalRef (JNIEnv *, jweak obj) +{ + using namespace gnu::gcj::runtime; + JNIWeakRef *ref = reinterpret_cast (obj); + unmark_for_gc (ref, global_ref_table); + ref->clear (); +} + -#ifdef INTERPRETER +// 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(); +} + + + +// Hash table of native methods. +static JNINativeMethod *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 JNINativeMethod *method) +{ + char *ptr; + int hash = 0; + + 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 JNINativeMethod * +nathash_find_slot (const JNINativeMethod *method) +{ + jint h = hash (method); + int step = (h ^ (h >> 16)) | 1; + int w = h & (nathash_size - 1); + int del = -1; + + for (;;) + { + JNINativeMethod *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)) + 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 (JNINativeMethod *method) +{ + if (nathash == NULL) + return NULL; + JNINativeMethod *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 = + (JNINativeMethod *) _Jv_AllocBytes (nathash_size + * sizeof (JNINativeMethod)); + } + else + { + int savesize = nathash_size; + JNINativeMethod *savehash = nathash; + nathash_size *= 2; + nathash = + (JNINativeMethod *) _Jv_AllocBytes (nathash_size + * sizeof (JNINativeMethod)); + + for (int i = 0; i < savesize; ++i) + { + if (savehash[i].name != NULL && savehash[i].name != DELETED_ENTRY) + { + JNINativeMethod *slot = nathash_find_slot (&savehash[i]); + *slot = savehash[i]; + } + } + } +} + +static void +nathash_add (const JNINativeMethod *method) +{ + if (3 * nathash_count >= 2 * nathash_size) + natrehash (); + JNINativeMethod *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 + slot->name = strdup (method->name); + // 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); + + JNINativeMethod dottedMethod; + + // Look at each descriptor given us, and find the corresponding + // method in the class. + for (int j = 0; j < nMethods; ++j) + { + bool found = false; + + _Jv_Method *imeths = JvGetFirstMethod (klass); + for (int i = 0; i < JvNumMethods (klass); ++i) + { + _Jv_Method *self = &imeths[i]; + + // Copy this JNINativeMethod and do a slash to dot + // conversion on the signature. + dottedMethod.name = methods[j].name; + dottedMethod.signature = strdup (methods[j].signature); + dottedMethod.fnPtr = methods[j].fnPtr; + char *c = dottedMethod.signature; + while (*c) + { + if (*c == '/') + *c = '.'; + c++; + } + + if (! strcmp (self->name->chars (), dottedMethod.name) + && ! strcmp (self->signature->chars (), dottedMethod.signature)) + { + if (! (self->accflags & java::lang::reflect::Modifier::NATIVE)) + break; + + // Found a match that is native. + found = true; + nathash_add (&dottedMethod); + + break; + } + } + + if (! found) + { + jstring m = JvNewStringUTF (methods[j].name); + try + { + env->ex = new java::lang::NoSuchMethodError (m); + } + catch (jthrowable t) + { + env->ex = t; + } + return JNI_ERR; + } + } + + return JNI_OK; +} + +static jint JNICALL +_Jv_JNI_UnregisterNatives (JNIEnv *, jclass) +{ + // FIXME -- we could implement this. + return JNI_ERR; +} + + // Add a character to the buffer, encoding properly. static void @@ -1249,11 +1986,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)++] = '_'; - if ((c >= '0' && c <= '9') - || (c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z')) + else if ((c >= '0' && c <= '9') + || (c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z')) buf[(*here)++] = (char) c; else { @@ -1263,7 +2003,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; @@ -1290,8 +2030,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); @@ -1305,10 +2045,11 @@ 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; - JvAssert (signature[0] == '('); - for (int i = 1; ; ++i) + const unsigned char *sig = (const unsigned char *) signature->chars (); + limit = sig + signature->len (); + JvAssert (sig[0] == '('); + ++sig; + while (1) { int ch = UTF8_GET (sig, limit); if (ch == ')' || ch < 0) @@ -1319,28 +2060,194 @@ 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 *env = _Jv_GetCurrentJNIEnv (); + if (__builtin_expect (env == NULL, false)) + { + env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv)); + env->p = &_Jv_JNIFunctions; + env->klass = klass; + 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 = 0; + memset (&env->bottom_locals->vec[0], 0, + env->bottom_locals->size * sizeof (jobject)); + + _Jv_SetCurrentJNIEnv (env); + } + + // 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. + + if (__builtin_expect (env->locals == NULL, true)) + env->locals = env->bottom_locals; + + 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 = 0; + frame->next = env->locals; + + memset (&frame->vec[0], 0, + frame->size * sizeof (jobject)); + + env->locals = frame; + } + + env->ex = NULL; + + return env; +} + +// 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, MAYBE_UNUSED int args_size) +{ + int name_length = name->len(); + int sig_length = signature->len(); + char buf[10 + 6 * (name_length + sig_length) + 12]; + int long_start; + void *function; + + // 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'; + JNINativeMethod meth; + meth.name = buf; + meth.signature = buf + name_length + 1; + 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) + { + // 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) + { +#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 *cif, void *ret, ffi_raw *args, void *__this) +_Jv_JNIMethod::call (ffi_cif *, void *ret, ffi_raw *args, void *__this) { _Jv_JNIMethod* _this = (_Jv_JNIMethod *) __this; - JNIEnv env; - _Jv_JNI_LocalFrame *frame - = (_Jv_JNI_LocalFrame *) alloca (sizeof (_Jv_JNI_LocalFrame) - + FRAME_SIZE * sizeof (jobject)); - - env.p = &_Jv_JNIFunctions; - env.ex = NULL; - env.klass = _this->defining_class; - env.locals = frame; - - frame->marker = true; - frame->next = NULL; - frame->size = FRAME_SIZE; - for (int i = 0; i < frame->size; ++i) - frame->vec[i] = NULL; + JNIEnv *env = _Jv_GetJNIEnvNewFrame (_this->defining_class); // FIXME: we should mark every reference parameter as a local. For // now we assume a conservative GC, and we assume that the @@ -1349,40 +2256,71 @@ _Jv_JNIMethod::call (ffi_cif *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) - { - char buf[10 + 6 * (_this->self->name->length - + _this->self->signature->length)]; - int long_start; - mangled_name (_this->defining_class, _this->self->name, - _this->self->signature, buf, &long_start); - char c = buf[long_start]; - buf[long_start] = '\0'; - _this->function = _Jv_FindSymbolInExecutable (buf); - if (_this->function == NULL) - { - buf[long_start] = c; - _this->function = _Jv_FindSymbolInExecutable (buf); - if (_this->function == NULL) - { - jstring str = JvNewStringUTF (_this->self->name->data); - JvThrow (new java::lang::AbstractMethodError (str)); - } - } + { + // 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 (ffi_raw) == 0); + ffi_raw real_args[2 + _this->args_raw_size / sizeof (ffi_raw)]; + int offset = 0; + + // First argument is always the environment pointer. + real_args[offset++].ptr = env; + + // For a static method, we pass in the Class. For non-static + // methods, the `this' argument is already handled. + 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); } - // The actual call to the JNI function. - // FIXME: if this is a static function we must include the class! - ffi_raw_call (cif, (void (*) (...)) _this->function, ret, args); + // Copy over passed-in arguments. + memcpy (&real_args[offset], args, _this->args_raw_size); - do + // The actual call to the JNI 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_JNI_PopLocalFrame (&env, NULL); + _Jv_value *val = (_Jv_value *) ret; + val->object_value = unwrap (val->object_value); } - while (env.locals != frame); - if (env.ex) - JvThrow (env.ex); + if (sync != NULL) + _Jv_MonitorExit (sync); + + _Jv_JNI_PopSystemFrame (env); } #endif /* INTERPRETER */ @@ -1395,7 +2333,8 @@ _Jv_JNIMethod::call (ffi_cif *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; @@ -1403,56 +2342,111 @@ _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_ThreadCurrent () != NULL) - return 0; + JNIEnv *env = _Jv_GetCurrentJNIEnv (); + if (env != NULL) + { + *penv = reinterpret_cast (env); + return 0; + } - // FIXME: NULL return? - JNIEnv *env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv)); + env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv)); + if (env == NULL) + return JNI_ERR; env->p = &_Jv_JNIFunctions; env->ex = NULL; env->klass = NULL; - // FIXME: NULL return? - 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 = 0; + env->locals->marker = MARK_SYSTEM; + env->locals->size = FRAME_SIZE; + env->locals->next = NULL; + + for (int i = 0; i < env->locals->size; ++i) + env->locals->vec[i] = NULL; + *penv = reinterpret_cast (env); - java::lang::Thread *t = new gnu::gcj::jni::NativeThread (group, name); - t = t; // Avoid compiler warning. Eww. + // This thread might already be a Java thread -- this function might + // have been called simply to set the new JNIEnv. + if (_Jv_ThreadCurrent () == NULL) + { + try + { + if (is_daemon) + _Jv_AttachCurrentThreadAsDaemon (name, group); + else + _Jv_AttachCurrentThread (name, group); + } + catch (jthrowable t) + { + return JNI_ERR; + } + } _Jv_SetCurrentJNIEnv (env); return 0; } // This is the one actually used by JNI. -static jint +static 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); - JNIEnv *env; + union + { + JNIEnv *env; + void *env_p; + }; + if (_Jv_ThreadCurrent () != NULL) { - jint r = _Jv_JNI_AttachCurrentThread (vm, - JvNewStringLatin1 ("main"), - reinterpret_cast (&env), - NULL); + jstring main_name; + // This sucks. + try + { + main_name = JvNewStringLatin1 ("main"); + } + catch (jthrowable t) + { + return JNI_ERR; + } + + jint r = _Jv_JNI_AttachCurrentThread (vm, main_name, &env_p, + NULL, false); if (r < 0) return r; } @@ -1465,31 +2459,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) @@ -1498,8 +2475,18 @@ _Jv_JNI_GetEnv (JavaVM *, void **penv, jint version) return JNI_EDETACHED; } +#ifdef ENABLE_JVMPI + // Handle JVMPI requests. + if (version == JVMPI_VERSION_1) + { + *penv = (void *) &_Jv_JVMPI_Interface; + 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; @@ -1509,16 +2496,16 @@ _Jv_JNI_GetEnv (JavaVM *, void **penv, jint version) return 0; } -jint +jint JNICALL JNI_GetDefaultJavaVMInitArgs (void *args) { jint version = * (jint *) args; - // Here we only support 1.2. - if (version != JNI_VERSION_1_2) + // Here we only support 1.2 and 1.4. + if (version != JNI_VERSION_1_2 && version != JNI_VERSION_1_4) return JNI_EVERSION; JavaVMInitArgs *ia = reinterpret_cast (args); - ia->version = JNI_VERSION_1_2; + ia->version = JNI_VERSION_1_4; ia->nOptions = 0; ia->options = NULL; ia->ignoreUnrecognized = true; @@ -1526,71 +2513,44 @@ JNI_GetDefaultJavaVMInitArgs (void *args) return 0; } -jint +jint JNICALL JNI_CreateJavaVM (JavaVM **vm, void **penv, void *args) { JvAssert (! the_vm); + + jint version = * (jint *) args; + // We only support 1.2 and 1.4. + if (version != JNI_VERSION_1_2 && version != JNI_VERSION_1_4) + return JNI_EVERSION; + + JvVMInitArgs* vm_args = reinterpret_cast (args); + + jint result = _Jv_CreateJavaVM (vm_args); + if (result) + return result; + // 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 +jint JNICALL JNI_GetCreatedJavaVMs (JavaVM **vm_buffer, jsize buf_len, jsize *n_vms) { - JvAssert (buf_len > 0); + if (buf_len <= 0) + return JNI_ERR; + // We only support a single VM. if (the_vm != NULL) { @@ -1602,26 +2562,38 @@ JNI_GetCreatedJavaVMs (JavaVM **vm_buffer, jsize buf_len, jsize *n_vms) return 0; } -jint -_Jv_JNI_GetJavaVM (JNIEnv *, JavaVM **vm) +JavaVM * +_Jv_GetJavaVM () { // FIXME: synchronize if (! the_vm) { JavaVM *nvm = (JavaVM *) _Jv_MallocUnchecked (sizeof (JavaVM)); - if (nvm == NULL) - return JNI_ERR; - nvm->functions = &_Jv_JNI_InvokeFunctions; + if (nvm != NULL) + nvm->functions = &_Jv_JNI_InvokeFunctions; the_vm = nvm; } - *vm = the_vm; - return 0; + // If this is a Java thread, we want to make sure it has an + // associated JNIEnv. + if (_Jv_ThreadCurrent () != NULL) + { + void *ignore; + _Jv_JNI_AttachCurrentThread (the_vm, &ignore, NULL); + } + + return the_vm; +} + +static jint JNICALL +_Jv_JNI_GetJavaVM (JNIEnv *, JavaVM **vm) +{ + *vm = _Jv_GetJavaVM (); + return *vm == NULL ? JNI_ERR : JNI_OK; } -#define NOT_IMPL NULL #define RESERVED NULL struct JNINativeInterface _Jv_JNIFunctions = @@ -1630,244 +2602,281 @@ struct JNINativeInterface _Jv_JNIFunctions = 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, - NOT_IMPL /* RegisterNatives */, - NOT_IMPL /* 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 }; struct JNIInvokeInterface _Jv_JNI_InvokeFunctions = @@ -1879,5 +2888,6 @@ struct JNIInvokeInterface _Jv_JNI_InvokeFunctions = _Jv_JNI_DestroyJavaVM, _Jv_JNI_AttachCurrentThread, _Jv_JNI_DetachCurrentThread, - _Jv_JNI_GetEnv + _Jv_JNI_GetEnv, + _Jv_JNI_AttachCurrentThreadAsDaemon };