diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 98d4c41a90f6..9dc48337bfef 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,22 @@ +2006-10-18 Tom Tromey + Bryce McKinlay + + * testsuite/libjava.jni/register2.java: New file. + * testsuite/libjava.jni/register2.out: New file. + * testsuite/libjava.jni/register2.c: New file. + * java/lang/natClass.cc (_Jv_GetClassNameUtf8): New function. + * java/lang/Class.h (_Jv_GetClassNameUtf8): Declare. + * jni.cc (struct NativeMethodCacheEntry): New struct. + (nathash): Changed type. + (hash): Updated. + (nathash_find_slot): Likewise. + (nathash_find): Likewise. + (natrehash): Likewise. + (nathash_add): Likewise. + (_Jv_JNI_RegisterNatives): Likewise. + (_Jv_LookupJNIMethod): Likewise. + Idea from Juerg Lehni + 2006-10-16 Geoffrey Keating * testsuite/libjava.jvmti/natevents.cc (env): Delete. diff --git a/libjava/java/lang/Class.h b/libjava/java/lang/Class.h index 1638f94e1072..a884cd6c59b7 100644 --- a/libjava/java/lang/Class.h +++ b/libjava/java/lang/Class.h @@ -231,6 +231,7 @@ jmethodID _Jv_FromReflectedMethod (java::lang::reflect::Method *); jmethodID _Jv_FromReflectedConstructor (java::lang::reflect::Constructor *); jint JvNumMethods (jclass); jmethodID JvGetFirstMethod (jclass); +_Jv_Utf8Const *_Jv_GetClassNameUtf8 (jclass); #ifdef INTERPRETER // Finds a desired interpreter method in the given class or NULL if not found @@ -474,6 +475,7 @@ private: friend jmethodID (::_Jv_FromReflectedConstructor) (java::lang::reflect::Constructor *); friend jint (::JvNumMethods) (jclass); friend jmethodID (::JvGetFirstMethod) (jclass); + friend _Jv_Utf8Const *::_Jv_GetClassNameUtf8 (jclass); #ifdef INTERPRETER friend _Jv_MethodBase *(::_Jv_FindInterpreterMethod) (jclass klass, jmethodID desired_method); diff --git a/libjava/java/lang/natClass.cc b/libjava/java/lang/natClass.cc index 0682fd6e1901..12984291ee11 100644 --- a/libjava/java/lang/natClass.cc +++ b/libjava/java/lang/natClass.cc @@ -1259,3 +1259,11 @@ _Jv_FindInterpreterMethod (jclass klass, jmethodID desired_method) return NULL; } #endif + +// Return Utf8 name of a class. This function is here for code that +// can't access klass->name directly. +_Jv_Utf8Const* +_Jv_GetClassNameUtf8 (jclass klass) +{ + return klass->name; +} diff --git a/libjava/jni.cc b/libjava/jni.cc index f7d73e553854..c5c2b0ff3cd9 100644 --- a/libjava/jni.cc +++ b/libjava/jni.cc @@ -1789,8 +1789,13 @@ _Jv_JNI_GetDirectBufferCapacity (JNIEnv *, jobject buffer) +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. @@ -1800,11 +1805,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++; @@ -1817,8 +1826,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; @@ -1827,7 +1836,7 @@ nathash_find_slot (const JNINativeMethod *method) for (;;) { - JNINativeMethod *slotp = &nathash[w]; + NativeMethodCacheEntry *slotp = &nathash[w]; if (slotp->name == NULL) { if (del >= 0) @@ -1838,7 +1847,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); } @@ -1846,11 +1856,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; @@ -1863,23 +1873,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]; } } @@ -1887,16 +1897,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; @@ -1912,7 +1923,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. @@ -1928,8 +1939,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) { @@ -2172,9 +2186,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; diff --git a/libjava/testsuite/libjava.jni/register2.c b/libjava/testsuite/libjava.jni/register2.c new file mode 100644 index 000000000000..1ed10a88a238 --- /dev/null +++ b/libjava/testsuite/libjava.jni/register2.c @@ -0,0 +1,48 @@ +#include +#include +#include + +static int +twentythree (JNIEnv *env, jclass k) +{ + return 23; +} + +static int +oneninetyseven (JNIEnv *env, jclass k) +{ + return 197; +} + +JNIEXPORT jint JNICALL +JNI_OnLoad (JavaVM *vm, void *nothing) +{ + JNIEnv *env; + JNINativeMethod meth; + jclass k; + jint r; + + r = (*vm)->GetEnv (vm, (void **) &env, JNI_VERSION_1_2); + assert (r == JNI_OK); + k = (*env)->FindClass (env, "register2$I1"); + assert (k != NULL); + + meth.name = "doit"; + meth.signature = "()I"; + meth.fnPtr = twentythree; + + r = (*env)->RegisterNatives (env, k, &meth, 1); + assert (r == JNI_OK); + + k = (*env)->FindClass (env, "register2$I2"); + assert (k != NULL); + + meth.name = "doit"; + meth.signature = "()I"; + meth.fnPtr = oneninetyseven; + + r = (*env)->RegisterNatives (env, k, &meth, 1); + assert (r == JNI_OK); + + return JNI_VERSION_1_2; +} diff --git a/libjava/testsuite/libjava.jni/register2.java b/libjava/testsuite/libjava.jni/register2.java new file mode 100644 index 000000000000..2d6c56a3b02a --- /dev/null +++ b/libjava/testsuite/libjava.jni/register2.java @@ -0,0 +1,27 @@ +// Another test of RegisterNatives. +// We neglected to track the class name in our internal hash table. +// This is a regression test for the fix. + +public class register2 +{ + static + { + System.loadLibrary ("register2"); + } + + static class I1 + { + public static native int doit (); + } + + static class I2 + { + public static native int doit (); + } + + public static void main (String[] args) + { + System.out.println (new I1().doit()); + System.out.println (new I2().doit()); + } +} diff --git a/libjava/testsuite/libjava.jni/register2.out b/libjava/testsuite/libjava.jni/register2.out new file mode 100644 index 000000000000..5b90358a22bc --- /dev/null +++ b/libjava/testsuite/libjava.jni/register2.out @@ -0,0 +1,2 @@ +23 +197