* src/native/jni.c (DeleteGlobalRef): Bugfix: handle the removal of
[cacao.git] / src / native / jni.c
index 0d2371d9c9324a66fa13f88971bb4ad4bd2b6fd3..1e1100652c996aa5b9614b29712d2a8a8ec2e69d 100644 (file)
@@ -32,7 +32,7 @@
             Christian Thalinger
                        Edwin Steiner
 
-   $Id: jni.c 4573 2006-03-08 09:44:22Z twisti $
+   $Id: jni.c 4901 2006-05-11 12:18:55Z twisti $
 
 */
 
 
 /* global reference table *****************************************************/
 
-static java_objectheader **global_ref_table;
+/* hashsize must be power of 2 */
 
-/* jmethodID and jclass caching variables for NewGlobalRef and DeleteGlobalRef*/
-static classinfo *ihmclass = NULL;
-static methodinfo *putmid = NULL;
-static methodinfo *getmid = NULL;
-static methodinfo *removemid = NULL;
+#define HASHTABLE_GLOBAL_REF_SIZE    64 /* initial size of globalref-hash     */
+
+static hashtable *hashtable_global_ref; /* hashtable for globalrefs           */
 
 
 /* direct buffer stuff ********************************************************/
@@ -162,29 +160,11 @@ jint EnsureLocalCapacity(JNIEnv* env, jint capacity);
 
 bool jni_init(void)
 {
-       /* initalize global reference table */
-
-       if (!(ihmclass =
-                 load_class_bootstrap(utf_new_char("java/util/IdentityHashMap"))))
-               return false;
-
-       global_ref_table = GCNEW(jobject);
+       /* create global ref hashtable */
 
-       if (!(*global_ref_table = native_new_and_init(ihmclass)))
-               return false;
+       hashtable_global_ref = NEW(hashtable);
 
-       if (!(getmid = class_resolvemethod(ihmclass, utf_get,
-                                                                          utf_java_lang_Object__java_lang_Object)))
-               return false;
-
-       if (!(putmid = class_resolvemethod(ihmclass, utf_put,
-                                                                          utf_new_char("(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"))))
-               return false;
-
-       if (!(removemid =
-                 class_resolvemethod(ihmclass, utf_remove,
-                                                         utf_java_lang_Object__java_lang_Object)))
-               return false;
+       hashtable_create(hashtable_global_ref, HASHTABLE_GLOBAL_REF_SIZE);
 
 
        /* direct buffer stuff */
@@ -243,6 +223,7 @@ static bool _Jv_jni_vmargs_from_objectarray(java_objectheader *o,
        classinfo         *c;
        s4                 i;
        s4                 j;
+       s8                 value;
 
        paramcount = descr->paramcount;
        paramtypes = descr->paramtypes;
@@ -253,8 +234,8 @@ static bool _Jv_jni_vmargs_from_objectarray(java_objectheader *o,
 
        if (o != NULL) {
                /* this pointer */
-               vmargs[0].type = TYPE_ADR;
-               vmargs[0].data = (u8) (ptrint) o;
+               vmargs[0].type   = TYPE_ADR;
+               vmargs[0].data.l = (u8) (ptrint) o;
 
                paramtypes++;
                paramcount--;
@@ -283,70 +264,82 @@ static bool _Jv_jni_vmargs_from_objectarray(java_objectheader *o,
                        switch (paramtypes->decltype) {
                        case PRIMITIVETYPE_BOOLEAN:
                                if (c == primitivetype_table[paramtypes->decltype].class_wrap)
-                                       vmargs[i].data = (s8) ((java_lang_Boolean *) param)->value;
+                                       value = (s8) ((java_lang_Boolean *) param)->value;
                                else
                                        goto illegal_arg;
+
+                               vmargs[i].data.l = value;
                                break;
 
                        case PRIMITIVETYPE_BYTE:
                                if (c == primitivetype_table[paramtypes->decltype].class_wrap)
-                                       vmargs[i].data = (s8) ((java_lang_Byte *) param)->value;
+                                       value = (s8) ((java_lang_Byte *) param)->value;
                                else
                                        goto illegal_arg;
+
+                               vmargs[i].data.l = value;
                                break;
 
                        case PRIMITIVETYPE_CHAR:
                                if (c == primitivetype_table[paramtypes->decltype].class_wrap)
-                                       vmargs[i].data = (s8) ((java_lang_Character *) param)->value;
+                                       value = (s8) ((java_lang_Character *) param)->value;
                                else
                                        goto illegal_arg;
+
+                               vmargs[i].data.l = value;
                                break;
 
                        case PRIMITIVETYPE_SHORT:
                                if (c == primitivetype_table[paramtypes->decltype].class_wrap)
-                                       vmargs[i].data = (s8) ((java_lang_Short *) param)->value;
+                                       value = (s8) ((java_lang_Short *) param)->value;
                                else if (c == primitivetype_table[PRIMITIVETYPE_BYTE].class_wrap)
-                                       vmargs[i].data = (s8) ((java_lang_Byte *) param)->value;
+                                       value = (s8) ((java_lang_Byte *) param)->value;
                                else
                                        goto illegal_arg;
+
+                               vmargs[i].data.l = value;
                                break;
 
                        case PRIMITIVETYPE_INT:
                                if (c == primitivetype_table[paramtypes->decltype].class_wrap)
-                                       vmargs[i].data = (s8) ((java_lang_Integer *) param)->value;
+                                       value = (s8) ((java_lang_Integer *) param)->value;
                                else if (c == primitivetype_table[PRIMITIVETYPE_SHORT].class_wrap)
-                                       vmargs[i].data = (s8) ((java_lang_Short *) param)->value;
+                                       value = (s8) ((java_lang_Short *) param)->value;
                                else if (c == primitivetype_table[PRIMITIVETYPE_BYTE].class_wrap)
-                                       vmargs[i].data = (s8) ((java_lang_Byte *) param)->value;
+                                       value = (s8) ((java_lang_Byte *) param)->value;
                                else
                                        goto illegal_arg;
+
+                               vmargs[i].data.l = value;
                                break;
 
                        case PRIMITIVETYPE_LONG:
                                if (c == primitivetype_table[paramtypes->decltype].class_wrap)
-                                       vmargs[i].data = (s8) ((java_lang_Long *) param)->value;
+                                       value = (s8) ((java_lang_Long *) param)->value;
                                else if (c == primitivetype_table[PRIMITIVETYPE_INT].class_wrap)
-                                       vmargs[i].data = (s8) ((java_lang_Integer *) param)->value;
+                                       value = (s8) ((java_lang_Integer *) param)->value;
                                else if (c == primitivetype_table[PRIMITIVETYPE_SHORT].class_wrap)
-                                       vmargs[i].data = (s8) ((java_lang_Short *) param)->value;
+                                       value = (s8) ((java_lang_Short *) param)->value;
                                else if (c == primitivetype_table[PRIMITIVETYPE_BYTE].class_wrap)
-                                       vmargs[i].data = (s8) ((java_lang_Byte *) param)->value;
+                                       value = (s8) ((java_lang_Byte *) param)->value;
                                else
                                        goto illegal_arg;
+
+                               vmargs[i].data.l = value;
                                break;
 
                        case PRIMITIVETYPE_FLOAT:
                                if (c == primitivetype_table[paramtypes->decltype].class_wrap)
-                                       *((jfloat *) (&vmargs[i].data)) = (jfloat) ((java_lang_Float *) param)->value;
+                                       vmargs[i].data.f = (jfloat) ((java_lang_Float *) param)->value;
                                else
                                        goto illegal_arg;
                                break;
 
                        case PRIMITIVETYPE_DOUBLE:
                                if (c == primitivetype_table[paramtypes->decltype].class_wrap)
-                                       *((jdouble *) (&vmargs[i].data)) = (jdouble) ((java_lang_Double *) param)->value;
+                                       vmargs[i].data.d = (jdouble) ((java_lang_Double *) param)->value;
                                else if (c == primitivetype_table[PRIMITIVETYPE_FLOAT].class_wrap)
-                                       *((jfloat *) (&vmargs[i].data)) = (jfloat) ((java_lang_Float *) param)->value;
+                                       vmargs[i].data.f = (jfloat) ((java_lang_Float *) param)->value;
                                else
                                        goto illegal_arg;
                                break;
@@ -370,8 +363,9 @@ static bool _Jv_jni_vmargs_from_objectarray(java_objectheader *o,
                                                        goto illegal_arg;
                                        }
                                }
-                               vmargs[i].type = TYPE_ADR;
-                               vmargs[i].data = (u8) (ptrint) params->data[j];
+
+                               vmargs[i].type   = TYPE_ADR;
+                               vmargs[i].data.l = (u8) (ptrint) params->data[j];
                                break;
 
                        default:
@@ -1061,7 +1055,7 @@ jclass DefineClass(JNIEnv *env, const char *name, jobject loader,
        STATISTICS(jniinvokation());
 
        cl = (java_lang_ClassLoader *) loader;
-       s = javastring_new_char(name);
+       s = javastring_new_from_ascii(name);
        ba = (java_bytearray *) buf;
 
        c = (jclass) Java_java_lang_VMClassLoader_defineClass(env, NULL, cl, s, ba,
@@ -1206,7 +1200,7 @@ jint ThrowNew(JNIEnv* env, jclass clazz, const char *msg)
 
        STATISTICS(jniinvokation());
 
-       s = (java_lang_String *) javastring_new_char(msg);
+       s = (java_lang_String *) javastring_new_from_ascii(msg);
 
        /* instantiate exception object */
 
@@ -5118,46 +5112,64 @@ void DeleteWeakGlobalRef(JNIEnv* env, jweak ref)
 
 *******************************************************************************/
     
-jobject NewGlobalRef(JNIEnv* env, jobject lobj)
+jobject NewGlobalRef(JNIEnv* env, jobject obj)
 {
-       java_objectheader *o;
-       java_lang_Integer *refcount;
-       java_objectheader *newval;
+       hashtable_global_ref_entry *gre;
+       u4   key;                           /* hashkey                            */
+       u4   slot;                          /* slot in hashtable                  */
 
        STATISTICS(jniinvokation());
 
 #if defined(USE_THREADS)
-       builtin_monitorenter(*global_ref_table);
+       builtin_monitorenter(hashtable_global_ref->header);
 #endif
+
+       /* normally addresses are aligned to 4, 8 or 16 bytes */
+
+       key  = ((u4) (ptrint) obj) >> 4;           /* align to 16-byte boundaries */
+       slot = key & (hashtable_global_ref->size - 1);
+       gre  = hashtable_global_ref->ptr[slot];
        
-       o = vm_call_method(getmid, *global_ref_table, lobj);
+       /* search external hash chain for the entry */
 
-       refcount = (java_lang_Integer *) o;
+       while (gre) {
+               if (gre->o == obj) {
+                       /* global object found, increment the reference */
 
-       if (refcount == NULL) {
-               newval = native_new_and_init_int(class_java_lang_Integer, 1);
+                       gre->refs++;
 
-               if (newval == NULL) {
 #if defined(USE_THREADS)
-                       builtin_monitorexit(*global_ref_table);
+                       builtin_monitorexit(hashtable_global_ref->header);
 #endif
-                       return NULL;
+
+                       return obj;
                }
 
-               (void) vm_call_method(putmid, *global_ref_table, lobj, newval);
+               gre = gre->hashlink;                /* next element in external chain */
+       }
 
-       } else {
-               /* we can access the object itself, as we are in a
-           synchronized section */
+       /* global ref not found, create a new one */
 
-               refcount->value++;
-       }
+       gre = NEW(hashtable_global_ref_entry);
+
+       gre->o    = obj;
+       gre->refs = 1;
+
+       /* insert entry into hashtable */
+
+       gre->hashlink = hashtable_global_ref->ptr[slot];
+
+       hashtable_global_ref->ptr[slot] = gre;
+
+       /* update number of hashtable-entries */
+
+       hashtable_global_ref->entries++;
 
 #if defined(USE_THREADS)
-       builtin_monitorexit(*global_ref_table);
+       builtin_monitorexit(hashtable_global_ref->header);
 #endif
 
-       return lobj;
+       return obj;
 }
 
 
@@ -5169,42 +5181,63 @@ jobject NewGlobalRef(JNIEnv* env, jobject lobj)
 
 void DeleteGlobalRef(JNIEnv* env, jobject globalRef)
 {
-       java_objectheader *o;
-       java_lang_Integer *refcount;
-       s4                 val;
+       hashtable_global_ref_entry *gre;
+       hashtable_global_ref_entry *prevgre;
+       u4   key;                           /* hashkey                            */
+       u4   slot;                          /* slot in hashtable                  */
 
        STATISTICS(jniinvokation());
 
 #if defined(USE_THREADS)
-       builtin_monitorenter(*global_ref_table);
+       builtin_monitorenter(hashtable_global_ref->header);
 #endif
 
-       o = vm_call_method(getmid, *global_ref_table, globalRef);
+       /* normally addresses are aligned to 4, 8 or 16 bytes */
 
-       refcount = (java_lang_Integer *) o;
+       key  = ((u4) (ptrint) globalRef) >> 4;     /* align to 16-byte boundaries */
+       slot = key & (hashtable_global_ref->size - 1);
+       gre  = hashtable_global_ref->ptr[slot];
 
-       if (refcount == NULL) {
-               log_text("JNI-DeleteGlobalRef: unable to find global reference");
-               return;
-       }
+       /* initialize prevgre */
 
-       /* we can access the object itself, as we are in a synchronized
-          section */
+       prevgre = NULL;
 
-       val = refcount->value - 1;
+       /* search external hash chain for the entry */
 
-       if (val == 0) {
-               (void) vm_call_method(removemid, *global_ref_table, refcount);
+       while (gre) {
+               if (gre->o == globalRef) {
+                       /* global object found, decrement the reference count */
 
-       } else {
-               /* we do not create a new object, but set the new value into
-           the old one */
+                       gre->refs--;
+
+                       /* if reference count is 0, remove the entry */
+
+                       if (gre->refs == 0) {
+                               /* special handling if it's the first in the chain */
+
+                               if (prevgre == NULL)
+                                       hashtable_global_ref->ptr[slot] = gre->hashlink;
+                               else
+                                       prevgre->hashlink = gre->hashlink;
+
+                               FREE(gre, hashtable_global_ref_entry);
+                       }
+
+#if defined(USE_THREADS)
+                       builtin_monitorexit(hashtable_global_ref->header);
+#endif
 
-               refcount->value = val;
+                       return;
+               }
+
+               prevgre = gre;                    /* save current pointer for removal */
+               gre     = gre->hashlink;            /* next element in external chain */
        }
 
+       log_println("JNI-DeleteGlobalRef: global reference not found");
+
 #if defined(USE_THREADS)
-       builtin_monitorexit(*global_ref_table);
+       builtin_monitorexit(hashtable_global_ref->header);
 #endif
 }
 
@@ -5811,10 +5844,6 @@ jint JNI_CreateJavaVM(JavaVM **p_vm, void **p_env, void *vm_args)
 
        _Jv_env = env;
 
-       /* actually create the JVM */
-
-       if (!vm_create(_vm_args))
-               return -1;
 
        /* create and fill a JavaVM structure */
 
@@ -5822,9 +5851,15 @@ jint JNI_CreateJavaVM(JavaVM **p_vm, void **p_env, void *vm_args)
        jvm->functions = &_Jv_JNIInvokeInterface;
 
        /* XXX Set the global variable.  Maybe we should do that differently. */
-
+       /* XXX JVMTI Agents needs a JavaVM  */
        _Jv_jvm = jvm;
 
+
+       /* actually create the JVM */
+
+       if (!vm_create(_vm_args))
+               return -1;
+
        /* setup the local ref table (must be created after vm_create) */
 
        lrt = GCNEW(localref_table);