1 /* mm/cacao-gc/heap.c - GC module for heap management
3 Copyright (C) 2006 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 Contact: cacao@cacaojvm.org
27 Authors: Michael Starzinger
41 #include "mm/memory.h"
42 #include "native/jni.h"
43 #include "src/native/include/java_lang_String.h" /* TODO: fix me! */
44 #include "toolbox/logging.h"
45 #include "vm/exceptions.h"
46 #include "vm/global.h"
47 /*#include "vm/options.h"*/
48 #include "vm/jit/stacktrace.h"
51 /* Global Variables ***********************************************************/
53 /*void *heap_base;*/ /* pointer to the base of the heap */
54 /*void *heap_ptr;*/ /* current allocation ptr for linear alloc */
55 s4 heap_current_size; /* current size of the heap */
56 s4 heap_maximal_size; /* maximal size of the heap */
57 s4 heap_free_size; /* free bytes on the heap */
58 s4 heap_used_size; /* used bytes on the heap */
59 regioninfo_t *heap_region_sys;
60 regioninfo_t *heap_region_main;
63 /* Helper Macros **************************************************************/
65 #define GC_ALIGN_SIZE SIZEOF_VOID_P
66 #define GC_ALIGN(length,size) ((((length) + (size) - 1) / (size)) * (size))
69 void heap_init_objectheader(java_objectheader *o, u4 bytelength)
73 /* initialize the header flags */
79 /* calculate the wordcount as stored in the header */
80 /* TODO: improve this to save wordcount and without header bytes */
81 if ((bytelength & 0x03) == 0) {
82 GC_ASSERT((bytelength & 0x03) == 0);
83 wordcount = (bytelength >> 2);
84 GC_ASSERT(wordcount != 0);
86 wordcount = GC_SIZE_DUMMY;
89 /* set the wordcount in the header */
90 if (wordcount >= GC_SIZE_DUMMY) {
91 GC_SET_SIZE(o, GC_SIZE_DUMMY);
93 GC_SET_SIZE(o, wordcount);
99 s4 heap_increase_size() {
104 /* TODO: locking for threads!!! */
106 /* only a quick sanity check */
107 GC_ASSERT(heap_current_size <= heap_maximal_size);
109 /* check if we are allowed to enlarge the heap */
110 if (heap_current_size == heap_maximal_size)
111 exceptions_throw_outofmemory_exit();
113 /* TODO: find out how much to increase the heap??? */
114 increasesize = heap_maximal_size - heap_current_size;
115 GC_LOG( dolog("GC: Increasing Heap Size by %d", increasesize); );
117 /* allocate new heap from the system */
118 newsize = heap_current_size + increasesize;
121 /* check if the newly allocated heap exists */
123 exceptions_throw_outofmemory_exit();
125 /* TODO: copy the old content to the new heap */
126 /* TODO: find a complete rootset and update it to the new position */
127 /* TODO: free the old heap */
129 /* set the new values */
130 /*heap_ptr = p + (heap_ptr - heap_base);
132 heap_current_size = newsize;
133 heap_free_size += increasesize;
135 GC_LOG( dolog("GC: Increasing Heap Size was successful");
136 heap_println_usage(); );
138 /* only a quick sanity check */
139 GC_ASSERT(heap_current_size <= heap_maximal_size);
145 s4 heap_get_hashcode(java_objectheader *o)
152 /* TODO: we need to lock the object here i think!!! */
154 /* check if there is a hash attached to this object */
155 if (GC_TEST_FLAGS(o, HDRFLAG_HASH_ATTACHED)) {
157 hashcode = *( (s4 *) ( ((u1 *) o) + get_object_size(o) - SIZEOF_VOID_P ) ); /* TODO: clean this up!!! */
158 GC_LOG( dolog("GC: Hash re-taken: %d (0x%08x)", hashcode, hashcode); );
162 GC_SET_FLAGS(o, HDRFLAG_HASH_TAKEN);
164 hashcode = (s4) (ptrint) o;
165 GC_LOG( dolog("GC: Hash taken: %d (0x%08x)", hashcode, hashcode); );
173 java_objectheader *heap_alloc_intern(u4 bytelength, regioninfo_t *region)
175 java_objectheader *p;
177 /* only a quick sanity check */
179 GC_ASSERT(bytelength >= sizeof(java_objectheader));
181 /* align objects in memory */
182 bytelength = GC_ALIGN(bytelength, GC_ALIGN_SIZE);
184 /* check for sufficient free space */
185 if (bytelength > region->free) {
186 dolog("GC: Region out of memory!");
187 /* TODO: change this to gc_collect() !!! */
192 /* allocate the object in this region */
194 region->ptr += bytelength;
195 region->free -= bytelength;
197 /*heap_free_size -= bytelength;
198 heap_used_size += bytelength;*/
200 /* clear allocated memory region */
202 MSET(p, 0, u1, bytelength);
204 /* set the header information */
205 heap_init_objectheader(p, bytelength);
211 /* heap_allocate ***************************************************************
213 Allocates memory on the Java heap.
215 *******************************************************************************/
217 void *heap_allocate(u4 bytelength, u4 references, methodinfo *finalizer)
219 java_objectheader *p;
221 /* We can't use a bool here for references, as it's passed as a
222 bitmask in builtin_new. Thus we check for != 0. */
224 p = heap_alloc_intern(bytelength, heap_region_main);
229 /* TODO: can this be overwritten by cloning??? */
230 if (finalizer != NULL) {
231 GC_LOG( log_text("GC: Finalizer not yet implemented!"); );
232 GC_SET_FLAGS(p, GC_FLAG_FINALIZER);
239 void *heap_alloc_uncollectable(u4 bytelength)
241 java_objectheader *p;
243 /* loader.c does this a lot for classes with fieldscount equal zero */
247 p = heap_alloc_intern(bytelength, heap_region_sys);
252 /* TODO: can this be overwritten by cloning??? */
253 /* remember this object as uncollectable */
254 GC_SET_FLAGS(p, GC_FLAG_UNCOLLECTABLE);
260 void heap_free(void *p)
262 GC_LOG( dolog("GC: Free %p", p); );
267 /* Debugging ******************************************************************/
270 void heap_println_usage()
272 printf("Current Heap Usage: Size=%d Free=%d Used=%d\n",
273 heap_current_size, heap_free_size, heap_used_size);
275 GC_ASSERT(heap_current_size == heap_free_size + heap_used_size);
281 void heap_print_object_flags(java_objectheader *o)
283 printf("0x%02x [%s%s%s%s%s]",
285 GC_TEST_FLAGS(o, GC_FLAG_FINALIZER) ? "F" : " ",
286 GC_TEST_FLAGS(o, HDRFLAG_HASH_ATTACHED) ? "A" : " ",
287 GC_TEST_FLAGS(o, HDRFLAG_HASH_TAKEN) ? "T" : " ",
288 GC_TEST_FLAGS(o, GC_FLAG_UNCOLLECTABLE) ? "U" : " ",
289 GC_TEST_FLAGS(o, GC_FLAG_MARKED) ? "M" : " ");
295 void heap_print_object(java_objectheader *o)
300 /* check for null pointers */
306 /* print general information */
307 printf("%p: ", (void *) o);
308 heap_print_object_flags(o);
312 /* maybe this is not really an object */
313 if (/*IS_CLASS*/ o->vftbl->class == class_java_lang_Class) {
315 /* get the class information */
318 /* print the class information */
322 } else if (/*IS_ARRAY*/ o->vftbl->arraydesc != NULL) {
324 /* get the array information */
325 a = (java_arrayheader *) o;
328 /* print the array information */
331 utf_display_printable_ascii_classname(c->name);
332 printf(" (size=%d)", a->size);
334 } else /*IS_OBJECT*/ {
336 /* get the object class */
339 /* print the object information */
342 utf_display_printable_ascii_classname(c->name);
343 if (c == class_java_lang_String) {
344 printf(" (string=\"");
345 utf_display_printable_ascii(
346 javastring_toutf((java_lang_String *) o, false));
355 void heap_dump_region(regioninfo_t *region, bool marked_only)
357 java_objectheader *o;
360 /* some basic sanity checks */
361 GC_ASSERT(region->base < region->ptr);
363 printf("Heap-Dump:\n");
365 /* walk the region in a linear style */
367 while ((void *) o < region->ptr) {
369 if (!marked_only || GC_IS_MARKED(o)) {
371 heap_print_object(o);
375 /* get size of object */
376 o_size = get_object_size(o);
378 /* walk to next object */
379 GC_ASSERT(o_size != 0);
380 o = ((u1 *) o) + o_size;
383 printf("Heap-Dump finished.\n");
388 s4 get_object_size(java_objectheader *o)
394 /* we can assume someone initialized the header */
395 GC_ASSERT(o->hdrflags != 0);
397 /* get the wordcount from the header */
398 o_size = GC_GET_SIZE(o);
400 /* maybe we need to calculate the size by hand */
401 if (o_size != GC_SIZE_DUMMY) {
402 GC_ASSERT(o_size != 0);
403 o_size = o_size << 2;
407 /* maybe this is not really an object */
408 if (/*IS_CLASS*/ o->vftbl->class == class_java_lang_Class) {
409 /* we know the size of a classinfo */
410 o_size = sizeof(classinfo);
412 } else if (/*IS_ARRAY*/ o->vftbl->arraydesc != NULL) {
413 /* compute size of this array */
414 a = (java_arrayheader *) o;
416 o_size = c->vftbl->arraydesc->dataoffset +
417 a->size * c->vftbl->arraydesc->componentsize;
419 } else /*IS_OBJECT*/ {
420 /* get the object size */
422 o_size = c->instancesize;
423 GC_LOG( dolog("Got size (from Class): %d bytes", o_size); );
429 o_size = GC_ALIGN(o_size, GC_ALIGN_SIZE);
431 /* the hashcode attached to this object might increase the size */
432 if (GC_TEST_FLAGS(o, HDRFLAG_HASH_ATTACHED))
433 o_size += SIZEOF_VOID_P;
439 java_objectheader *next;
441 void *gc_copy_forward(java_objectheader *o, void *src_start, void *src_end)
445 if (POINTS_INTO(o, src_start, src_end)) {
447 /* update all references which point into the source region */
449 /* NOTE: we use the marking bit here to mark object which have already
450 * been copied; in such a case the *vftbl contains the location of
452 if (GC_IS_MARKED(o)) {
454 /* return the location of an already existing copy */
459 /* calculate the size of the object to be copied */
460 o_size = get_object_size(o);
462 /* copy the object pointed to by O to location NEXT */
463 memcpy(next, o, o_size);
465 /* remember where the copy is located */
466 o->vftbl = (void *) next;
468 /* increment NEXT to point past the copy of the object */
469 next = ((u1 *) next) + o_size;
471 /* return the location of the copy */
478 /* do not change references not pointing into the source region */
485 void gc_copy(regioninfo_t *src, regioninfo_t *dst, rootset_t *rs)
487 java_objectheader *scan;
488 /*java_objectheader *next;*/
490 java_objectheader *ref_old;
491 java_objectheader *ref_new;
494 /* initialize the scan and next pointer */
495 scan = (java_objectheader *) dst->base;
496 next = (java_objectheader *) dst->base;
498 /* for each root pointer R: replace R with forward(R) */
499 for (i = 0; i < rs->refcount; i++) {
501 ref_old = *( rs->refs[i] );
502 GC_LOG( printf("Will forward: ");
503 heap_print_object(ref_old);
506 ref_new = gc_copy_forward(ref_old, src->base, src->end);
508 *( rs->refs[i] ) = ref_new;
509 GC_LOG( printf("New location: ");
510 heap_print_object(ref_new);
514 /* update all references for objects in the destination region.
515 * when scan catches up with next, the algorithm is finished */
518 /* TODO: implement me! */
519 GC_LOG( printf("Will also forward pointers in ");
520 heap_print_object(scan); printf("\n"); );
522 scan = ((u1 *) scan) + get_object_size(scan);
525 /* some basic assumptions */
526 GC_ASSERT(scan == next);
527 GC_ASSERT(scan < dst->end);
532 * These are local overrides for various environment variables in Emacs.
533 * Please do not remove this and leave it at the end of the file, where
534 * Emacs will automagically detect them.
535 * ---------------------------------------------------------------------
538 * indent-tabs-mode: t
542 * vim:noexpandtab:sw=4:ts=4: