* src/vm/vm.c, src/vm/vm.h: Moved to .cpp.
[cacao.git] / src / mm / cacao-gc / heap.c
index 21293454a7913726807fba6d368bffa9a4bcc0f1..ae5adfd36fcbdc86c50e3d1a3de53a12c533d795 100644 (file)
    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;
 
@@ -93,41 +84,114 @@ void heap_init_objectheader(java_objectheader *o, u4 bytelength)
 }
 
 
-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(); );
@@ -135,11 +199,10 @@ s4 heap_increase_size() {
        /* 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;
 
@@ -167,32 +230,58 @@ s4 heap_get_hashcode(java_objectheader *o)
 }
 
 
-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);
@@ -205,49 +294,58 @@ java_objectheader *heap_alloc_intern(u4 bytelength, regioninfo_t *region)
 }
 
 
-/* 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;
@@ -272,20 +370,19 @@ void heap_free(void *p)
 #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" : " ",
@@ -295,10 +392,10 @@ void heap_print_object_flags(java_objectheader *o)
 
 
 #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) {
@@ -307,10 +404,26 @@ void heap_print_object(java_objectheader *o)
        }
 
        /* 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) {
@@ -325,7 +438,7 @@ void heap_print_object(java_objectheader *o)
        } 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 */
@@ -357,16 +470,16 @@ void heap_print_object(java_objectheader *o)
 #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)) {
@@ -388,11 +501,11 @@ void heap_dump_region(regioninfo_t *region, bool marked_only)
 #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);
@@ -414,7 +527,7 @@ s4 get_object_size(java_objectheader *o)
 
                } 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;
@@ -439,98 +552,6 @@ s4 get_object_size(java_objectheader *o)
 }
 
 
-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