* src/mm/dumpmemory.c (dump_release): Renamed to dumpmemory_release.
[cacao.git] / src / mm / cacao-gc / gc.c
index 71e07c5a2a74f6d5d8c633c83184e5134b72604b..f2739cbdbf6307cd498fe5ec8efe334dc81e8c20 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 zu Foerderung der freien virtuellen Machine CACAO
 
    This file is part of CACAO.
 
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   $Id$
-
 */
 
 
 #include "config.h"
+
 #include <signal.h>
+#include <stdint.h>
+
 #include "vm/types.h"
 
-#if defined(ENABLE_THREADS)
-# include "threads/native/threads.h"
-#else
-# include "threads/none/lock.h"
-/*# include "threads/none/threads.h"*/
-#endif
+#include "threads/lock-common.h"
+#include "threads/threads-common.h"
 
 #include "compact.h"
 #include "copy.h"
@@ -59,9 +54,8 @@ bool gc_pending;
 bool gc_running;
 bool gc_notify_finalizer;
 
-#if defined(ENABLE_THREADS)
-java_objectheader *gc_global_lock;
-#endif
+list_t *gc_reflist_strong;
+list_t *gc_reflist_weak;
 
 #if !defined(ENABLE_THREADS)
 executionstate_t *_no_threads_executionstate;
@@ -83,6 +77,16 @@ void gc_init(u4 heapmaxsize, u4 heapstartsize)
                dolog("GC: Initialising with heap-size %d (max. %d)",
                        heapstartsize, heapmaxsize);
 
+#if defined(ENABLE_HANDLES)
+       /* check our indirection cells */
+       if (OFFSET(java_handle_t, heap_object) != 0)
+               vm_abort("gc_init: indirection cell offset is displaced: %d", OFFSET(java_handle_t, heap_object));
+       if (OFFSET(hashtable_classloader_entry, object) != 0)
+               vm_abort("gc_init: classloader entry cannot be used as indirection cell: %d", OFFSET(hashtable_classloader_entry, object));
+       if (OFFSET(hashtable_global_ref_entry, o) != 0)
+               vm_abort("gc_init: global reference entry cannot be used as indirection cell: %d", OFFSET(hashtable_global_ref_entry, o));
+#endif
+
        /* finalizer stuff */
        final_init();
 
@@ -90,11 +94,9 @@ void gc_init(u4 heapmaxsize, u4 heapstartsize)
        gc_pending = false;
        gc_running = false;
 
-#if defined(ENABLE_THREADS)
-       /* create global gc lock object */
-       gc_global_lock = NEW(java_objectheader);
-       lock_init_object_lock(gc_global_lock);
-#endif
+       /* create list for external references */
+       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);
@@ -111,6 +113,109 @@ void gc_init(u4 heapmaxsize, u4 heapstartsize)
 }
 
 
+/* gc_reference_register *******************************************************
+
+   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)
+
+*******************************************************************************/
+
+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(NDEBUG)
+       /* check if this reference is already registered */
+       for (re = list_first_unsynced(list); re != NULL; re = list_next_unsynced(list, re)) {
+               if (re->ref == ref)
+                       vm_abort("gc_reference_register_intern: reference already registered");
+       }
+#endif
+
+       /* create a new reference entry */
+       re = NEW(list_gcref_entry_t);
+
+       re->ref     = ref;
+#if !defined(NDEBUG)
+       re->reftype = reftype;
+#endif
+
+       /* add the entry to the given list */
+       list_add_last_unsynced(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_unsynced(list); re != NULL; re = list_next_unsynced(list, re)) {
+               if (re->ref == ref) {
+                       /* remove the entry from the given list */
+                       list_remove_unsynced(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)
+{
+       gc_reference_unregister_intern(gc_reflist_strong, ref);
+}
+
+void gc_weakreference_unregister(java_object_t **ref)
+{
+       gc_reference_unregister_intern(gc_reflist_weak, ref);
+}
+
+
 /* gc_collect ******************************************************************
 
    This is the main machinery which manages a collection. It should be run by
@@ -127,20 +232,20 @@ void gc_init(u4 heapmaxsize, u4 heapstartsize)
 void gc_collect(s4 level)
 {
        rootset_t    *rs;
-       s4            dumpsize;
+       int32_t       dumpmarker;
 #if !defined(NDEBUG)
-       stackframeinfo   *sfi;
-       stacktracebuffer *stb
+       stackframeinfo_t *sfi;
+       stacktracebuffer *stb;
 #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);
 
@@ -158,7 +263,7 @@ void gc_collect(s4 level)
        GC_LOG( dolog("GC: Suspending threads ..."); );
        GC_LOG( threads_dump(); );
        threads_stopworld();
-       GC_LOG( threads_dump(); );
+       /*GC_LOG( threads_dump(); );*/
        GC_LOG( dolog("GC: Suspension finished."); );
 #endif
 
@@ -191,7 +296,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);
 
@@ -199,14 +309,13 @@ void gc_collect(s4 level)
 
        /* mark the objects considering the given rootset */
        mark_me(rs);
-       /*GC_LOG( heap_dump_region(heap_region_main, true); );*/
+       /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
 
        RT_TIMING_GET_TIME(time_mark);
 
        /* compact the heap */
        compact_me(rs, heap_region_main);
-       /*GC_LOG( heap_dump_region(heap_region_main, false); );
-       GC_LOG( rootset_print(rs); );*/
+       /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
 
 #if defined(ENABLE_MEMCHECK)
        /* invalidate the rest of the main region */
@@ -215,6 +324,10 @@ void gc_collect(s4 level)
 
        RT_TIMING_GET_TIME(time_compact);
 
+       /* check if we should increase the heap size */
+       if (gc_get_free_bytes() < gc_get_heap_size() / 3) /* TODO: improve this heuristic */
+               heap_increase_size(rs);
+
 #else
 
        /* copy the heap to new region */
@@ -270,11 +383,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();
 }