* src/mm/cacao-gc/gc.c (gc_reflist_weak): Added list for weak references.
authorMichael Starzinger <michi@complang.tuwien.ac.at>
Fri, 12 Oct 2007 21:52:11 +0000 (23:52 +0200)
committerMichael Starzinger <michi@complang.tuwien.ac.at>
Fri, 12 Oct 2007 21:52:11 +0000 (23:52 +0200)
(gc_weakreference_register, gc_weakreference_unregister): Implemented.
(gc_collect): Added preliminary call to lock_hashtable_cleanup.

* src/mm/cacao-gc/gc.h (gc_reflist_weak): Added.

* src/mm/cacao-gc/mark.c (mark_post): Added postprocessing function.

* src/mm/cacao-gc/rootset.c (rootset_from_globals): Add weak references.
(reftype_names): Adapted to new enumeration.

* src/mm/gc-common.h: Reference types are now enumerated.
(gc_weakreference_register, gc_weakreference_unregister): Added prototypes.

* src/threads/native/lock.c [ENABLE_GC_CACAO] (lock_hashtable_cleanup): Added.
(lock_record_new, lock_record_free) [ENABLE_GC_CACAO]: Register and unregister
references to lock object with the GC (as weak references).

src/mm/cacao-gc/gc.c
src/mm/cacao-gc/gc.h
src/mm/cacao-gc/mark.c
src/mm/cacao-gc/rootset.c
src/mm/gc-common.h
src/threads/native/lock.c

index 0ad4b59180caa040b3c8afea4f17689dab1361c2..61490282d522f78b0c6d5b0552e5fdc2fee31613 100644 (file)
@@ -53,7 +53,8 @@ bool gc_pending;
 bool gc_running;
 bool gc_notify_finalizer;
 
-list_t *gc_reflist;
+list_t *gc_reflist_strong;
+list_t *gc_reflist_weak;
 
 #if defined(ENABLE_THREADS)
 java_object_t *gc_global_lock;
@@ -97,7 +98,8 @@ void gc_init(u4 heapmaxsize, u4 heapstartsize)
        gc_running = false;
 
        /* create list for external references */
-       gc_reflist = list_create(OFFSET(list_gcref_entry_t, linkage));
+       gc_reflist_strong = list_create(OFFSET(list_gcref_entry_t, linkage));
+       gc_reflist_weak   = list_create(OFFSET(list_gcref_entry_t, linkage));
 
 #if defined(ENABLE_THREADS)
        /* create global gc lock object */
@@ -127,14 +129,47 @@ void gc_init(u4 heapmaxsize, u4 heapstartsize)
 
 *******************************************************************************/
 
-void gc_reference_register(java_object_t **ref, int32_t reftype)
+static void gc_reference_register_intern(list_t *list, java_object_t **ref, int32_t reftype)
 {
        list_gcref_entry_t *re;
 
+       GC_LOG2( printf("Registering Reference at %p\n", (void *) ref); );
+
        /* the reference needs to be registered before it is set, so make sure the
           reference is not yet set */
        GC_ASSERT(*ref == NULL);
 
+       re = NEW(list_gcref_entry_t);
+
+       re->ref      = ref;
+#if !defined(NDEBUG)
+       re->reftype  = reftype;
+#endif
+
+       list_add_last(list, re);
+}
+
+static void gc_reference_unregister_intern(list_t *list, java_object_t **ref)
+{
+       list_gcref_entry_t *re;
+
+       GC_LOG2( printf("Un-Registering Reference at %p\n", (void *) ref); );
+
+       for (re = list_first(list); re != NULL; re = list_next(list, re)) {
+               if (re->ref == ref) {
+                       list_remove(list, re);
+
+                       FREE(re, list_gcref_entry_t);
+
+                       break;
+               }
+       }
+
+       assert(re != NULL);
+}
+
+void gc_reference_register(java_object_t **ref, int32_t reftype)
+{
 #if defined(ENABLE_THREADS)
        /* XXX dirty hack because threads_init() not yet called */
        if (THREADOBJECT == NULL) {
@@ -143,22 +178,22 @@ void gc_reference_register(java_object_t **ref, int32_t reftype)
        }
 #endif
 
-       GC_LOG2( printf("Registering Reference at %p\n", (void *) ref); );
-
-       re = NEW(list_gcref_entry_t);
-
-       re->ref     = ref;
-#if !defined(NDEBUG)
-       re->reftype = reftype;
-#endif
-
-       list_add_last(gc_reflist, re);
+       gc_reference_register_intern(gc_reflist_strong, ref, reftype);
 }
 
