X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=libjava%2Fjni.cc;h=86a4dc5b2610738b6f5cc65124240564ef7df1c2;hb=41a604740013b2e8ef6444b43693ed6d115710c9;hp=19539c7714a83c7f67ab82bcdac7ad606f355606;hpb=10fd8185f15498797ae2ee1e6fc2722b5d47379c;p=pf3gnuchains%2Fgcc-fork.git diff --git a/libjava/jni.cc b/libjava/jni.cc index 19539c7714a..86a4dc5b261 100644 --- a/libjava/jni.cc +++ b/libjava/jni.cc @@ -1,6 +1,6 @@ // jni.cc - JNI implementation, including the jump table. -/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation This file is part of libgcj. @@ -22,7 +22,10 @@ details. */ #ifdef ENABLE_JVMPI #include #endif - +#ifdef INTERPRETER +#include +#include "jvmti-int.h" +#endif #include #include #include @@ -67,8 +70,8 @@ enum invocation_type }; // Forward declarations. -extern struct JNINativeInterface _Jv_JNIFunctions; -extern struct JNIInvokeInterface _Jv_JNI_InvokeFunctions; +extern struct JNINativeInterface_ _Jv_JNIFunctions; +extern struct JNIInvokeInterface_ _Jv_JNI_InvokeFunctions; // Number of slots in the default frame. The VM must allow at least // 16. @@ -84,16 +87,18 @@ extern struct JNIInvokeInterface _Jv_JNI_InvokeFunctions; // This structure is used to keep track of local references. struct _Jv_JNI_LocalFrame { - // This is true if this frame object represents a pushed frame (eg - // from PushLocalFrame). - int marker; + // This is one of the MARK_ constants. + unsigned char marker; // Flag to indicate some locals were allocated. - int allocated_p; + bool allocated_p; // Number of elements in frame. int size; + // The class loader of the JNI method that allocated this frame. + ::java::lang::ClassLoader *loader; + // Next frame in chain. _Jv_JNI_LocalFrame *next; @@ -248,6 +253,12 @@ _Jv_JNI_DeleteGlobalRef (JNIEnv *, jobject obj) { // This seems weird but I think it is correct. obj = unwrap (obj); + + // NULL is ok here -- the JNI specification doesn't say so, but this + // is a no-op. + if (! obj) + return; + unmark_for_gc (obj, global_ref_table); } @@ -259,6 +270,11 @@ _Jv_JNI_DeleteLocalRef (JNIEnv *env, jobject obj) // This seems weird but I think it is correct. obj = unwrap (obj); + // NULL is ok here -- the JNI specification doesn't say so, but this + // is a no-op. + if (! obj) + return; + for (frame = env->locals; frame != NULL; frame = frame->next) { for (int i = 0; i < frame->size; ++i) @@ -299,8 +315,9 @@ _Jv_JNI_EnsureLocalCapacity (JNIEnv *env, jint size) frame->marker = MARK_NONE; frame->size = size; - frame->allocated_p = 0; + frame->allocated_p = false; memset (&frame->vec[0], 0, size * sizeof (jobject)); + frame->loader = env->locals->loader; frame->next = env->locals; env->locals = frame; @@ -338,7 +355,7 @@ _Jv_JNI_NewLocalRef (JNIEnv *env, jobject obj) set = true; done = true; frame->vec[i] = obj; - frame->allocated_p = 1; + frame->allocated_p = true; break; } } @@ -356,7 +373,7 @@ _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; + env->locals->allocated_p = true; } mark_for_gc (obj, local_ref_table); @@ -385,7 +402,7 @@ _Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result, int stop) { if (rf->allocated_p) memset (&rf->vec[0], 0, rf->size * sizeof (jobject)); - rf->allocated_p = 0; + rf->allocated_p = false; rf = NULL; break; } @@ -436,13 +453,17 @@ _Jv_JNI_PopSystemFrame (JNIEnv *env) _Jv_JNI_PopLocalFrame (env, NULL, MARK_SYSTEM); else env->locals = NULL; - + +#ifdef INTERPRETER if (__builtin_expect (env->ex != NULL, false)) { jthrowable t = env->ex; env->ex = NULL; + if (JVMTI_REQUESTED_EVENT (Exception)) + _Jv_ReportJVMTIExceptionThrow (t); throw t; } +#endif } template T extract_from_jvalue(jvalue const & t); @@ -529,8 +550,8 @@ _Jv_JNI_FindClass (JNIEnv *env, const char *name) jstring n = JvNewStringUTF (s); java::lang::ClassLoader *loader = NULL; - if (env->klass != NULL) - loader = env->klass->getClassLoaderInternal (); + if (env->locals->loader != NULL) + loader = env->locals->loader; if (loader == NULL) { @@ -540,6 +561,7 @@ _Jv_JNI_FindClass (JNIEnv *env, const char *name) } r = loader->loadClass (n); + _Jv_InitClass (r); } catch (jthrowable t) { @@ -735,7 +757,8 @@ _Jv_JNI_GetAnyMethodID (JNIEnv *env, jclass clazz, java::lang::StringBuffer *name_sig = new java::lang::StringBuffer (JvNewStringUTF (name)); - name_sig->append ((jchar) ' ')->append (JvNewStringUTF (s)); + name_sig->append ((jchar) ' '); + name_sig->append (JvNewStringUTF (s)); env->ex = new java::lang::NoSuchMethodError (name_sig->toString ()); } catch (jthrowable t) @@ -850,7 +873,7 @@ _Jv_JNI_CallAnyMethod (JNIEnv *env, jobject obj, jclass klass, template static T JNICALL _Jv_JNI_CallAnyMethodA (JNIEnv *env, jobject obj, jclass klass, - jmethodID id, jvalue *args) + jmethodID id, const jvalue *args) { obj = unwrap (obj); klass = unwrap (klass); @@ -947,7 +970,7 @@ _Jv_JNI_CallAnyVoidMethod (JNIEnv *env, jobject obj, jclass klass, template static void JNICALL _Jv_JNI_CallAnyVoidMethodA (JNIEnv *env, jobject obj, jclass klass, - jmethodID id, jvalue *args) + jmethodID id, const jvalue *args) { jclass decl_class = klass ? klass : obj->getClass (); JvAssert (decl_class != NULL); @@ -1012,7 +1035,7 @@ _Jv_JNI_CallMethod (JNIEnv *env, jobject obj, jmethodID id, ...) template static T JNICALL _Jv_JNI_CallMethodA (JNIEnv *env, jobject obj, - jmethodID id, jvalue *args) + jmethodID id, const jvalue *args) { return _Jv_JNI_CallAnyMethodA (env, obj, NULL, id, args); } @@ -1036,7 +1059,7 @@ _Jv_JNI_CallVoidMethod (JNIEnv *env, jobject obj, jmethodID id, ...) static void JNICALL _Jv_JNI_CallVoidMethodA (JNIEnv *env, jobject obj, - jmethodID id, jvalue *args) + jmethodID id, const jvalue *args) { _Jv_JNI_CallAnyVoidMethodA (env, obj, NULL, id, args); } @@ -1080,7 +1103,7 @@ _Jv_JNI_CallStaticMethod (JNIEnv *env, jclass klass, template static T JNICALL _Jv_JNI_CallStaticMethodA (JNIEnv *env, jclass klass, jmethodID id, - jvalue *args) + const jvalue *args) { JvAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC)); JvAssert (java::lang::Class::class$.isInstance (unwrap (klass))); @@ -1108,7 +1131,7 @@ _Jv_JNI_CallStaticVoidMethod (JNIEnv *env, jclass klass, static void JNICALL _Jv_JNI_CallStaticVoidMethodA (JNIEnv *env, jclass klass, - jmethodID id, jvalue *args) + jmethodID id, const jvalue *args) { _Jv_JNI_CallAnyVoidMethodA (env, NULL, klass, id, args); } @@ -1151,7 +1174,7 @@ _Jv_JNI_NewObject (JNIEnv *env, jclass klass, jmethodID id, ...) static jobject JNICALL _Jv_JNI_NewObjectA (JNIEnv *env, jclass klass, jmethodID id, - jvalue *args) + const jvalue *args) { JvAssert (klass && ! klass->isArray ()); JvAssert (! strcmp (id->name->chars(), "") @@ -1309,6 +1332,9 @@ _Jv_JNI_NewStringUTF (JNIEnv *env, const char *bytes) { try { + // For compatibility with the JDK. + if (!bytes) + return NULL; jstring result = JvNewStringUTF (bytes); return (jstring) wrap_value (env, result); } @@ -1554,7 +1580,7 @@ _Jv_JNI_GetPrimitiveArrayRegion (JNIEnv *env, JArray *array, template static void JNICALL _Jv_JNI_SetPrimitiveArrayRegion (JNIEnv *env, JArray *array, - jsize start, jsize len, T *buf) + jsize start, jsize len, const T *buf) { array = unwrap (array); if (! _Jv_JNI_check_types (env, array, K)) @@ -1734,6 +1760,10 @@ _Jv_JNI_NewWeakGlobalRef (JNIEnv *env, jobject obj) void JNICALL _Jv_JNI_DeleteWeakGlobalRef (JNIEnv *, jweak obj) { + // JDK compatibility. + if (obj == NULL) + return; + using namespace gnu::gcj::runtime; JNIWeakRef *ref = reinterpret_cast (obj); unmark_for_gc (ref, global_ref_table); @@ -1775,10 +1805,22 @@ _Jv_JNI_GetDirectBufferCapacity (JNIEnv *, jobject buffer) return tmp->capacity(); } +static jobjectRefType JNICALL +_Jv_JNI_GetObjectRefType (JNIEnv *, MAYBE_UNUSED jobject object) +{ + JvFail("GetObjectRefType not implemented"); + return JNIInvalidRefType; +} + +struct NativeMethodCacheEntry : public JNINativeMethod +{ + char *className; +}; + // Hash table of native methods. -static JNINativeMethod *nathash; +static NativeMethodCacheEntry *nathash; // Number of slots used. static int nathash_count = 0; // Number of slots available. Must be power of 2. @@ -1788,11 +1830,15 @@ static int nathash_size = 0; // Compute a hash value for a native method descriptor. static int -hash (const JNINativeMethod *method) +hash (const NativeMethodCacheEntry *method) { char *ptr; int hash = 0; + ptr = method->className; + while (*ptr) + hash = (31 * hash) + *ptr++; + ptr = method->name; while (*ptr) hash = (31 * hash) + *ptr++; @@ -1805,8 +1851,8 @@ hash (const JNINativeMethod *method) } // Find the slot where a native method goes. -static JNINativeMethod * -nathash_find_slot (const JNINativeMethod *method) +static NativeMethodCacheEntry * +nathash_find_slot (const NativeMethodCacheEntry *method) { jint h = hash (method); int step = (h ^ (h >> 16)) | 1; @@ -1815,7 +1861,7 @@ nathash_find_slot (const JNINativeMethod *method) for (;;) { - JNINativeMethod *slotp = &nathash[w]; + NativeMethodCacheEntry *slotp = &nathash[w]; if (slotp->name == NULL) { if (del >= 0) @@ -1826,7 +1872,8 @@ nathash_find_slot (const JNINativeMethod *method) else if (slotp->name == DELETED_ENTRY) del = w; else if (! strcmp (slotp->name, method->name) - && ! strcmp (slotp->signature, method->signature)) + && ! strcmp (slotp->signature, method->signature) + && ! strcmp (slotp->className, method->className)) return slotp; w = (w + step) & (nathash_size - 1); } @@ -1834,11 +1881,11 @@ nathash_find_slot (const JNINativeMethod *method) // Find a method. Return NULL if it isn't in the hash table. static void * -nathash_find (JNINativeMethod *method) +nathash_find (NativeMethodCacheEntry *method) { if (nathash == NULL) return NULL; - JNINativeMethod *slot = nathash_find_slot (method); + NativeMethodCacheEntry *slot = nathash_find_slot (method); if (slot->name == NULL || slot->name == DELETED_ENTRY) return NULL; return slot->fnPtr; @@ -1851,23 +1898,23 @@ natrehash () { nathash_size = 1024; nathash = - (JNINativeMethod *) _Jv_AllocBytes (nathash_size - * sizeof (JNINativeMethod)); + (NativeMethodCacheEntry *) _Jv_AllocBytes (nathash_size + * sizeof (NativeMethodCacheEntry)); } else { int savesize = nathash_size; - JNINativeMethod *savehash = nathash; + NativeMethodCacheEntry *savehash = nathash; nathash_size *= 2; nathash = - (JNINativeMethod *) _Jv_AllocBytes (nathash_size - * sizeof (JNINativeMethod)); + (NativeMethodCacheEntry *) _Jv_AllocBytes (nathash_size + * sizeof (NativeMethodCacheEntry)); for (int i = 0; i < savesize; ++i) { if (savehash[i].name != NULL && savehash[i].name != DELETED_ENTRY) { - JNINativeMethod *slot = nathash_find_slot (&savehash[i]); + NativeMethodCacheEntry *slot = nathash_find_slot (&savehash[i]); *slot = savehash[i]; } } @@ -1875,16 +1922,17 @@ natrehash () } static void -nathash_add (const JNINativeMethod *method) +nathash_add (const NativeMethodCacheEntry *method) { if (3 * nathash_count >= 2 * nathash_size) natrehash (); - JNINativeMethod *slot = nathash_find_slot (method); + NativeMethodCacheEntry *slot = nathash_find_slot (method); // If the slot has a real entry in it, then there is no work to do. if (slot->name != NULL && slot->name != DELETED_ENTRY) return; - // FIXME + // FIXME: memory leak? slot->name = strdup (method->name); + slot->className = strdup (method->className); // This was already strduped in _Jv_JNI_RegisterNatives. slot->signature = method->signature; slot->fnPtr = method->fnPtr; @@ -1900,7 +1948,7 @@ _Jv_JNI_RegisterNatives (JNIEnv *env, jclass klass, // the nathash table. JvSynchronize sync (global_ref_table); - JNINativeMethod dottedMethod; + NativeMethodCacheEntry dottedMethod; // Look at each descriptor given us, and find the corresponding // method in the class. @@ -1916,8 +1964,11 @@ _Jv_JNI_RegisterNatives (JNIEnv *env, jclass klass, // Copy this JNINativeMethod and do a slash to dot // conversion on the signature. dottedMethod.name = methods[j].name; + // FIXME: we leak a little memory here if the method + // is not found. dottedMethod.signature = strdup (methods[j].signature); dottedMethod.fnPtr = methods[j].fnPtr; + dottedMethod.className = _Jv_GetClassNameUtf8 (klass)->chars(); char *c = dottedMethod.signature; while (*c) { @@ -2060,18 +2111,14 @@ mangled_name (jclass klass, _Jv_Utf8Const *func_name, buf[here] = '\0'; } -// Return the current thread's JNIEnv; if one does not exist, create -// it. Also create a new system frame for use. This is `extern "C"' -// because the compiler calls it. -extern "C" JNIEnv * -_Jv_GetJNIEnvNewFrame (jclass klass) +JNIEnv * +_Jv_GetJNIEnvNewFrameWithLoader (::java::lang::ClassLoader *loader) { JNIEnv *env = _Jv_GetCurrentJNIEnv (); if (__builtin_expect (env == NULL, false)) { env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv)); - env->p = &_Jv_JNIFunctions; - env->klass = klass; + env->functions = &_Jv_JNIFunctions; env->locals = NULL; // We set env->ex below. @@ -2080,11 +2127,12 @@ _Jv_GetJNIEnvNewFrame (jclass klass) _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; + env->bottom_locals->allocated_p = false; + // We set the klass field below. memset (&env->bottom_locals->vec[0], 0, env->bottom_locals->size * sizeof (jobject)); @@ -2096,23 +2144,25 @@ _Jv_GetJNIEnvNewFrame (jclass klass) // built, above. if (__builtin_expect (env->locals == NULL, true)) - env->locals = env->bottom_locals; - + { + env->locals = env->bottom_locals; + env->locals->loader = loader; + } else { // Alternatively, we might be re-entering JNI, in which case we can't // reuse the bottom_locals frame, because it is already underneath // us. So we need to make a new one. - _Jv_JNI_LocalFrame *frame = (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame) + (FRAME_SIZE * sizeof (jobject))); - + frame->marker = MARK_SYSTEM; frame->size = FRAME_SIZE; - frame->allocated_p = 0; + frame->allocated_p = false; frame->next = env->locals; + frame->loader = loader; memset (&frame->vec[0], 0, frame->size * sizeof (jobject)); @@ -2125,6 +2175,15 @@ _Jv_GetJNIEnvNewFrame (jclass klass) return env; } +// Return the current thread's JNIEnv; if one does not exist, create +// it. Also create a new system frame for use. This is `extern "C"' +// because the compiler calls it. +extern "C" JNIEnv * +_Jv_GetJNIEnvNewFrame (jclass klass) +{ + return _Jv_GetJNIEnvNewFrameWithLoader (klass->getClassLoaderInternal()); +} + // Destroy the env's reusable resources. This is called from the thread // destructor "finalize_native" in natThread.cc void @@ -2160,9 +2219,10 @@ _Jv_LookupJNIMethod (jclass klass, _Jv_Utf8Const *name, buf[name_length] = '\0'; strncpy (buf + name_length + 1, signature->chars (), sig_length); buf[name_length + sig_length + 1] = '\0'; - JNINativeMethod meth; + NativeMethodCacheEntry meth; meth.name = buf; meth.signature = buf + name_length + 1; + meth.className = _Jv_GetClassNameUtf8(klass)->chars(); function = nathash_find (&meth); if (function != NULL) return function; @@ -2243,7 +2303,8 @@ _Jv_LookupJNIMethod (jclass klass, _Jv_Utf8Const *name, // This function is the stub which is used to turn an ordinary (CNI) // method call into a JNI call. void -_Jv_JNIMethod::call (ffi_cif *, void *ret, ffi_raw *args, void *__this) +_Jv_JNIMethod::call (ffi_cif *, void *ret, INTERP_FFI_RAW_TYPE *args, + void *__this) { _Jv_JNIMethod* _this = (_Jv_JNIMethod *) __this; @@ -2275,8 +2336,9 @@ _Jv_JNIMethod::call (ffi_cif *, void *ret, ffi_raw *args, void *__this) } } - JvAssert (_this->args_raw_size % sizeof (ffi_raw) == 0); - ffi_raw real_args[2 + _this->args_raw_size / sizeof (ffi_raw)]; + JvAssert (_this->args_raw_size % sizeof (INTERP_FFI_RAW_TYPE) == 0); + INTERP_FFI_RAW_TYPE + real_args[2 + _this->args_raw_size / sizeof (INTERP_FFI_RAW_TYPE)]; int offset = 0; // First argument is always the environment pointer. @@ -2300,6 +2362,10 @@ _Jv_JNIMethod::call (ffi_cif *, void *ret, ffi_raw *args, void *__this) // Copy over passed-in arguments. memcpy (&real_args[offset], args, _this->args_raw_size); + + // Add a frame to the composite (interpreted + JNI) call stack + java::lang::Thread *thread = java::lang::Thread::currentThread(); + _Jv_NativeFrame nat_frame (_this, thread); // The actual call to the JNI function. #if FFI_NATIVE_RAW_API @@ -2362,9 +2428,8 @@ _Jv_JNI_AttachCurrentThread (JavaVM *, jstring name, void **penv, env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv)); if (env == NULL) return JNI_ERR; - env->p = &_Jv_JNIFunctions; + env->functions = &_Jv_JNIFunctions; env->ex = NULL; - env->klass = NULL; env->bottom_locals = (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame) + (FRAME_SIZE @@ -2376,9 +2441,10 @@ _Jv_JNI_AttachCurrentThread (JavaVM *, jstring name, void **penv, return JNI_ERR; } - env->locals->allocated_p = 0; + env->locals->allocated_p = false; env->locals->marker = MARK_SYSTEM; env->locals->size = FRAME_SIZE; + env->locals->loader = NULL; env->locals->next = NULL; for (int i = 0; i < env->locals->size; ++i) @@ -2484,6 +2550,15 @@ _Jv_JNI_GetEnv (JavaVM *, void **penv, jint version) } #endif +#ifdef INTERPRETER + // Handle JVMTI requests + if (version == JVMTI_VERSION_1_0) + { + *penv = (void *) _Jv_GetJVMTIEnv (); + return 0; + } +#endif + // FIXME: do we really want to support 1.1? if (version != JNI_VERSION_1_4 && version != JNI_VERSION_1_2 && version != JNI_VERSION_1_1) @@ -2530,7 +2605,7 @@ _Jv_JNI_GetJavaVM (JNIEnv *, JavaVM **vm) #define RESERVED NULL -struct JNINativeInterface _Jv_JNIFunctions = +struct JNINativeInterface_ _Jv_JNIFunctions = { RESERVED, RESERVED, @@ -2810,10 +2885,12 @@ struct JNINativeInterface _Jv_JNIFunctions = _Jv_JNI_NewDirectByteBuffer, // NewDirectByteBuffer _Jv_JNI_GetDirectBufferAddress, // GetDirectBufferAddress - _Jv_JNI_GetDirectBufferCapacity // GetDirectBufferCapacity + _Jv_JNI_GetDirectBufferCapacity, // GetDirectBufferCapacity + + _Jv_JNI_GetObjectRefType // GetObjectRefType }; -struct JNIInvokeInterface _Jv_JNI_InvokeFunctions = +struct JNIInvokeInterface_ _Jv_JNI_InvokeFunctions = { RESERVED, RESERVED,