Merge from subtype.
[cacao.git] / src / mm / cacao-gc / gc.c
index d262bcf778164021861647eaa6631c68ca38dc45..e9fd6d50f66e34a5f5232eff0da07d1cb7bcaf71 100644 (file)
@@ -1,9 +1,7 @@
 /* src/mm/cacao-gc/gc.c - main garbage collector methods
 
-   Copyright (C) 2006 R. Grafl, A. Krall, C. Kruegel,
-   C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
-   E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
-   J. Wenninger, Institut f. Computersprachen - TU Wien
+   Copyright (C) 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
 
    This file is part of CACAO.
 
 
 
 #include "config.h"
+
 #include <signal.h>
+#include <stdint.h>
+
 #include "vm/types.h"
 
-#include "threads/lock-common.h"
-#include "threads/threads-common.h"
+#include "threads/lock.hpp"
+#include "threads/thread.hpp"
 
 #include "compact.h"
 #include "copy.h"
 #include "rootset.h"
 #include "mm/memory.h"
 #include "toolbox/logging.h"
+
 #include "vm/finalizer.h"
-#include "vm/vm.h"
-#include "vmcore/rt-timing.h"
+#include "vm/rt-timing.h"
+#include "vm/vm.hpp"
 
 
 /* Global Variables ***********************************************************/
@@ -53,11 +55,8 @@ bool gc_pending;
 bool gc_running;
 bool gc_notify_finalizer;
 
-list_t *gc_reflist;
-
-#if defined(ENABLE_THREADS)
-java_object_t *gc_global_lock;
-#endif
+list_t *gc_reflist_strong;
+list_t *gc_reflist_weak;
 
 #if !defined(ENABLE_THREADS)
 executionstate_t *_no_threads_executionstate;
@@ -97,13 +96,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));
-
-#if defined(ENABLE_THREADS)
-       /* create global gc lock object */
-       gc_global_lock = NEW(java_object_t);
-       lock_init_object_lock(gc_global_lock);
-#endif
+       gc_reflist_strong = list_create(OFFSET(list_gcref_entry_t, linkage));
+       gc_reflist_weak   = list_create(OFFSET(list_gcref_entry_t, linkage));
 
        /* region for uncollectable objects */
        heap_region_sys = NEW(regioninfo_t);
@@ -122,29 +116,37 @@ void gc_init(u4 heapmaxsize, u4 heapstartsize)
 
 /* gc_reference_register *******************************************************
 
-   Register an external reference which points onto the Heap and keeps
-   objects alive (strong reference).
+   Register an external reference which points onto the Heap. The
+   reference needs to be cleared (set to NULL) when registering and
+   has to be set after it has been registered (to avoid a race condition).
+   
+   STRONG REFERENCE: gets updated and keeps objects alive
+   WEAK REFERENCE:   only gets updated (or maybe cleared)
 
 *******************************************************************************/
 
-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;
 
+       /* the global GC lock also guards the reference lists */
+       GC_MUTEX_LOCK;
+
+       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);
 
-#if defined(ENABLE_THREADS)
-       /* XXX dirty hack because threads_init() not yet called */
-       if (THREADOBJECT == NULL) {
-               GC_LOG( dolog("GC: Unable to register Reference!"); );
-               return;
+#if !defined(NDEBUG)
+       /* check if this reference is already registered */
+       for (re = list_first(list); re != NULL; re = list_next(list, re)) {
+               if (re->ref == ref)
+                       vm_abort("gc_reference_register_intern: reference already registered");
        }
 #endif
 
-       GC_LOG2( printf("Registering Reference at %p\n", (void *) ref); );
-
+       /* create a new reference entry */
        re = NEW(list_gcref_entry_t);
 
        re->ref     = ref;
@@ -152,13 +154,66 @@ void gc_reference_register(java_object_t **ref, int32_t reftype)
        re->reftype = reftype;
 #endif
 
-       list_add_last(gc_reflist, re);
+       /* add the entry to the given list */
+       list_add_last(list, re);
+
+       /* the global GC lock also guards the reference lists */
+       GC_MUTEX_UNLOCK;
+}
+
+void gc_reference_register(java_object_t **ref, int32_t reftype)
+{
+       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);
 }
 
 
