src/mm/cacao-gc/rootset.c: Added.
* src/mm/cacao-gc/Makefile.am: See above.
* src/mm/cacao-gc/gc.h (gc_notify_finalizer): Added.
* src/mm/cacao-gc/gc.c: Added finalization support.
* src/mm/cacao-gc/mark.c: Same as above. Rootset can contain "non-marking"
references now.
* src/mm/cacao-gc/heap.h, src/mm/cacao-gc/heap.c: Severe code cleanup,
this applies to almost all files.
--HG--
branch : exact-gc
libgc_la_SOURCES = \
compact.c \
compact.h \
+ final.c \
+ final.h \
gc.c \
gc.h \
heap.c \
mark.c \
mark.h \
region.c \
- region.h
+ region.h \
+ rootset.c \
+ rootset.h
## Local variables:
java_objectheader **refptr;
int i;
- GC_LOG2( printf("threading in rootset\n"); );
+ GC_LOG2( printf("threading in rootsets\n"); );
- /* walk through the references of this rootset */
- for (i = 0; i < rs->refcount; i++) {
+ /* walk through all rootsets */
+ while (rs) {
- /* load the reference */
- refptr = rs->refs[i];
- ref = *( refptr );
+ /* walk through the references of this rootset */
+ for (i = 0; i < rs->refcount; i++) {
+
+ /* load the reference */
+ refptr = rs->refs[i];
+ ref = *( refptr );
- GC_LOG2( printf("\troot pointer to %p\n", (void *) ref); );
+ GC_LOG2( printf("\troot pointer to %p\n", (void *) ref); );
- /* thread the references */
- GC_THREAD(ref, refptr, start, end);
+ /* thread the references */
+ GC_THREAD(ref, refptr, start, end);
+
+ }
+
+ /* skip to next rootset in chain */
+ rs = rs->next;
}
}
/* compact_thread_classes ******************************************************
- Threads all the references from classinfo structures (static fields and
- classloaders)
+ Threads all the references from classinfo structures (static fields)
IN:
start.....Region to be compacted start here
java_objectheader **refptr;
classinfo *c;
fieldinfo *f;
- hashtable_classloader_entry *cle;
+ /*hashtable_classloader_entry *cle;*/
void *sys_start, *sys_end;
int i;
sys_start = heap_region_sys->base;
sys_end = heap_region_sys->ptr;
+#if 0
/* walk through all classloaders */
for (i = 0; i < hashtable_classloader->size; i++) {
cle = hashtable_classloader->ptr[i];
cle = cle->hashlink;
}
}
+#endif
/* walk through all classinfo blocks */
for (c = sys_start; c < (classinfo *) sys_end; c++) {
/* check if we need to attach the hashcode to the object */
if (GC_TEST_FLAGS((java_objectheader *) new, HDRFLAG_HASH_TAKEN)) {
+ /* TODO: move this whole bunch to heap_attach_hashcode() */
+
/* change the flags accordingly */
GC_CLEAR_FLAGS((java_objectheader *) new, HDRFLAG_HASH_TAKEN);
GC_SET_FLAGS((java_objectheader *) new, HDRFLAG_HASH_ATTACHED);
*( (s4 *) (new + new_size - SIZEOF_VOID_P) ) = hashcode; /* TODO: clean this up */
GC_ASSERT(new + SIZEOF_VOID_P < old);
- GC_LOG( dolog("GC: Hash attached: %d (0x%08x) to new object at %p", hashcode, hashcode, new); );
+ GC_LOG2( dolog("GC: Hash attached: %d (0x%08x) to new object at %p", hashcode, hashcode, new); );
}
u4 o_size_new;
u4 used;
- GC_LOG( dolog("GC: Compaction Phase 1 started ..."); );
+ GC_LOG( dolog("GC: Compaction Phase 0 started ..."); );
/* Phase 0:
* - thread all references in classes
compact_thread_classes(region->base, region->ptr);
compact_thread_rootset(rs, region->base, region->ptr);
+ GC_LOG( dolog("GC: Compaction Phase 1 started ..."); );
+
/* Phase 1:
* - scan the heap
* - thread all references
o = (java_objectheader *) ptr;
/* uncollectable items should never be compacted */
- GC_ASSERT(!GC_TEST_FLAGS(o, GC_FLAG_UNCOLLECTABLE));
+ GC_ASSERT(!GC_TEST_FLAGS(o, HDRFLAG_UNCOLLECTABLE));
/* if this object is already part of a threaded chain ... */
if (GC_IS_THREADED(o->vftbl)) {
--- /dev/null
+/* mm/cacao-gc/final.c - GC module for finalization and weak references
+
+ 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
+
+ This file is part of CACAO.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+ Contact: cacao@cacaojvm.org
+
+ Authors: Michael Starzinger
+
+ $Id$
+
+*/
+
+
+#include "config.h"
+#include "vm/types.h"
+
+#include "gc.h"
+#include "final.h"
+#include "heap.h"
+#include "mm/memory.h"
+#include "vm/finalizer.h"
+
+
+/* Global Variables ***********************************************************/
+
+list *final_list;
+
+
+
+void final_init()
+{
+ final_list = list_create(OFFSET(final_entry, linkage));
+}
+
+void final_register(java_objectheader *o, methodinfo *finalizer)
+{
+ final_entry *fe;
+
+ fe = NEW(final_entry);
+ fe->type = FINAL_REACHABLE;
+ fe->o = o;
+ fe->finalizer = finalizer;
+
+ list_add_last(final_list, fe);
+
+ GC_LOG( printf("Finalizer registered for: %p\n", (void *) o); );
+}
+
+void final_invoke()
+{
+ final_entry *fe;
+ final_entry *fe_next;
+
+ fe = list_first(final_list);
+ fe_next = NULL;
+ while (fe) {
+ fe_next = list_next(final_list, fe);
+
+ if (fe->type == FINAL_RECLAIMABLE) {
+
+ GC_LOG( printf("Finalizer starting for: ");
+ heap_print_object(fe->o); printf("\n"); );
+
+ GC_ASSERT(fe->finalizer == fe->o->vftbl->class->finalizer);
+
+ fe->type = FINAL_FINALIZING;
+
+ finalizer_run(fe->o, NULL);
+
+ fe->type = FINAL_FINALIZED;
+
+ list_remove(final_list, fe);
+ FREE(fe, final_entry);
+ }
+
+ fe = fe_next;
+ }
+}
+
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
--- /dev/null
+/* mm/cacao-gc/final.h - GC header for finalization and weak references
+
+ 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
+
+ This file is part of CACAO.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+ Contact: cacao@cacaojvm.org
+
+ Authors: Michael Starzinger
+
+ $Id$
+
+*/
+
+
+#ifndef _FINAL_H
+#define _FINAL_H
+
+#include "vm/types.h"
+
+#include "toolbox/list.h"
+#include "vmcore/method.h"
+
+
+/* Global Variables ***********************************************************/
+
+extern list *final_list;
+
+
+/* Structures *****************************************************************/
+
+typedef struct final_entry final_entry;
+
+#define FINAL_REACHABLE 1
+#define FINAL_RECLAIMABLE 2
+#define FINAL_FINALIZING 3
+#define FINAL_FINALIZED 4
+
+struct final_entry {
+ listnode linkage;
+ u4 type;
+ java_objectheader *o;
+ methodinfo *finalizer;
+};
+
+
+/* Prototypes *****************************************************************/
+
+void final_init();
+void final_register(java_objectheader *o, methodinfo *finalizer);
+void final_invoke();
+
+
+#endif /* _FINAL_H */
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
#endif
#include "compact.h"
+#include "final.h"
#include "gc.h"
#include "heap.h"
#include "mark.h"
#include "region.h"
+#include "rootset.h"
#include "mm/memory.h"
#include "toolbox/logging.h"
-#include "vm/exceptions.h"
-/*#include "vm/options.h"*/
+#include "vm/finalizer.h"
+#include "vm/vm.h"
+
+
+/* Global Variables ***********************************************************/
+
+bool gc_running;
+bool gc_notify_finalizer;
/* gc_init *********************************************************************
dolog("GC: Initialising with heap-size %d (max. %d)",
heapstartsize, heapmaxsize);
+ /* finalizer stuff */
+ final_init();
+
+ /* set global variables */
+ gc_running = false;
+
/* region for uncollectable objects */
heap_region_sys = NEW(regioninfo_t);
if (!region_create(heap_region_sys, GC_SYS_SIZE))
- exceptions_throw_outofmemory_exit();
+ vm_abort("gc_init: region_create failed: out of memory");
/* region for java objects */
heap_region_main = NEW(regioninfo_t);
if (!region_create(heap_region_main, heapstartsize))
- exceptions_throw_outofmemory_exit();
+ vm_abort("gc_init: region_create failed: out of memory");
heap_current_size = heapstartsize;
heap_maximal_size = heapmaxsize;
void gc_collect(s4 level)
{
rootset_t *rs;
- regioninfo_t *src, *dst;
s4 dumpsize;
/* remember start of dump memory area */
dumpsize = dump_size();
+ /* finalizer is not notified, unless marking tells us to do so */
+ gc_notify_finalizer = false;
+
GC_LOG( heap_println_usage(); );
/*GC_LOG( heap_dump_region(heap_base, heap_ptr, false); );*/
/* find the global rootset and the rootset for the current thread */
- rs = DNEW(rootset_t);
- /*TODO: mark_rootset_create(rs);*/
- /*TODO: mark_rootset_from_globals(rs);*/
- mark_rootset_from_thread(THREADOBJECT, rs);
- GC_LOG( mark_rootset_print(rs); );
+ rs = rootset_create();
+ rootset_from_globals(rs);
+ rs->next = rootset_create();
+ rootset_from_thread(THREADOBJECT, rs->next);
+ GC_LOG( rootset_print(rs); );
+
+ /* check for reentrancy here */
+ if (gc_running) {
+ dolog("GC: REENTRANCY DETECTED, aborting ...");
+ goto gc_collect_abort;
+ }
+
+ /* once the rootset is complete, we consider ourselves running */
+ gc_running = true;
#if 1
/* compact the heap */
compact_me(rs, heap_region_main);
/*GC_LOG( heap_dump_region(heap_region_main, false); );
- GC_LOG( mark_rootset_print(rs); );*/
+ GC_LOG( rootset_print(rs); );*/
#if defined(ENABLE_MEMCHECK)
/* invalidate the rest of the main region */
#else
/* copy the heap to new region */
- dst = DNEW(regioninfo_t);
- region_init(dst, heap_current_size);
- gc_copy(heap_region_main, dst, rs);
+ {
+ regioninfo_t *src, *dst;
+
+ dst = DNEW(regioninfo_t);
+ region_init(dst, heap_current_size);
+ gc_copy(heap_region_main, dst, rs);
+ }
/* invalidate old heap */
/*memset(heap_base, 0x5a, heap_current_size);*/
/*heap_increase_size();*/
/* write back the rootset to update root references */
- GC_LOG( mark_rootset_print(rs); );
- mark_rootset_writeback(rs);
+ GC_LOG( rootset_print(rs); );
+ rootset_writeback(rs);
#if defined(ENABLE_STATISTICS)
if (opt_verbosegc)
gcstat_println();
#endif
+ /* does the finalizer need to be notified */
+ if (gc_notify_finalizer)
+ finalizer_notify();
+
+ /* we are no longer running */
+ /* REMEBER: keep this below the finalizer notification */
+ gc_running = false;
+
+gc_collect_abort:
/* free dump memory area */
dump_release(dumpsize);
}
+/* gc_invoke_finalizers ********************************************************
+
+ Forces invocation of all the finalizers for objects which are reclaimable.
+ This is the function which is called by the finalizer thread.
+
+*******************************************************************************/
+
+void gc_invoke_finalizers(void)
+{
+ if (opt_verbosegc)
+ dolog("GC: Invoking finalizers ...");
+
+ final_invoke();
+
+ if (opt_verbosegc)
+ dolog("GC: Invoking finalizers finished.");
+}
+
+
/* Informational getter functions *********************************************/
s8 gc_get_heap_size(void) { return heap_current_size; }
/* Development Break **********************************************************/
-#if 1 && defined(ENABLE_THREADS)
+#if 0 && defined(ENABLE_THREADS)
# error "GC does not work with threads enabled!"
#endif
#endif
-/* Global Variables ***********************************************************/
-
-static bool gc_pending;
-
-
/* Helper Macros **************************************************************/
#define GC_SET_FLAGS(obj, flags) ((obj)->hdrflags |= (flags))
((void *) (ptr) > (ptr_start) && (void *) (ptr) < (ptr_end))
+/* Global Variables ***********************************************************/
+
+extern bool gc_notify_finalizer;
+
+
/* Statistics *****************************************************************/
#if defined(ENABLE_STATISTICS)
#include "mark.h"
#include "region.h"
#include "mm/memory.h"
-#include "native/jni.h"
#include "src/native/include/java_lang_String.h" /* TODO: fix me! */
#include "toolbox/logging.h"
-#include "vm/exceptions.h"
#include "vm/global.h"
-/*#include "vm/options.h"*/
-#include "vm/jit/stacktrace.h"
/* Global Variables ***********************************************************/
#define GC_ALIGN(length,size) ((((length) + (size) - 1) / (size)) * (size))
+
void heap_init_objectheader(java_objectheader *o, u4 bytelength)
{
u4 wordcount;
if (GC_TEST_FLAGS(o, HDRFLAG_HASH_ATTACHED)) {
hashcode = *( (s4 *) ( ((u1 *) o) + get_object_size(o) - SIZEOF_VOID_P ) ); /* TODO: clean this up!!! */
- GC_LOG( dolog("GC: Hash re-taken: %d (0x%08x)", hashcode, hashcode); );
+ GC_LOG2( dolog("GC: Hash re-taken: %d (0x%08x)", hashcode, hashcode); );
} else {
GC_SET_FLAGS(o, HDRFLAG_HASH_TAKEN);
hashcode = (s4) (ptrint) o;
- GC_LOG( dolog("GC: Hash taken: %d (0x%08x)", hashcode, hashcode); );
+ GC_LOG2( dolog("GC: Hash taken: %d (0x%08x)", hashcode, hashcode); );
}
}
/* allocate the object in this region */
- p = region->ptr;
+ p = (java_objectheader *) region->ptr;
region->ptr += bytelength;
region->free -= bytelength;
if (p == NULL)
return NULL;
- /* TODO: can this be overwritten by cloning??? */
+ /* take care of finalization stuff */
if (finalizer != NULL) {
- GC_LOG( log_text("GC: Finalizer not yet implemented!"); );
+
+ /* set the header bit */
+ /* TODO: do we really need this??? */
+ /* TODO: can this be overwritten by cloning??? */
GC_SET_FLAGS(p, GC_FLAG_FINALIZER);
+
+ /* register the finalizer for this object */
+ final_register(p, finalizer);
}
return p;
/* TODO: can this be overwritten by cloning??? */
/* remember this object as uncollectable */
- GC_SET_FLAGS(p, GC_FLAG_UNCOLLECTABLE);
+ GC_SET_FLAGS(p, HDRFLAG_UNCOLLECTABLE);
return p;
}
GC_TEST_FLAGS(o, GC_FLAG_FINALIZER) ? "F" : " ",
GC_TEST_FLAGS(o, HDRFLAG_HASH_ATTACHED) ? "A" : " ",
GC_TEST_FLAGS(o, HDRFLAG_HASH_TAKEN) ? "T" : " ",
- GC_TEST_FLAGS(o, GC_FLAG_UNCOLLECTABLE) ? "U" : " ",
+ GC_TEST_FLAGS(o, HDRFLAG_UNCOLLECTABLE) ? "U" : " ",
GC_TEST_FLAGS(o, GC_FLAG_MARKED) ? "M" : " ");
}
#endif
printf("Heap-Dump:\n");
/* walk the region in a linear style */
- o = region->base;
- while ((void *) o < region->ptr) {
+ o = (java_objectheader *) region->base;
+ while (o < region->ptr) {
if (!marked_only || GC_IS_MARKED(o)) {
printf("\t");
/* TODO: maybe move this to global.h */
#define GC_FLAG_FINALIZER 0x40
-#define GC_FLAG_UNCOLLECTABLE HDRFLAG_UNCOLLECTABLE
-#define GC_FLAG_MARKED (HDRFLAG_MARK1 | HDRFLAG_MARK2)
-
-#define GC_IS_MARKED(obj) GC_TEST_FLAGS(obj, GC_FLAG_MARKED)
-#define GC_SET_MARKED(obj) GC_SET_FLAGS(obj, GC_FLAG_MARKED)
-#define GC_CLEAR_MARKED(obj) GC_CLEAR_FLAGS(obj, GC_FLAG_MARKED)
#define GC_SIZE_DUMMY 0xff
-
#if SIZEOF_VOID_P == 8
# define GC_GET_SIZE(obj) ((u4) (((obj)->hdrflags >> 56) & 0xff))
# define GC_SET_SIZE(obj, size) ((obj)->hdrflags |= ((u8) ((size) & 0xff)) << 56)
s4 get_object_size(java_objectheader *o);
-
#if !defined(NDEBUG)
+void heap_println_usage();
void heap_print_object(java_objectheader *o);
void heap_dump_region(regioninfo_t *region, bool marked_only);
#endif
#endif
#include "gc.h"
+#include "final.h"
#include "heap.h"
#include "mark.h"
+#include "rootset.h"
#include "mm/memory.h"
#include "toolbox/logging.h"
#include "vm/global.h"
-#include "vm/jit/replace.h"
-#include "vm/jit/stacktrace.h"
#include "vmcore/linker.h"
-/* mark_rootset_from_globals ***************************************************
-
- Searches global variables to compile the global root set out of references
- contained in them.
-
- SEARCHES IN:
- - global reference table (jni.c)
-
-*******************************************************************************/
-
-void mark_rootset_from_globals(rootset_t *rs)
-{
- GC_ASSERT(0);
-}
-
-
-/* mark_rootset_from_thread ****************************************************
-
- Searches the stack of the current thread for references and compiles a
- root set out of them.
-
- NOTE: uses dump memory!
-
- IN:
- TODO!!!
-
- OUT:
- TODO!!!
-
-*******************************************************************************/
-
-stacktracebuffer *stacktrace_create(threadobject* thread, bool rplpoints);
-void replace_read_executionstate(rplpoint *rp,
- executionstate_t *es,
- sourcestate_t *ss,
- bool topframe);
-void replace_write_executionstate(rplpoint *rp,
- executionstate_t *es,
- sourcestate_t *ss,
- bool topframe);
-
-void mark_rootset_from_thread(threadobject *thread, rootset_t *rs)
-{
- stacktrace_entry *ste;
- stacktracebuffer *stb;
- executionstate_t *es;
- sourcestate_t *ss;
- sourceframe_t *sf;
- rplpoint *rp;
- rplpoint *rp_search;
- s4 rpcount;
- int i;
-
- /* TODO: remove these */
- java_objectheader *o;
- int refcount;
-
- GC_LOG( printf("Walking down stack of current thread:\n");
- stacktrace_dump_trace(thread); );
-
- /* create empty execution state */
- es = DNEW(executionstate_t);
- es->pc = 0;
- es->sp = 0;
- es->pv = 0;
- es->code = NULL;
-
- /* TODO: we assume we are in a native and in current thread! */
- ss = replace_recover_source_state(NULL, NULL, es);
-
- /* print our full source state */
- GC_LOG( replace_sourcestate_println(ss); );
-
- /* initialize the rootset struct */
- GC_ASSERT(rs);
- rs->thread = thread;
- rs->ss = ss;
- rs->es = es;
- rs->stb = stb;
- rs->refcount = 0;
-
- /* now inspect the source state to compile the root set */
- refcount = rs->refcount;
- for (sf = ss->frames; sf != NULL; sf = sf->down) {
-
- GC_ASSERT(sf->javastackdepth == 0);
-
- for (i = 0; i < sf->javalocalcount; i++) {
-
- if (sf->javalocaltype[i] != TYPE_ADR)
- continue;
-
- o = sf->javalocals[i].a;
-
- /* check for outside or null pointer */
- if (!POINTS_INTO(o, heap_region_main->base, heap_region_main->ptr))
- continue;
-
- /* add this reference to the root set */
- GC_LOG2( printf("Found Reference: %p\n", (void *) o); );
- GC_ASSERT(refcount < RS_REFS); /* TODO: UGLY!!! */
- rs->refs[refcount] = (java_objectheader **) &( sf->javalocals[i] );
-
- refcount++;
-
- }
-
- }
-
- /* remeber how many references there are inside this root set */
- rs->refcount = refcount;
-
- GC_LOG( printf("Walking done.\n"); );
-}
-
-
-void mark_rootset_writeback(rootset_t *rs)
-{
- sourcestate_t *ss;
- executionstate_t *es;
- rplpoint *rp;
- stacktracebuffer *stb;
- stacktrace_entry *ste;
- int i;
-
- ss = rs->ss;
- es = rs->es;
-
- replace_build_execution_state_intern(ss, es);
-
-}
-
-
-/* mark_recursice **************************************************************
+/* mark_recursive **************************************************************
Recursively mark all objects (including this) which are referenced.
+ TODO, XXX: We need to implement a non-recursive version of this!!!
+
IN:
o.....heap-object to be marked (either OBJECT or ARRAY)
/* uncollectable objects should never get marked this way */
/* the reference should point into the heap */
GC_ASSERT(o);
- GC_ASSERT(!GC_TEST_FLAGS(o, GC_FLAG_UNCOLLECTABLE));
+ GC_ASSERT(!GC_TEST_FLAGS(o, HDRFLAG_UNCOLLECTABLE));
GC_ASSERT(POINTS_INTO(o, start, end));
/* mark this object */
c = t->class;
GC_ASSERT(c);
- /* TODO: should we mark the class of the object as well? */
- /*GC_ASSERT(GC_IS_MARKED((java_objectheader *) c));*/
-
/* does this object has pointers? */
/* TODO: check how often this happens, maybe remove this check! */
/*if (!GC_IS_REFERENCING(o))
}
+/* mark_classes ****************************************************************
+
+ Marks all the references from classinfo structures (static fields)
+
+ IN:
+ start.....Region to be marked starts here
+ end.......Region to be marked ends here
+
+*******************************************************************************/
+
void mark_classes(void *start, void *end)
{
java_objectheader *ref;
void *sys_start, *sys_end;
int i;
- GC_LOG( printf("Marking from classes\n"); );
+ GC_LOG( dolog("GC: Marking from classes ..."); );
/* TODO: cleanup!!! */
sys_start = heap_region_sys->base;
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)
{
java_objectheader *ref;
+ final_entry *fe;
+ u4 f_type;
int i;
GCSTAT_INIT(gcstat_mark_count);
/* recursively mark all references from classes */
mark_classes(heap_region_main->base, heap_region_main->ptr);
- GC_LOG( printf("Marking from rootset (%d entries)\n", rs->refcount); );
+ while (rs) {
+ GC_LOG( dolog("GC: Marking from rootset (%d entries) ...", rs->refcount); );
- /* recursively mark all references of the rootset */
- GCSTAT_COUNT_MAX(gcstat_mark_depth, gcstat_mark_depth_max);
- for (i = 0; i < rs->refcount; i++) {
+ /* recursively mark all references of the rootset */
+ GCSTAT_COUNT_MAX(gcstat_mark_depth, gcstat_mark_depth_max);
+ for (i = 0; i < rs->refcount; i++) {
- ref = *( rs->refs[i] );
- mark_recursive(ref);
+ /* is this a marking reference? */
+ if (!rs->ref_marks[i])
+ continue;
+
+ /* do the marking here */
+ ref = *( rs->refs[i] );
+ mark_recursive(ref);
+ }
+ GCSTAT_DEC(gcstat_mark_depth);
+
+ rs = rs->next;
}
- GCSTAT_DEC(gcstat_mark_depth);
- GC_ASSERT(gcstat_mark_depth == 0);
- GC_ASSERT(gcstat_mark_depth_max > 0);
-}
+ /* objects with finalizers will also be marked here. if they have not been
+ * 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) {
+ f_type = fe->type;
+ ref = fe->o;
+ /* object not marked, but was reachable before */
+ if (f_type == FINAL_REACHABLE && !GC_IS_MARKED(ref)) {
+ GC_LOG2( printf("Finalizer triggered for: ");
+ heap_print_object(ref); printf("\n"); );
-#if !defined(NDEBUG)
-void mark_rootset_print(rootset_t *rs)
-{
- java_objectheader *o;
- int i;
+ /* object is now reclaimable */
+ fe->type = FINAL_RECLAIMABLE;
+
+ /* keep the object alive until finalizer finishes */
+ mark_recursive(ref);
+
+ /* notify the finalizer after collection finished */
+ gc_notify_finalizer = true;
+ } else
+
+#if 0
+ /* object not marked, but was not finalized yet */
+ if (f_type == FINAL_RECLAIMABLE && !GC_IS_MARKED(ref)) {
+ GC_LOG2( printf("Finalizer not yet started for: ");
+ heap_print_object(ref); printf("\n"); );
+
+ /* keep the object alive until finalizer finishes */
+ mark_recursive(ref);
+ } else
- printf("Root Set:\n");
+ /* object not marked, but was not finalized yet */
+ if (f_type == FINAL_RECLAIMABLE && !GC_IS_MARKED(ref)) {
+ GC_LOG2( printf("Finalizer not yet finished for: ");
+ heap_print_object(ref); printf("\n"); );
- printf("\tThread: %p\n", rs->thread);
- printf("\tReferences (%d):\n", rs->refcount);
+ /* keep the object alive until finalizer finishes */
+ mark_recursive(ref);
+ } else
+
+ /* object marked, but finalizer already ran */
+ /* TODO: nothing has to be done here, remove me! */
+ if (f_type == FINAL_FINALIZED && GC_IS_MARKED(ref)) {
+ GC_LOG2( printf("Finalizer resurrected object: ");
+ heap_print_object(ref); printf("\n"); );
+
+ /* do nothing */
+ } else
- for (i = 0; i < rs->refcount; i++) {
+ /* object not marked, finalizer already ran */
+ if (f_type == FINAL_FINALIZED && !GC_IS_MARKED(ref)) {
+ GC_LOG2( printf("Finalizer already finished!\n"); );
+
+ /* do nothing */
+ } else
+#endif
- o = *( rs->refs[i] );
+ /* object marked, finalizer not yet run */
+ if (f_type == FINAL_REACHABLE && GC_IS_MARKED(ref)) {
+ /* do nothing */
+ } else
- /*printf("\t\tReference at %p points to ...\n", (void *) rs->refs[i]);*/
- printf("\t\t");
- heap_print_object(o);
- printf("\n");
+ /* case not yet covered */
+ { assert(0); }
+ fe = list_next_unsynced(final_list, fe);
}
+ GC_LOG( dolog("GC: Marking finished."); );
+
+ GC_ASSERT(gcstat_mark_depth == 0);
+ GC_ASSERT(gcstat_mark_depth_max > 0);
}
-#endif
/*
#ifndef _MARK_H
#define _MARK_H
-typedef struct rootset_t rootset_t;
#include "config.h"
#include "vm/types.h"
-#if defined(ENABLE_THREADS)
-# include "threads/native/threads.h"
-#else
-/*# include "threads/none/threads.h"*/
-#endif
+#include "rootset.h"
-#include "vm/jit/replace.h"
-#include "vm/jit/stacktrace.h"
-#include "vmcore/method.h"
+/* Helper Macros **************************************************************/
+#define GC_FLAG_MARKED (HDRFLAG_MARK1 | HDRFLAG_MARK2)
-/* Structures *****************************************************************/
-
-#define RS_REFS 10
-
-/* rootset is passed as array of pointers, which point to the location of
- the reference */
-
-struct rootset_t {
- threadobject *thread; /* thread this rootset belongs to */
- sourcestate_t *ss; /* sourcestate of the thread */
- executionstate_t *es; /* executionstate of the thread */
- stacktracebuffer *stb; /* stacktrace of the thread */
- s4 refcount; /* number of references */
- java_objectheader **refs[RS_REFS]; /* list of references */
-};
+#define GC_IS_MARKED(obj) GC_TEST_FLAGS(obj, GC_FLAG_MARKED)
+#define GC_SET_MARKED(obj) GC_SET_FLAGS(obj, GC_FLAG_MARKED)
+#define GC_CLEAR_MARKED(obj) GC_CLEAR_FLAGS(obj, GC_FLAG_MARKED)
/* Prototypes *****************************************************************/
-void mark_rootset_from_thread(threadobject *thread, rootset_t *rs);
void mark_me(rootset_t *rs);
--- /dev/null
+/* mm/cacao-gc/rootset.c - GC module for root set management
+
+ 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
+
+ This file is part of CACAO.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+ Contact: cacao@cacaojvm.org
+
+ Authors: Michael Starzinger
+
+ $Id$
+
+*/
+
+
+#include "config.h"
+
+#if defined(ENABLE_THREADS)
+# include "threads/native/threads.h"
+#else
+/*# include "threads/none/threads.h"*/
+#endif
+
+#include "gc.h"
+#include "final.h"
+#include "heap.h"
+#include "mark.h"
+#include "mm/memory.h"
+#include "toolbox/logging.h"
+#include "vm/global.h"
+#include "vm/jit/replace.h"
+#include "vm/jit/stacktrace.h"
+#include "vmcore/linker.h"
+#include "vmcore/loader.h"
+
+
+rootset_t *rootset_create(void)
+{
+ rootset_t *rs;
+
+ rs = DNEW(rootset_t);
+
+ rs->next = NULL;
+ rs->refcount = 0;
+
+ return rs;
+}
+
+
+/* rootset_from_globals ********************************************************
+
+ Searches global variables to compile the global root set out of references
+ contained in them.
+
+ SEARCHES IN:
+ - classloader objects (loader.c)
+ - global reference table (jni.c)
+ - finalizer entries (final.c)
+
+*******************************************************************************/
+
+void rootset_from_globals(rootset_t *rs)
+{
+ hashtable_classloader_entry *cle;
+ final_entry *fe;
+ int refcount;
+ int i;
+
+ GC_LOG( dolog("GC: Acquiring Root-Set from globals ..."); );
+
+ /* initialize the rootset struct */
+ GC_ASSERT(rs);
+ GC_ASSERT(rs->refcount == 0);
+ rs->thread = ROOTSET_DUMMY_THREAD;
+ rs->ss = NULL;
+ rs->es = NULL;
+ rs->stb = NULL;
+
+ /* walk through all classloaders */
+ refcount = rs->refcount;
+ for (i = 0; i < hashtable_classloader->size; i++) {
+ cle = hashtable_classloader->ptr[i];
+
+ while (cle) {
+
+ GC_LOG2( printf("Found Classloader: %p\n", (void *) cle->object); );
+
+ /* add this classloader to the root set */
+ GC_ASSERT(refcount < RS_REFS); /* TODO: UGLY!!! */
+ rs->refs[refcount] = &( cle->object );
+ rs->ref_marks[refcount] = true;
+ refcount++;
+
+ cle = cle->hashlink;
+ }
+ }
+
+ /* 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) {
+
+ GC_LOG2( printf("Found Finalizer Entry: %p\n", (void *) fe->o); );
+
+ /* add this object with finalizer to the root set */
+ GC_ASSERT(refcount < RS_REFS); /* TODO: UGLY!!! */
+ rs->refs[refcount] = &( fe->o );
+ rs->ref_marks[refcount] = false;
+ refcount++;
+
+ fe = list_next_unsynced(final_list, fe);
+ }
+
+ /* remeber how many references there are inside this root set */
+ rs->refcount = refcount;
+
+}
+
+
+/* rootset_from_thread *********************************************************
+
+ Searches the stack of the passed thread for references and compiles a
+ root set out of them.
+
+ NOTE: uses dump memory!
+
+ IN:
+ thread...TODO
+ rs.......TODO
+
+ OUT:
+ TODO!!!
+
+*******************************************************************************/
+
+void rootset_from_thread(threadobject *thread, rootset_t *rs)
+{
+ stacktracebuffer *stb;
+ executionstate_t *es;
+ sourcestate_t *ss;
+ sourceframe_t *sf;
+ rplpoint *rp;
+ s4 rpcount;
+ int i;
+
+ /* TODO: remove these */
+ java_objectheader *o;
+ int refcount;
+
+ GC_LOG( dolog("GC: Acquiring Root-Set from thread (%p) ...", (void *) thread); );
+
+ GC_LOG2( printf("Stacktrace of current thread:\n");
+ stacktrace_dump_trace(thread); );
+
+ /* create empty execution state */
+ es = DNEW(executionstate_t);
+ es->pc = 0;
+ es->sp = 0;
+ es->pv = 0;
+ es->code = NULL;
+
+ /* TODO: we assume we are in a native and in current thread! */
+ ss = replace_recover_source_state(NULL, NULL, es);
+
+ /* print our full source state */
+ GC_LOG2( replace_sourcestate_println(ss); );
+
+ /* initialize the rootset struct */
+ GC_ASSERT(rs);
+ GC_ASSERT(rs->refcount == 0);
+ rs->thread = thread;
+ rs->ss = ss;
+ rs->es = es;
+ rs->stb = stb;
+
+ /* now inspect the source state to compile the root set */
+ refcount = rs->refcount;
+ for (sf = ss->frames; sf != NULL; sf = sf->down) {
+
+ GC_ASSERT(sf->javastackdepth == 0);
+
+ for (i = 0; i < sf->javalocalcount; i++) {
+
+ if (sf->javalocaltype[i] != TYPE_ADR)
+ continue;
+
+ o = sf->javalocals[i].a;
+
+ /* check for outside or null pointer */
+ if (!POINTS_INTO(o, heap_region_main->base, heap_region_main->ptr))
+ continue;
+
+ /* add this reference to the root set */
+ GC_LOG2( printf("Found Reference: %p\n", (void *) o); );
+ GC_ASSERT(refcount < RS_REFS); /* TODO: UGLY!!! */
+ rs->refs[refcount] = (java_objectheader **) &( sf->javalocals[i] );
+ rs->ref_marks[refcount] = true;
+
+ refcount++;
+
+ }
+
+ }
+
+ /* remeber how many references there are inside this root set */
+ rs->refcount = refcount;
+
+}
+
+
+void rootset_writeback(rootset_t *rs)
+{
+ sourcestate_t *ss;
+ executionstate_t *es;
+ rplpoint *rp;
+ stacktracebuffer *stb;
+
+ /* TODO: only a dirty hack! */
+ GC_ASSERT(rs->next->thread == THREADOBJECT);
+ ss = rs->next->ss;
+ es = rs->next->es;
+
+ replace_build_execution_state_intern(ss, es);
+
+}
+
+
+/* Debugging ******************************************************************/
+
+#if !defined(NDEBUG)
+void rootset_print(rootset_t *rs)
+{
+ java_objectheader *o;
+ int i;
+
+ /* walk through all rootsets in the chain */
+ printf("Root Set Chain:\n");
+ while (rs) {
+
+ /* print the thread this rootset belongs to */
+ if (rs->thread == ROOTSET_DUMMY_THREAD) {
+ printf("\tGlobal Root Set:\n");
+ } else {
+#if defined(ENABLE_THREADS)
+ printf("\tLocal Root Set with Thread-Id %p:\n", (void *) rs->thread->tid);
+#else
+ printf("\tLocal Root Set:\n");
+#endif
+ }
+
+ /* print the references in this rootset */
+ printf("\tReferences (%d):\n", rs->refcount);
+ for (i = 0; i < rs->refcount; i++) {
+
+ o = *( rs->refs[i] );
+
+ /*printf("\t\tReference at %p points to ...\n", (void *) rs->refs[i]);*/
+ printf("\t\t");
+ if (rs->ref_marks[i])
+ printf("MRK");
+ else
+ printf("UPD");
+ printf(" ");
+ heap_print_object(o);
+ printf("\n");
+
+ }
+
+ rs = rs->next;
+
+ }
+
+}
+#endif
+
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
--- /dev/null
+/* mm/cacao-gc/rootset.h - GC header for root set management
+
+ 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
+
+ This file is part of CACAO.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+ Contact: cacao@cacaojvm.org
+
+ Authors: Michael Starzinger
+
+ $Id$
+
+*/
+
+
+#ifndef _ROOTSET_H
+#define _ROOTSET_H
+
+typedef struct rootset_t rootset_t;
+
+#include "config.h"
+#include "vm/types.h"
+
+#if defined(ENABLE_THREADS)
+# include "threads/native/threads.h"
+#else
+/*# include "threads/none/threads.h"*/
+#endif
+
+#include "vm/jit/replace.h"
+#include "vm/jit/stacktrace.h"
+
+#include "vmcore/method.h"
+
+
+/* Structures *****************************************************************/
+
+#define ROOTSET_DUMMY_THREAD ((threadobject *) (ptrint) -1)
+#define RS_REFS 32
+
+/* rootset is passed as array of pointers, which point to the location of
+ the reference */
+
+struct rootset_t {
+ rootset_t *next; /* link to the next chain element */
+ threadobject *thread; /* thread this rootset belongs to */
+ sourcestate_t *ss; /* sourcestate of the thread */
+ executionstate_t *es; /* executionstate of the thread */
+ stacktracebuffer *stb; /* stacktrace of the thread */
+ s4 refcount; /* number of references */
+ java_objectheader **refs[RS_REFS]; /* list of references */
+ bool ref_marks[RS_REFS]; /* indicates if a reference marks */
+};
+
+
+/* Prototypes *****************************************************************/
+
+rootset_t *rootset_create(void);
+void rootset_from_globals(rootset_t *rs);
+void rootset_from_thread(threadobject *thread, rootset_t *rs);
+void rootset_writeback(rootset_t *rs);
+
+#if !defined(NDEBUG)
+void rootset_print(rootset_t *rs);
+#endif
+
+
+#endif /* _ROOTSET_H */
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
Changes:
- $Id: md-asm.h 7355 2007-02-14 10:57:32Z twisti $
+ $Id: md-asm.h 7300 2007-02-07 22:06:53Z pm $
*/