(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).
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;
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 */
*******************************************************************************/
-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) {
}
#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);
}
/* leave the global gc lock */
LOCK_MONITOR_EXIT(gc_global_lock);
+ /* XXX move this to an appropriate place */
+ lock_hashtable_cleanup();
}
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 *****************************************************************/
}
-/* 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;
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) {
#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);
}
}
}
#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)
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)
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 */
#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)
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");
/* 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 ********************************************************/
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);
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);
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);
}
+/* 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,