/* 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 ***********************************************************/
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;
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);
/* 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;
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);
}
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);
#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 */
/* 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);
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();
}