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 "threads/lock-common.h"
+
#include "gc.h"
+#include "final.h"
#include "heap.h"
#include "mark.h"
#include "region.h"
#include "mm/memory.h"
-#include "src/native/include/java_lang_String.h" /* TODO: fix me! */
+#include "native/include/java_lang_String.h"
+#include "native/llni.h"
#include "toolbox/logging.h"
#include "vm/global.h"
+#include "vm/stringlocal.h"
+#include "vm/vm.hpp"
+#include "vmcore/options.h"
+#include "vmcore/rt-timing.h"
/* Global Variables ***********************************************************/
-/*void *heap_base;*/ /* pointer to the base of the heap */
-/*void *heap_ptr;*/ /* current allocation ptr for linear alloc */
s4 heap_current_size; /* current size of the heap */
s4 heap_maximal_size; /* maximal size of the heap */
-s4 heap_free_size; /* free bytes on the heap */
-s4 heap_used_size; /* used bytes on the heap */
regioninfo_t *heap_region_sys;
regioninfo_t *heap_region_main;
-/* Helper Macros **************************************************************/
-
-#define GC_ALIGN_SIZE SIZEOF_VOID_P
-#define GC_ALIGN(length,size) ((((length) + (size) - 1) / (size)) * (size))
-
-
-
-void heap_init_objectheader(java_objectheader *o, u4 bytelength)
+void heap_init_objectheader(java_object_t *o, u4 bytelength)
{
u4 wordcount;
}
-s4 heap_increase_size() {
- void *p;
- s4 increasesize;
- s4 newsize;
+void heap_update_references(rootset_t *rs, regioninfo_t *region, u4 offset)
+{
+ java_object_t *o;
+ java_object_t *ref;
+ java_object_t **refptr;
+ u1* start;
+ u1* end;
+ int i;
+
+ GC_LOG( dolog("GC: Updating all references (offset=%x) ...", offset); );
+
+ start = region->base - offset;
+ end = region->ptr - offset;
+ GC_LOG( printf("Region previously was [ %p ; %p]\n", start, end); );
+
+ GC_LOG2( printf("updating in root-sets ..."); );
+
+ /* walk through all rootsets */
+ while (rs) {
+
+ /* walk through the references of this rootset */
+ for (i = 0; i < rs->refcount; i++) {
+
+ /* load the reference */
+ refptr = rs->refs[i].ref;
+ ref = *( refptr );
+
+ GC_LOG2( printf("\troot pointer to %p\n", (void *) ref); );
+
+ /* update the references */
+ if (POINTS_INTO(ref, start, end))
+ *refptr = ((u1 *) ref) + offset;
+
+ }
+
+ /* skip to next rootset in chain */
+ rs = rs->next;
+
+ }
+
+
+ o = region->base;
+ while (o < region->ptr) {
+
+ GC_LOG2( printf("updating in %p ...\n", (void *) o); );
+
+ if (IS_ARRAY(o)) {
+
+ /* walk through the references of an Array */
+ FOREACH_ARRAY_REF(o,ref,refptr,
- /* TODO: locking for threads!!! */
+ GC_LOG2( printf("\tarray-entry %p -> %p\n", (void *) ref, ((u1 *) ref) + offset); );
+
+ if (POINTS_INTO(ref, start, end))
+ *refptr = ((u1 *) ref) + offset;
+
+ );
+
+ } else {
+
+ /* walk through the references of an Object */
+ FOREACH_OBJECT_REF(o,ref,refptr,
+
+ GC_LOG2( printf("\tobject-field %p -> %p\n", (void *) ref, ((u1 *) ref) + offset); );
+
+ if (POINTS_INTO(ref, start, end))
+ *refptr = ((u1 *) ref) + offset;
+
+ );
+
+ }
+
+ /* skip to next object */
+ o = ((u1 *) o) + get_object_size(o);
+
+ }
+
+}
+
+
+void heap_increase_size(rootset_t *rs)
+{
+ s4 newsize;
+ s4 resize_offset;
/* only a quick sanity check */
GC_ASSERT(heap_current_size <= heap_maximal_size);
/* check if we are allowed to enlarge the heap */
if (heap_current_size == heap_maximal_size)
- exceptions_throw_outofmemory_exit();
+ vm_abort("heap_increase_size: reached maximal heap size: out of memory");
- /* TODO: find out how much to increase the heap??? */
- increasesize = heap_maximal_size - heap_current_size;
- GC_LOG( dolog("GC: Increasing Heap Size by %d", increasesize); );
+ /* find out how much to increase the heap??? */
+ newsize = 2 * heap_current_size; /* XXX TODO: better heuristic here */
+ dolog("GC: Increasing Heap Size to %d bytes", newsize); /* XXX remove me */
+ GC_LOG( dolog("GC: Increasing Heap Size to %d bytes", newsize); );
- /* allocate new heap from the system */
- newsize = heap_current_size + increasesize;
- p = malloc(newsize);
+ /* resize the main heap region */
+ resize_offset = region_resize(heap_region_main, newsize);
- /* check if the newly allocated heap exists */
- if (p == NULL)
- exceptions_throw_outofmemory_exit();
-
- /* TODO: copy the old content to the new heap */
- /* TODO: find a complete rootset and update it to the new position */
- /* TODO: free the old heap */
+ /* update all references if necesarry */
+ if (resize_offset != 0)
+ heap_update_references(rs, heap_region_main, resize_offset);
+ else
+ dolog("GC WARNING: References are not updated after heap resizing!");
/* set the new values */
- /*heap_ptr = p + (heap_ptr - heap_base);
- heap_base = p;*/
heap_current_size = newsize;
- heap_free_size += increasesize;
GC_LOG( dolog("GC: Increasing Heap Size was successful");
heap_println_usage(); );
/* only a quick sanity check */
GC_ASSERT(heap_current_size <= heap_maximal_size);
- return increasesize;
}
-s4 heap_get_hashcode(java_objectheader *o)
+s4 heap_get_hashcode(java_object_t *o)
{
s4 hashcode;
}
-java_objectheader *heap_alloc_intern(u4 bytelength, regioninfo_t *region)
+static java_object_t *heap_alloc_intern(u4 bytelength, regioninfo_t *region, bool collect)
{
- java_objectheader *p;
+ java_object_t *p;
/* only a quick sanity check */
GC_ASSERT(region);
- GC_ASSERT(bytelength >= sizeof(java_objectheader));
+ GC_ASSERT(bytelength >= sizeof(java_object_t));
+
+#if !defined(NDEBUG) && defined(ENABLE_THREADS)
+ /* check the current VM state for sanity */
+ GC_ASSERT(!THREADOBJECT->gc_critical);
+ GC_ASSERT(THREADOBJECT->flags & THREAD_FLAG_IN_NATIVE);
+#endif
/* align objects in memory */
bytelength = GC_ALIGN(bytelength, GC_ALIGN_SIZE);
+ /* lock the region */
+ LOCK_MONITOR_ENTER(region);
+
+#if !defined(NDEBUG)
+ /* heavy stress test */
+ if (opt_GCStress && collect)
+ gc_collect(0);
+#endif
+
/* check for sufficient free space */
if (bytelength > region->free) {
- dolog("GC: Region out of memory!");
- /* TODO: change this to gc_collect() !!! */
- /*gc_call();*/
- return NULL;
+ dolog("GC: Region out of memory! (collect=%d)", collect);
+
+ if (collect) {
+ gc_collect(0);
+#if 0
+ GC_ASSERT(region->free >= bytelength);
+#else
+ if (region->free < bytelength) {
+ dolog("GC: OOM OOM OOM OOM OOM OOM OOM OOM OOM OOM");
+ exceptions_throw_outofmemoryerror();
+ return NULL;
+ }
+#endif
+ } else
+ return NULL;
}
/* allocate the object in this region */
- p = (java_objectheader *) region->ptr;
+ p = (java_object_t *) region->ptr;
region->ptr += bytelength;
region->free -= bytelength;
- /*heap_free_size -= bytelength;
- heap_used_size += bytelength;*/
+ /* unlock the region */
+ LOCK_MONITOR_EXIT(region);
/* clear allocated memory region */
GC_ASSERT(p);
}
-/* heap_allocate ***************************************************************
+/* heap_alloc ******************************************************************
Allocates memory on the Java heap.
*******************************************************************************/
-void *heap_allocate(u4 bytelength, u4 references, methodinfo *finalizer)
+void *heap_alloc(u4 size, u4 references, methodinfo *finalizer, bool collect)
{
- java_objectheader *p;
+ java_object_t *p;
+ java_handle_t *h;
+#if defined(ENABLE_RT_TIMING)
+ struct timespec time_start, time_end;
+#endif
- /* We can't use a bool here for references, as it's passed as a
- bitmask in builtin_new. Thus we check for != 0. */
+ RT_TIMING_GET_TIME(time_start);
- p = heap_alloc_intern(bytelength, heap_region_main);
+ p = heap_alloc_intern(size, heap_region_main, collect);
if (p == NULL)
return NULL;
- /* take care of finalization stuff */
- if (finalizer != NULL) {
-
- /* set the header bit */
- /* TODO: do we really need this??? */
- /* TODO: can this be overwritten by cloning??? */
- GC_SET_FLAGS(p, GC_FLAG_FINALIZER);
+#if defined(GCCONF_HDRFLAG_REFERENCING)
+ /* We can't use a bool here for references, as it's passed as a
+ bitmask in builtin_new. Thus we check for != 0. */
+ if (references != 0) {
+ GC_SET_FLAGS(p, HDRFLAG_REFERENCING);
+ }
+#endif
- /* register the finalizer for this object */
+ /* register the finalizer for this object */
+ if (finalizer != NULL) {
final_register(p, finalizer);
}
- return p;
+ h = LLNI_WRAP(p);
+
+ RT_TIMING_GET_TIME(time_end);
+ RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_GC_ALLOC);
+
+ return h;
}
-void *heap_alloc_uncollectable(u4 bytelength)
+void *heap_alloc_uncollectable(u4 size)
{
- java_objectheader *p;
+ java_object_t *p;
/* loader.c does this a lot for classes with fieldscount equal zero */
- if (bytelength == 0)
+ if (size == 0)
return NULL;
- p = heap_alloc_intern(bytelength, heap_region_sys);
+ p = heap_alloc_intern(size, heap_region_sys, false);
if (p == NULL)
return NULL;
#if !defined(NDEBUG)
void heap_println_usage()
{
- printf("Current Heap Usage: Size=%d Free=%d Used=%d\n",
- heap_current_size, heap_free_size, heap_used_size);
+ printf("Current Heap Usage: Size=%d Free=%d\n",
+ heap_current_size, heap_region_main->free);
- GC_ASSERT(heap_current_size == heap_free_size + heap_used_size);
+ GC_ASSERT(heap_current_size == heap_region_main->size);
}
#endif
#if !defined(NDEBUG)
-void heap_print_object_flags(java_objectheader *o)
+void heap_print_object_flags(java_object_t *o)
{
- printf("0x%02x [%s%s%s%s%s]",
+ printf("0x%02x [%s%s%s%s]",
GC_GET_SIZE(o),
- 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, HDRFLAG_UNCOLLECTABLE) ? "U" : " ",
#if !defined(NDEBUG)
-void heap_print_object(java_objectheader *o)
+void heap_print_object(java_object_t *o)
{
- java_arrayheader *a;
- classinfo *c;
+ java_array_t *a;
+ classinfo *c;
/* check for null pointers */
if (o == NULL) {
}
/* print general information */
- printf("%p: ", (void *) o);
+#if SIZEOF_VOID_P == 8
+ printf("0x%016llx: ", (unsigned long long) o);
+#else
+ printf("0x%08lx: ", (unsigned long) o);
+#endif
+
+ /* check for invalid heap references */
+ if (!POINTS_INTO(o, heap_region_main->base, heap_region_main->end) &&
+ !POINTS_INTO(o, heap_region_sys->base, heap_region_sys->end))
+ {
+ printf("<<< No Heap Reference >>>");
+ return;
+ }
+
+ /* print object flags */
heap_print_object_flags(o);
printf(" ");
+ GC_ASSERT(o->vftbl);
+
/* TODO */
/* maybe this is not really an object */
if (/*IS_CLASS*/ o->vftbl->class == class_java_lang_Class) {
} else if (/*IS_ARRAY*/ o->vftbl->arraydesc != NULL) {
/* get the array information */
- a = (java_arrayheader *) o;
+ a = (java_array_t *) o;
c = o->vftbl->class;
/* print the array information */
#if !defined(NDEBUG)
void heap_dump_region(regioninfo_t *region, bool marked_only)
{
- java_objectheader *o;
- u4 o_size;
+ java_object_t *o;
+ u4 o_size;
/* some basic sanity checks */
- GC_ASSERT(region->base < region->ptr);
+ GC_ASSERT(region->base <= region->ptr);
printf("Heap-Dump:\n");
/* walk the region in a linear style */
- o = (java_objectheader *) region->base;
+ o = (java_object_t *) region->base;
while (o < region->ptr) {
if (!marked_only || GC_IS_MARKED(o)) {
#endif
-s4 get_object_size(java_objectheader *o)
+s4 get_object_size(java_object_t *o)
{
- java_arrayheader *a;
- classinfo *c;
- s4 o_size;
+ java_array_t *a;
+ classinfo *c;
+ s4 o_size;
/* we can assume someone initialized the header */
GC_ASSERT(o->hdrflags != 0);
} else if (/*IS_ARRAY*/ o->vftbl->arraydesc != NULL) {
/* compute size of this array */
- a = (java_arrayheader *) o;
+ a = (java_array_t *) o;
c = o->vftbl->class;
o_size = c->vftbl->arraydesc->dataoffset +
a->size * c->vftbl->arraydesc->componentsize;
}
-java_objectheader *next;
-
-void *gc_copy_forward(java_objectheader *o, void *src_start, void *src_end)
-{
- s4 o_size;
-
- if (POINTS_INTO(o, src_start, src_end)) {
-
- /* update all references which point into the source region */
-
- /* NOTE: we use the marking bit here to mark object which have already
- * been copied; in such a case the *vftbl contains the location of
- * the copy */
- if (GC_IS_MARKED(o)) {
-
- /* return the location of an already existing copy */
- return o->vftbl;
-
- } else {
-
- /* calculate the size of the object to be copied */
- o_size = get_object_size(o);
-
- /* copy the object pointed to by O to location NEXT */
- memcpy(next, o, o_size);
-
- /* remember where the copy is located */
- o->vftbl = (void *) next;
-
- /* increment NEXT to point past the copy of the object */
- next = ((u1 *) next) + o_size;
-
- /* return the location of the copy */
- return o->vftbl;
-
- }
-
- } else {
-
- /* do not change references not pointing into the source region */
- return o;
-
- }
-}
-
-
-void gc_copy(regioninfo_t *src, regioninfo_t *dst, rootset_t *rs)
-{
- java_objectheader *scan;
- /*java_objectheader *next;*/
- /*classinfo *c;*/
- java_objectheader *ref_old;
- java_objectheader *ref_new;
- int i;
-
- /* initialize the scan and next pointer */
- scan = (java_objectheader *) dst->base;
- next = (java_objectheader *) dst->base;
-
- /* for each root pointer R: replace R with forward(R) */
- for (i = 0; i < rs->refcount; i++) {
-
- ref_old = *( rs->refs[i] );
- GC_LOG( printf("Will forward: ");
- heap_print_object(ref_old);
- printf("\n"); );
-
- ref_new = gc_copy_forward(ref_old, src->base, src->end);
-
- *( rs->refs[i] ) = ref_new;
- GC_LOG( printf("New location: ");
- heap_print_object(ref_new);
- printf("\n"); );
- }
-
- /* update all references for objects in the destination region.
- * when scan catches up with next, the algorithm is finished */
- while (scan < next)
- {
- /* TODO: implement me! */
- GC_LOG( printf("Will also forward pointers in ");
- heap_print_object(scan); printf("\n"); );
-
- scan = ((u1 *) scan) + get_object_size(scan);
- }
-
- /* some basic assumptions */
- GC_ASSERT(scan == next);
- GC_ASSERT(scan < dst->end);
-}
-
-
/*
* 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