From 4265a08351e56affd091ca08ec8381c247719ae6 Mon Sep 17 00:00:00 2001 From: tromey Date: Mon, 20 Aug 2001 19:52:02 +0000 Subject: [PATCH] * jni.cc (nathash, nathash_count, nathash_size): New globals. (DELETED_ENTRY): New define. (hash): New function. (nathash_find_slot): Likewise. (natrehash): Likewise. (nathash_add): Likewise. (_Jv_JNI_RegisterNatives): No longer interpreter-specific. Use nathash_add. (nathash_find): New function. (_Jv_LookupJNIMethod): Use it. Synchronize body. (call): Synchronize around assignment. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@45060 138bc75d-0d04-0410-961f-82ee72b054a4 --- libjava/ChangeLog | 14 +++++ libjava/jni.cc | 173 +++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 166 insertions(+), 21 deletions(-) diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 4d9ef24..b6fa026 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,17 @@ +2001-08-20 Tom Tromey + + * jni.cc (nathash, nathash_count, nathash_size): New globals. + (DELETED_ENTRY): New define. + (hash): New function. + (nathash_find_slot): Likewise. + (natrehash): Likewise. + (nathash_add): Likewise. + (_Jv_JNI_RegisterNatives): No longer interpreter-specific. Use + nathash_add. + (nathash_find): New function. + (_Jv_LookupJNIMethod): Use it. Synchronize body. + (call): Synchronize around assignment. + 2001-08-17 Jeff Sturm * gnu/gcj/convert/UnicodeToBytes.java (write): Write work buffer diff --git a/libjava/jni.cc b/libjava/jni.cc index 7b82908..be45cb2 100644 --- a/libjava/jni.cc +++ b/libjava/jni.cc @@ -1543,19 +1543,131 @@ _Jv_JNI_FromReflectedMethod (JNIEnv *, jobject method) _Jv_FromReflectedConstructor (reinterpret_cast (method)); } + + +// 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)); + memset (nathash, 0, nathash_size * sizeof (JNINativeMethod)); + } + else + { + int savesize = nathash_size; + JNINativeMethod *savehash = nathash; + nathash_size *= 2; + nathash = + (JNINativeMethod *) _Jv_AllocBytes (nathash_size + * sizeof (JNINativeMethod)); + memset (nathash, 0, 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); + slot->signature = strdup (method->signature); + slot->fnPtr = method->fnPtr; +} + static jint -_Jv_JNI_RegisterNatives (JNIEnv *env, jclass k, +_Jv_JNI_RegisterNatives (JNIEnv *env, jclass klass, const JNINativeMethod *methods, jint nMethods) { -#ifdef INTERPRETER - // For now, this only matters for interpreted methods. FIXME. - if (! _Jv_IsInterpretedClass (k)) - { - // FIXME: throw exception. - return JNI_ERR; - } - _Jv_InterpClass *klass = reinterpret_cast<_Jv_InterpClass *> (k); + // 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); // Look at each descriptor given us, and find the corresponding // method in the class. @@ -1563,11 +1675,10 @@ _Jv_JNI_RegisterNatives (JNIEnv *env, jclass k, { bool found = false; - _Jv_MethodBase **imeths = _Jv_GetFirstMethod (klass); + _Jv_Method *imeths = JvGetFirstMethod (klass); for (int i = 0; i < JvNumMethods (klass); ++i) { - _Jv_MethodBase *meth = imeths[i]; - _Jv_Method *self = meth->get_method (); + _Jv_Method *self = &imeths[i]; if (! strcmp (self->name->data, methods[j].name) && ! strcmp (self->signature->data, methods[j].signature)) @@ -1577,9 +1688,9 @@ _Jv_JNI_RegisterNatives (JNIEnv *env, jclass k, break; // Found a match that is native. - _Jv_JNIMethod *jmeth = reinterpret_cast<_Jv_JNIMethod *> (meth); - jmeth->set_function (methods[i].fnPtr); found = true; + nathash_add (&methods[j]); + break; } } @@ -1600,14 +1711,12 @@ _Jv_JNI_RegisterNatives (JNIEnv *env, jclass k, } return JNI_OK; -#else /* INTERPRETER */ - return JNI_ERR; -#endif /* INTERPRETER */ } static jint _Jv_JNI_UnregisterNatives (JNIEnv *, jclass) { + // FIXME -- we could implement this. return JNI_ERR; } @@ -1751,6 +1860,22 @@ _Jv_LookupJNIMethod (jclass klass, _Jv_Utf8Const *name, 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->data, name->length); + buf[name->length] = '\0'; + strncpy (buf + name->length + 1, signature->data, signature->length); + buf[name->length + signature->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. mangled_name (klass, name, signature, buf, &long_start); char c = buf[long_start]; buf[long_start] = '\0'; @@ -1787,10 +1912,16 @@ _Jv_JNIMethod::call (ffi_cif *, void *ret, ffi_raw *args, void *__this) // We cache the value that we find, of course, but if we don't find // a value we don't cache that fact -- we might subsequently load a // library which finds the function in question. - if (_this->function == NULL) - _this->function = _Jv_LookupJNIMethod (_this->defining_class, - _this->self->name, - _this->self->signature); + { + // 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) + _this->function = _Jv_LookupJNIMethod (_this->defining_class, + _this->self->name, + _this->self->signature); + } JvAssert (_this->args_raw_size % sizeof (ffi_raw) == 0); ffi_raw real_args[2 + _this->args_raw_size / sizeof (ffi_raw)]; -- 2.7.4