+void gc_weakreference_register(java_object_t **ref, int32_t reftype)
+{
+       gc_reference_register_intern(gc_reflist_weak, ref, reftype);
+}
 
 void gc_reference_unregister(java_object_t **ref)
 {
-       vm_abort("gc_reference_unregister: IMPLEMENT ME!");
+       gc_reference_unregister_intern(gc_reflist_strong, ref);
+}
+
+void gc_weakreference_unregister(java_object_t **ref)
+{
+       gc_reference_unregister_intern(gc_reflist_weak, ref);
 }
 
 
@@ -334,6 +369,8 @@ void gc_collect(s4 level)
        /* leave the global gc lock */
        LOCK_MONITOR_EXIT(gc_global_lock);
 
+       /* XXX move this to an appropriate place */
+       lock_hashtable_cleanup();
 }
 
 
index ff2fa45e56c61abbf636ff3611d01de982c13157..b8eeab691437ef0a4734a675ff666ee06bb6ad7e 100644 (file)
 extern bool gc_pending;
 extern bool gc_notify_finalizer;
 
-extern list_t *gc_reflist;
+extern list_t *gc_reflist_strong;
+extern list_t *gc_reflist_weak;
 
 
 /* Structures *****************************************************************/
index 64cbb32a0473f711b574bab02789755370c43db0..7b7d514ac157a91d1de4e13081fa6a43ea963903 100644 (file)
@@ -164,24 +164,23 @@ void mark_recursive(java_object_t *o)
 }
 
 
-/* mark_me *********************************************************************
-
-   Marks all Heap Objects which are reachable from a given root-set.
+/* mark_post *******************************************************************
 
-   REMEMBER: Assumes all threads are stopped!
+   Perform some post-marking cleanup tasks.
 
-   IN:
-         rs.....root set containing the references
+   TASKS:
+      - mark unmarked objects with Finalizers
+      - clear unmarked Weak References
 
 *******************************************************************************/
 
-void mark_me(rootset_t *rs)
+void mark_post(rootset_t *rs)
 {
        java_object_t      *ref;
 #if defined(GCCONF_FINALIZER)
        list_final_entry_t *fe;
-#endif
        u4                  f_type;
+#endif
        void *start, *end;
        int i;
 
@@ -189,38 +188,9 @@ void mark_me(rootset_t *rs)
        start = heap_region_main->base;
        end = heap_region_main->ptr;
 
-       GCSTAT_INIT(gcstat_mark_count);
-       GCSTAT_INIT(gcstat_mark_depth);
-       GCSTAT_INIT(gcstat_mark_depth_max);
-
-       while (rs) {
-               GC_LOG( dolog("GC: Marking from rootset (%d entries) ...", rs->refcount); );
-
-               /* mark all references of the rootset */
-               for (i = 0; i < rs->refcount; i++) {
-
-                       /* is this a marking reference? */
-                       if (!rs->refs[i].marks)
-                               continue;
-
-                       /* load the reference */
-                       ref = *( rs->refs[i].ref );
-
-                       /* check for outside or null pointers */
-                       if (!POINTS_INTO(ref, start, end))
-                               continue;
-
-                       /* do the marking here */
-                       MARK(ref);
-
-               }
-
-               rs = rs->next;
-       }
-
 #if defined(GCCONF_FINALIZER)
        /* objects with finalizers will also be marked here. if they have not been
-        * marked before the finalization is triggered */
+          marked before the finalization is triggered */
        /* REMEMBER: all threads are stopped, so we can use unsynced access here */
        fe = list_first_unsynced(final_list);
        while (fe) {
@@ -265,7 +235,7 @@ void mark_me(rootset_t *rs)
 #endif
 
                        default: /* case not yet covered */
-                               vm_abort("mark_me: uncovered case (type=%d)", f_type);
+                               vm_abort("mark_post: uncovered case (type=%d)", f_type);
 
                        }
                }
@@ -274,6 +244,99 @@ void mark_me(rootset_t *rs)
        }
 #endif /*defined(GCCONF_FINALIZER)*/
 
+       /* Clear all references in the rootset which have not yet been
+          marked. This applies to registered weak references. */
+
+       while (rs) {
+               GC_LOG( dolog("GC: Clearing in rootset (%d entries) ...", rs->refcount); );
+
+               /* mark all references of the rootset */
+               for (i = 0; i < rs->refcount; i++) {
+
+                       /* load the reference */
+                       ref = *( rs->refs[i].ref );
+
+                       /* check for outside or null pointers */
+                       if (!POINTS_INTO(ref, start, end))
+                               continue;
+
+                       /* is this a marking reference? */
+                       if (rs->refs[i].marks) {
+                               assert(GC_IS_MARKED(ref));
+                       } else {
+
+                               /* clear unmarked references */
+                               if (!GC_IS_MARKED(ref)) {
+                                       GC_LOG( printf("Clearing Weak Reference %p at %p\n", ref, rs->refs[i]); );
+
+                                       *( rs->refs[i].ref ) = NULL;
+                               }
+                       }
+               }
+
+               rs = rs->next;
+       }
+
+}
+
+
+/* mark_me *********************************************************************
+
+   Marks all Heap Objects which are reachable from a given root-set.
+
+   REMEMBER: Assumes all threads are stopped!
+
+   IN:
+         rs.....root set containing the references
+
+*******************************************************************************/
+
+void mark_me(rootset_t *rs)
+{
+       rootset_t     *rstop;
+       java_object_t *ref;
+       void *start, *end;
+       int i;
+
+       /* TODO: this needs cleanup!!! */
+       start = heap_region_main->base;
+       end = heap_region_main->ptr;
+       rstop = rs;
+
+       GCSTAT_INIT(gcstat_mark_count);
+       GCSTAT_INIT(gcstat_mark_depth);
+       GCSTAT_INIT(gcstat_mark_depth_max);
+
+       while (rs) {
+               GC_LOG( dolog("GC: Marking from rootset (%d entries) ...", rs->refcount); );
+
+               /* mark all references of the rootset */
+               for (i = 0; i < rs->refcount; i++) {
+
+                       /* is this a marking reference? */
+                       if (!rs->refs[i].marks)
+                               continue;
+
+                       /* load the reference */
+                       ref = *( rs->refs[i].ref );
+
+                       /* check for outside or null pointers */
+                       if (!POINTS_INTO(ref, start, end))
+                               continue;
+
+                       /* do the marking here */
+                       MARK(ref);
+
+               }
+
+               rs = rs->next;
+       }
+
+       GC_LOG( dolog("GC: Marking postprocessing ..."); );
+
+       /* perform some post processing of the marked heap */
+       mark_post(rstop);
+
        GC_LOG( dolog("GC: Marking finished."); );
 
 #if defined(ENABLE_STATISTICS)
index 4dce00d9822d6eba5ebaf23b7fce29cd6ef3cc4e..1eabc815426177d8ffb584aed256b1d6f43a49cb 100644 (file)
@@ -79,6 +79,9 @@ rootset_t *rootset_resize(rootset_t *rs)
    Searches global variables to compile the global root set out of references
    contained in them.
 
+   REMEMBER: All threads are stopped, so we can use unsynced access
+   in this function.
+
    SEARCHES IN:
      - thread objects (threads.c)
      - classloader objects (loader.c)
@@ -110,30 +113,28 @@ static rootset_t *rootset_from_globals(rootset_t *rs)
 
        refcount = rs->refcount;
 
-       /* walk through all registered references */
-       /* REMEMBER: all threads are stopped, so we can use unsynced access here */
-       re = list_first_unsynced(gc_reflist);
-       while (re) {
-
+       /* walk through all registered strong references */
+       for (re = list_first_unsynced(gc_reflist_strong); re != NULL; re = list_next_unsynced(gc_reflist_strong, re)) {
                GC_LOG2( printf("Found Registered Reference: %p at %p of type %d\n", *(re->ref), re->ref, ref->reftype); );
 
                /* add this registered reference to the root set */
                ROOTSET_ADD(re->ref, true, re->reftype)
+       }
+
+       /* walk through all registered weak references */
+       for (re = list_first_unsynced(gc_reflist_weak); re != NULL; re = list_next_unsynced(gc_reflist_weak, re)) {
+               GC_LOG2( printf("Found Registered Weak Reference: %p at %p of type %d\n", *(re->ref), re->ref, ref->reftype); );
 
-               re = list_next_unsynced(gc_reflist, re);
+               /* add this registered reference to the root set */
+               ROOTSET_ADD(re->ref, false, re->reftype)
        }
 
        /* walk through all finalizer entries */
-       /* REMEMBER: all threads are stopped, so we can use unsynced access here */
-       fe = list_first_unsynced(final_list);
-       while (fe) {
-
+       for (fe = list_first_unsynced(final_list); fe != NULL; fe = list_next_unsynced(final_list, fe)) {
                GC_LOG2( printf("Found Finalizer Entry: %p\n", (void *) fe->o); );
 
                /* add this object with finalizer to the root set */
                ROOTSET_ADD(&( fe->o ), false, GC_REFTYPE_FINALIZER)
-
-               fe = list_next_unsynced(final_list, fe);
        }
 
        /* remeber how many references there are inside this root set */
@@ -391,9 +392,9 @@ void rootset_writeback(rootset_t *rs)
 
 #if !defined(NDEBUG)
 static const char* reftype_names[] = {
-               "XXXXXXXXXXXX", "THREADOBJECT", "CLASSLOADER ",
-               "GLOBAL-REF  ", "FINALIZER   ", "LOCAL-REF   ",
-               "ON-STACK-ADR", "STATIC FIELD"
+               "THREADOBJECT", "CLASSLOADER ", "GLOBAL-REF  ",
+               "FINALIZER   ", "LOCAL-REF   ", "ON-STACK-ADR",
+               "STATIC FIELD", "LOCKRECORD  "
 };
 
 void rootset_print(rootset_t *rs)
@@ -426,9 +427,9 @@ void rootset_print(rootset_t *rs)
                        printf("\t\t");
                        printf("%s ", reftype_names[rs->refs[i].reftype]);
                        if (rs->refs[i].marks)
-                               printf("MARK+UPDATE");
+                               printf("STRONG");
                        else
-                               printf("     UPDATE");
+                               printf("  WEAK");
                        printf(" ");
                        heap_print_object(o);
                        printf("\n");
index 756a71ed0a43fcafeb471de3ca1610076c06561e..f3b6ff9259c19f10a28a78952173e691d8b97987 100644 (file)
 
 /* reference types ************************************************************/
 
-#define GC_REFTYPE_THREADOBJECT  1
-#define GC_REFTYPE_CLASSLOADER   2
-#define GC_REFTYPE_JNI_GLOBALREF 3
-#define GC_REFTYPE_FINALIZER     4
-#define GC_REFTYPE_LOCALREF      5
-#define GC_REFTYPE_STACK         6
-#define GC_REFTYPE_CLASSREF      7
+enum {
+       GC_REFTYPE_THREADOBJECT,
+       GC_REFTYPE_CLASSLOADER,
+       GC_REFTYPE_JNI_GLOBALREF,
+       GC_REFTYPE_FINALIZER,
+       GC_REFTYPE_LOCALREF,
+       GC_REFTYPE_STACK,
+       GC_REFTYPE_CLASSREF,
+       GC_REFTYPE_LOCKRECORD
+};
 
 
 /* function prototypes ********************************************************/
@@ -63,6 +66,9 @@ s4    heap_get_hashcode(java_object_t *o);
 
 void  gc_reference_register(java_object_t **ref, int32_t reftype);
 void  gc_reference_unregister(java_object_t **ref);
+
+void  gc_weakreference_register(java_object_t **ref, int32_t reftype);
+void  gc_weakreference_unregister(java_object_t **ref);
 #endif
 
 void  gc_call(void);
index 36294c93c1b4828ad87e71970ee84bdf705bb76c..e99e587056356b466b7a70f94b22a772122e0e3b 100644 (file)
@@ -273,6 +273,12 @@ static lock_record_t *lock_record_new(void)
        lr->count   = 0;
        lr->waiters = list_create(OFFSET(lock_waiter_t, linkage));
 
+#if defined(ENABLE_GC_CACAO)
+       /* register the lock object as weak reference with the GC */
+
+       gc_weakreference_register(&(lr->object), GC_REFTYPE_LOCKRECORD);
+#endif
+
        /* initialize the mutex */
 
        pthread_mutex_init(&(lr->mutex), NULL);
@@ -300,6 +306,12 @@ static void lock_record_free(lock_record_t *lr)
 
        pthread_mutex_destroy(&(lr->mutex));
 
+#if defined(ENABLE_GC_CACAO)
+       /* unregister the lock object reference with the GC */
+
+       gc_weakreference_unregister(&(lr->object));
+#endif
+
        /* Free the waiters list. */
 
        list_free(lr->waiters);
@@ -410,6 +422,67 @@ static void lock_hashtable_grow(void)
 }
 
 
+/* lock_hashtable_cleanup ******************************************************
+
+   Removes (and frees) lock records which have a cleared object reference
+   from the hashtable. The locked object was reclaimed by the GC.
+
+*******************************************************************************/
+
+#if defined(ENABLE_GC_CACAO)
+void lock_hashtable_cleanup(void)
+{
+       threadobject  *t;
+       lock_record_t *lr;
+       lock_record_t *prev;
+       lock_record_t *next;
+       int i;
+
+       t = THREADOBJECT;
+
+       /* lock the hashtable */
+
+       pthread_mutex_lock(&(lock_hashtable.mutex));
+
+       /* search the hashtable for cleared references */
+
+       for (i = 0; i < lock_hashtable.size; i++) {
+               lr = lock_hashtable.ptr[i];
+               prev = NULL;
+
+               while (lr) {
+                       next = lr->hashlink;
+
+                       /* remove lock records with cleared references */
+
+                       if (lr->object == NULL) {
+
+                               /* unlink the lock record from the hashtable */
+
+                               if (prev == NULL)
+                                       lock_hashtable.ptr[i] = next;
+                               else
+                                       prev->hashlink = next;
+
+                               /* free the lock record */
+
+                               lock_record_free(lr);
+
+                       } else {
+                               prev = lr;
+                       }
+
+                       lr = next;
+               }
+       }
+
+       /* unlock the hashtable */
+
+       pthread_mutex_unlock(&(lock_hashtable.mutex));
+}
+#endif
+
+
 /* lock_hashtable_get **********************************************************
 
    Find the lock record for the given object.  If it does not exists,