+/* gc_reference_unregister *****************************************************
+
+   Unregister a previously registered external reference.
+
+*******************************************************************************/
+
+static void gc_reference_unregister_intern(list_t *list, java_object_t **ref)
+{
+       list_gcref_entry_t *re;
+
+       /* the global GC lock also guards the reference lists */
+       GC_MUTEX_LOCK;
+
+       GC_LOG2( printf("Un-Registering Reference at %p\n", (void *) ref); );
+
+       /* search for the appropriate reference entry */
+       for (re = list_first(list); re != NULL; re = list_next(list, re)) {
+               if (re->ref == ref) {
+                       /* remove the entry from the given list */
+                       list_remove(list, re);
+
+                       /* free the reference entry */
+                       FREE(re, list_gcref_entry_t);
+
+                       break;
+               }
+       }
+
+       vm_abort("gc_reference_unregister_intern: reference not found");
+
+       /* the global GC lock also guards the reference lists */
+       GC_MUTEX_UNLOCK;
+}
+
 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);
 }
 
 
@@ -178,20 +233,19 @@ void gc_reference_unregister(java_object_t **ref)
 void gc_collect(s4 level)
 {
        rootset_t    *rs;
-       s4            dumpsize;
+       int32_t       dumpmarker;
 #if !defined(NDEBUG)
-       stackframeinfo   *sfi;
-       stacktracebuffer *stb;
+       stacktrace_t *st;
 #endif
 #if defined(ENABLE_RT_TIMING)
        struct timespec time_start, time_suspend, time_rootset, time_mark, time_compact, time_end;
 #endif
 
        /* enter the global gc lock */
-       LOCK_MONITOR_ENTER(gc_global_lock);
+       GC_MUTEX_LOCK;
 
        /* remember start of dump memory area */
-       dumpsize = dump_size();
+       DMARKER;
 
        GCSTAT_COUNT(gcstat_collections);
 
@@ -216,11 +270,10 @@ void gc_collect(s4 level)
 #if !defined(NDEBUG)
        /* get the stacktrace of the current thread and make sure it is non-empty */
        GC_LOG( printf("Stacktrace of current thread:\n"); );
-       sfi = STACKFRAMEINFO;
-       stb = stacktrace_create(sfi);
-       if (stb == NULL)
+       st = stacktrace_get_current();
+       if (st == NULL)
                vm_abort("gc_collect: no stacktrace available for current thread!");
-       GC_LOG( stacktrace_print_trace_from_buffer(stb); );
+       GC_LOG( stacktrace_print(st); );
 #endif
 
        /* sourcestate of the current thread, assuming we are in the native world */
@@ -242,7 +295,12 @@ void gc_collect(s4 level)
 
        /* find the global and local rootsets */
        rs = rootset_readout();
-       GC_LOG( rootset_print(rs); );
+
+#if !defined(NDEBUG)
+       /* print the rootsets if debugging is enabled */
+       if (opt_GCDebugRootSet)
+               rootset_print(rs);
+#endif
 
        RT_TIMING_GET_TIME(time_rootset);
 
@@ -324,11 +382,13 @@ void gc_collect(s4 level)
        RT_TIMING_TIME_DIFF(time_start  , time_end    , RT_TIMING_GC_TOTAL);
 
     /* free dump memory area */
-    dump_release(dumpsize);
+    DRELEASE;
 
        /* leave the global gc lock */
-       LOCK_MONITOR_EXIT(gc_global_lock);
+       GC_MUTEX_UNLOCK;
 
+       /* XXX move this to an appropriate place */
+       lock_hashtable_cleanup();
 }