1 /* mm/cacao-gc/heap.c - GC module for heap management
3 Copyright (C) 2006, 2008
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6 This file is part of CACAO.
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2, or (at
11 your option) any later version.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
29 #include "threads/lock-common.h"
36 #include "mm/memory.h"
37 #include "native/include/java_lang_String.h"
38 #include "native/llni.h"
39 #include "toolbox/logging.h"
41 #include "vm/global.h"
42 #include "vm/options.h"
43 #include "vm/rt-timing.h"
44 #include "vm/string.hpp"
48 /* Global Variables ***********************************************************/
50 s4 heap_current_size; /* current size of the heap */
51 s4 heap_maximal_size; /* maximal size of the heap */
52 regioninfo_t *heap_region_sys;
53 regioninfo_t *heap_region_main;
56 void heap_init_objectheader(java_object_t *o, u4 bytelength)
60 /* initialize the header flags */
66 /* calculate the wordcount as stored in the header */
67 /* TODO: improve this to save wordcount and without header bytes */
68 if ((bytelength & 0x03) == 0) {
69 GC_ASSERT((bytelength & 0x03) == 0);
70 wordcount = (bytelength >> 2);
71 GC_ASSERT(wordcount != 0);
73 wordcount = GC_SIZE_DUMMY;
76 /* set the wordcount in the header */
77 if (wordcount >= GC_SIZE_DUMMY) {
78 GC_SET_SIZE(o, GC_SIZE_DUMMY);
80 GC_SET_SIZE(o, wordcount);
86 void heap_update_references(rootset_t *rs, regioninfo_t *region, u4 offset)
90 java_object_t **refptr;
95 GC_LOG( dolog("GC: Updating all references (offset=%x) ...", offset); );
97 start = region->base - offset;
98 end = region->ptr - offset;
99 GC_LOG( printf("Region previously was [ %p ; %p]\n", start, end); );
101 GC_LOG2( printf("updating in root-sets ..."); );
103 /* walk through all rootsets */
106 /* walk through the references of this rootset */
107 for (i = 0; i < rs->refcount; i++) {
109 /* load the reference */
110 refptr = rs->refs[i].ref;
113 GC_LOG2( printf("\troot pointer to %p\n", (void *) ref); );
115 /* update the references */
116 if (POINTS_INTO(ref, start, end))
117 *refptr = ((u1 *) ref) + offset;
121 /* skip to next rootset in chain */
128 while (o < region->ptr) {
130 GC_LOG2( printf("updating in %p ...\n", (void *) o); );
134 /* walk through the references of an Array */
135 FOREACH_ARRAY_REF(o,ref,refptr,
137 GC_LOG2( printf("\tarray-entry %p -> %p\n", (void *) ref, ((u1 *) ref) + offset); );
139 if (POINTS_INTO(ref, start, end))
140 *refptr = ((u1 *) ref) + offset;
146 /* walk through the references of an Object */
147 FOREACH_OBJECT_REF(o,ref,refptr,
149 GC_LOG2( printf("\tobject-field %p -> %p\n", (void *) ref, ((u1 *) ref) + offset); );
151 if (POINTS_INTO(ref, start, end))
152 *refptr = ((u1 *) ref) + offset;
158 /* skip to next object */
159 o = ((u1 *) o) + get_object_size(o);
166 void heap_increase_size(rootset_t *rs)
171 /* only a quick sanity check */
172 GC_ASSERT(heap_current_size <= heap_maximal_size);
174 /* check if we are allowed to enlarge the heap */
175 if (heap_current_size == heap_maximal_size)
176 vm_abort("heap_increase_size: reached maximal heap size: out of memory");
178 /* find out how much to increase the heap??? */
179 newsize = 2 * heap_current_size; /* XXX TODO: better heuristic here */
180 dolog("GC: Increasing Heap Size to %d bytes", newsize); /* XXX remove me */
181 GC_LOG( dolog("GC: Increasing Heap Size to %d bytes", newsize); );
183 /* resize the main heap region */
184 resize_offset = region_resize(heap_region_main, newsize);
186 /* update all references if necesarry */
187 if (resize_offset != 0)
188 heap_update_references(rs, heap_region_main, resize_offset);
190 dolog("GC WARNING: References are not updated after heap resizing!");
192 /* set the new values */
193 heap_current_size = newsize;
195 GC_LOG( dolog("GC: Increasing Heap Size was successful");
196 heap_println_usage(); );
198 /* only a quick sanity check */
199 GC_ASSERT(heap_current_size <= heap_maximal_size);
204 s4 heap_get_hashcode(java_object_t *o)
211 /* TODO: we need to lock the object here i think!!! */
213 /* check if there is a hash attached to this object */
214 if (GC_TEST_FLAGS(o, HDRFLAG_HASH_ATTACHED)) {
216 hashcode = *( (s4 *) ( ((u1 *) o) + get_object_size(o) - SIZEOF_VOID_P ) ); /* TODO: clean this up!!! */
217 GC_LOG2( dolog("GC: Hash re-taken: %d (0x%08x)", hashcode, hashcode); );
221 GC_SET_FLAGS(o, HDRFLAG_HASH_TAKEN);
223 hashcode = (s4) (ptrint) o;
224 GC_LOG2( dolog("GC: Hash taken: %d (0x%08x)", hashcode, hashcode); );
232 static java_object_t *heap_alloc_intern(u4 bytelength, regioninfo_t *region, bool collect)
236 /* only a quick sanity check */
238 GC_ASSERT(bytelength >= sizeof(java_object_t));
240 #if !defined(NDEBUG) && defined(ENABLE_THREADS)
241 /* check the current VM state for sanity */
242 GC_ASSERT(!THREADOBJECT->gc_critical);
243 GC_ASSERT(THREADOBJECT->flags & THREAD_FLAG_IN_NATIVE);
246 /* align objects in memory */
247 bytelength = GC_ALIGN(bytelength, GC_ALIGN_SIZE);
249 /* lock the region */
250 LOCK_MONITOR_ENTER(region);
253 /* heavy stress test */
254 if (opt_GCStress && collect)
258 /* check for sufficient free space */
259 if (bytelength > region->free) {
260 dolog("GC: Region out of memory! (collect=%d)", collect);
265 GC_ASSERT(region->free >= bytelength);
267 if (region->free < bytelength) {
268 dolog("GC: OOM OOM OOM OOM OOM OOM OOM OOM OOM OOM");
269 exceptions_throw_outofmemoryerror();
277 /* allocate the object in this region */
278 p = (java_object_t *) region->ptr;
279 region->ptr += bytelength;
280 region->free -= bytelength;
282 /* unlock the region */
283 LOCK_MONITOR_EXIT(region);
285 /* clear allocated memory region */
287 MSET(p, 0, u1, bytelength);
289 /* set the header information */
290 heap_init_objectheader(p, bytelength);
296 /* heap_alloc ******************************************************************
298 Allocates memory on the Java heap.
300 *******************************************************************************/
302 void *heap_alloc(u4 size, u4 references, methodinfo *finalizer, bool collect)
306 #if defined(ENABLE_RT_TIMING)
307 struct timespec time_start, time_end;
310 RT_TIMING_GET_TIME(time_start);
312 p = heap_alloc_intern(size, heap_region_main, collect);
317 #if defined(GCCONF_HDRFLAG_REFERENCING)
318 /* We can't use a bool here for references, as it's passed as a
319 bitmask in builtin_new. Thus we check for != 0. */
320 if (references != 0) {
321 GC_SET_FLAGS(p, HDRFLAG_REFERENCING);
325 /* register the finalizer for this object */
326 if (finalizer != NULL) {
327 final_register(p, finalizer);
332 RT_TIMING_GET_TIME(time_end);
333 RT_TIMING_TIME_DIFF(time_start, time_end, RT_TIMING_GC_ALLOC);
339 void *heap_alloc_uncollectable(u4 size)
343 /* loader.c does this a lot for classes with fieldscount equal zero */
347 p = heap_alloc_intern(size, heap_region_sys, false);
352 /* TODO: can this be overwritten by cloning??? */
353 /* remember this object as uncollectable */
354 GC_SET_FLAGS(p, HDRFLAG_UNCOLLECTABLE);
360 void heap_free(void *p)
362 GC_LOG( dolog("GC: Free %p", p); );
367 /* Debugging ******************************************************************/
370 void heap_println_usage()
372 printf("Current Heap Usage: Size=%d Free=%d\n",
373 heap_current_size, heap_region_main->free);
375 GC_ASSERT(heap_current_size == heap_region_main->size);
381 void heap_print_object_flags(java_object_t *o)
383 printf("0x%02x [%s%s%s%s]",
385 GC_TEST_FLAGS(o, HDRFLAG_HASH_ATTACHED) ? "A" : " ",
386 GC_TEST_FLAGS(o, HDRFLAG_HASH_TAKEN) ? "T" : " ",
387 GC_TEST_FLAGS(o, HDRFLAG_UNCOLLECTABLE) ? "U" : " ",
388 GC_TEST_FLAGS(o, GC_FLAG_MARKED) ? "M" : " ");
394 void heap_print_object(java_object_t *o)
399 /* check for null pointers */
405 /* print general information */
406 #if SIZEOF_VOID_P == 8
407 printf("0x%016llx: ", (unsigned long long) o);
409 printf("0x%08lx: ", (unsigned long) o);
412 /* check for invalid heap references */
413 if (!POINTS_INTO(o, heap_region_main->base, heap_region_main->end) &&
414 !POINTS_INTO(o, heap_region_sys->base, heap_region_sys->end))
416 printf("<<< No Heap Reference >>>");
420 /* print object flags */
421 heap_print_object_flags(o);
427 /* maybe this is not really an object */
428 if (/*IS_CLASS*/ o->vftbl->class == class_java_lang_Class) {
430 /* get the class information */
433 /* print the class information */
437 } else if (/*IS_ARRAY*/ o->vftbl->arraydesc != NULL) {
439 /* get the array information */
440 a = (java_array_t *) o;
443 /* print the array information */
446 utf_display_printable_ascii_classname(c->name);
447 printf(" (size=%d)", a->size);
449 } else /*IS_OBJECT*/ {
451 /* get the object class */
454 /* print the object information */
457 utf_display_printable_ascii_classname(c->name);
458 if (c == class_java_lang_String) {
459 printf(" (string=\"");
460 utf_display_printable_ascii(
461 javastring_toutf((java_lang_String *) o, false));
470 void heap_dump_region(regioninfo_t *region, bool marked_only)
475 /* some basic sanity checks */
476 GC_ASSERT(region->base <= region->ptr);
478 printf("Heap-Dump:\n");
480 /* walk the region in a linear style */
481 o = (java_object_t *) region->base;
482 while (o < region->ptr) {
484 if (!marked_only || GC_IS_MARKED(o)) {
486 heap_print_object(o);
490 /* get size of object */
491 o_size = get_object_size(o);
493 /* walk to next object */
494 GC_ASSERT(o_size != 0);
495 o = ((u1 *) o) + o_size;
498 printf("Heap-Dump finished.\n");
503 s4 get_object_size(java_object_t *o)
509 /* we can assume someone initialized the header */
510 GC_ASSERT(o->hdrflags != 0);
512 /* get the wordcount from the header */
513 o_size = GC_GET_SIZE(o);
515 /* maybe we need to calculate the size by hand */
516 if (o_size != GC_SIZE_DUMMY) {
517 GC_ASSERT(o_size != 0);
518 o_size = o_size << 2;
522 /* maybe this is not really an object */
523 if (/*IS_CLASS*/ o->vftbl->class == class_java_lang_Class) {
524 /* we know the size of a classinfo */
525 o_size = sizeof(classinfo);
527 } else if (/*IS_ARRAY*/ o->vftbl->arraydesc != NULL) {
528 /* compute size of this array */
529 a = (java_array_t *) o;
531 o_size = c->vftbl->arraydesc->dataoffset +
532 a->size * c->vftbl->arraydesc->componentsize;
534 } else /*IS_OBJECT*/ {
535 /* get the object size */
537 o_size = c->instancesize;
538 GC_LOG( dolog("Got size (from Class): %d bytes", o_size); );
544 o_size = GC_ALIGN(o_size, GC_ALIGN_SIZE);
546 /* the hashcode attached to this object might increase the size */
547 if (GC_TEST_FLAGS(o, HDRFLAG_HASH_ATTACHED))
548 o_size += SIZEOF_VOID_P;
555 * These are local overrides for various environment variables in Emacs.
556 * Please do not remove this and leave it at the end of the file, where
557 * Emacs will automagically detect them.
558 * ---------------------------------------------------------------------
561 * indent-tabs-mode: t
565 * vim:noexpandtab:sw=4:ts=4: