2 #include <unistd.h> /* getpagesize, mmap, ... */
5 #define MAP_FAILED ((void*) -1)
9 #include "../asmpart.h"
10 #include "../callargs.h"
11 #include "../threads/thread.h"
12 #include "../threads/locks.h"
17 #define PAGESIZE_MINUS_ONE (getpagesize() - 1)
25 #include "allocator.h" /* rev. 1 allocator */
26 #include "bitmap2.h" /* rev. 2 bitmap management */
34 #define align_size(size) ((size) & ~((1 << ALIGN) - 1))
35 #define MAP_ADDRESS (void*) 0x10000000
37 #define VERBOSITY_MESSAGE 1
38 #define VERBOSITY_DEBUG 2
39 #define VERBOSITY_MISTRUST 3
40 #define VERBOSITY_TRACE 4
41 #define VERBOSITY_PARANOIA 5
42 #define VERBOSITY_LIFESPAN 6
44 //#define VERBOSITY VERBOSITY_MESSAGE
45 //#define VERBOSITY VERBOSITY_PARANOIA
46 #define VERBOSITY VERBOSITY_LIFESPAN
48 /* --- file-wide variables */
50 static void* heap_base = NULL;
51 static SIZE heap_size = 0;
52 static void* heap_top = NULL;
53 static void* heap_limit = NULL;
54 static void* heap_next_collection = NULL;
56 static bitmap_t* start_bitmap = NULL;
57 static BITBLOCK* start_bits = NULL;
58 static bitmap_t* reference_bitmap = NULL;
59 static BITBLOCK* reference_bits = NULL;
60 static bitmap_t* mark_bitmap = NULL;
61 static BITBLOCK* mark_bits = NULL;
63 static void** stackbottom = NULL;
65 typedef struct address_list_node {
67 struct address_list_node* next;
70 static address_list_node* references = NULL;
71 static address_list_node* finalizers = NULL;
73 /* --- implementation */
77 SIZE startsize, /* when should we collect for the first time ? */
78 void **in_stackbottom)
80 #if VERBOSITY == VERBOSITY_MESSAGE
81 fprintf(stderr, "The heap is verbose.\n");
82 #elif VERBOSITY == VERBOSITY_DEBUG
83 fprintf(stderr, "The heap is in debug mode.\n");
84 #elif VERBOSITY == VERBOSITY_MISTRUST
85 fprintf(stderr, "The heap is mistrusting us.\n");
86 #elif VERBOSITY == VERBOSITY_TRACE
87 fprintf(stderr, "The heap is outputting trace information.\n");
88 #elif VERBOSITY == VERBOSITY_PARANOIA
89 fprintf(stderr, "The heap is paranoid.\n");
90 #elif VERBOSITY == VERBOSITY_LIFESPAN
91 fprintf(stderr, "The heap is collecting lifespan information.\n");
94 /* 1. Initialise the freelists & reset the allocator's state */
97 /* 2. Allocate at least (alignment!) size bytes of memory for the heap */
98 heap_size = align_size(size + ((1 << ALIGN) - 1));
101 /* For now, we'll try to map in the stack at a fixed address...
102 ...this will change soon. -- phil. */
103 heap_base = (void*) mmap (MAP_ADDRESS,
104 ((size_t)heap_size + PAGESIZE_MINUS_ONE) & ~PAGESIZE_MINUS_ONE,
105 PROT_READ | PROT_WRITE,
106 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
110 heap_base = malloc(heap_size);
113 if (heap_base == MAP_FAILED) {
114 /* unable to allocate the requested amount of memory */
115 fprintf(stderr, "The queen, mylord, is dead!\n");
119 /* 3. Allocate the bitmaps */
120 start_bitmap = bitmap_allocate(heap_base, heap_size);
121 reference_bitmap = bitmap_allocate(heap_base, heap_size);
122 mark_bitmap = bitmap_allocate(heap_base, heap_size);
124 start_bits = start_bitmap->bitmap;
125 reference_bits = reference_bitmap->bitmap;
126 mark_bits = mark_bitmap->bitmap;
128 /* 4. Mark the first free-area as an object-start */
129 bitmap_setbit(start_bits, heap_base);
131 /* 5. Initialise the heap's state (heap_top, etc.) */
132 stackbottom = in_stackbottom; /* copy the stackbottom */
134 heap_top = heap_base; /* the current end of the heap (just behind the last allocated object) */
135 heap_limit = heap_base + heap_size; /* points just behind the last accessible block of the heap */
137 /* 6. calculate a useful first collection limit */
138 /* This is extremly primitive at this point...
139 we should replace it with something more useful -- phil. */
140 heap_next_collection = heap_base + (heap_size / 8);
142 /* 7. Init the global reference lists & finalizer addresses */
150 /* 1. Clean up on the heap... finalize all remaining objects */
152 address_list_node* curr = finalizers;
154 address_list_node* prev = curr;
156 if (bitmap_testbit(start_bits, curr->address))
157 asm_calljavamethod(((java_objectheader*)(curr->address))->vftbl->class->finalizer, curr->address, NULL, NULL, NULL);
164 /* 2. Release the bitmaps */
165 bitmap_release(start_bitmap);
166 bitmap_release(reference_bitmap);
167 bitmap_release(mark_bitmap);
169 /* 3. Release the memory allocated to the heap */
171 munmap(heap_base, heap_size);
177 heap_add_address_to_address_list(address_list_node** list, void* address)
179 /* Note: address lists are kept sorted to simplify finalization */
181 address_list_node* new_node = malloc(sizeof(address_list_node));
182 new_node->address = address;
183 new_node->next = NULL;
185 while (*list && (*list)->next) {
186 #if VERBOSITY >= VERBOSITY_PARANOIA
187 if ((*list)->address == address)
189 "Attempt to add a duplicate adress to an adress list.\n");
192 if ((*list)->next->address < address)
193 list = &(*list)->next;
195 new_node->next = *list;
201 new_node->next = *list;
208 heap_add_finalizer_for_object_at(void* addr)
210 /* Finalizers seem to be very rare... for this reason, I keep a linked
211 list of object addresses, which have a finalizer attached. This list
212 is kept in ascending order according to the order garbage is freed.
213 This list is currently kept separate from the heap, but should be
214 moved onto it, but some JIT-marker code to handle these special
215 objects will need to be added first. -- phil. */
217 heap_add_address_to_address_list(&finalizers, addr);
221 heap_allocate (SIZE in_length,
223 methodinfo *finalizer)
225 SIZE length = align_size(in_length + ((1 << ALIGN) - 1));
226 void* free_chunk = NULL;
228 #if VERBOSITY >= VERBOSITY_MISTRUST && 0
229 /* check for misaligned in_length parameter */
230 if (length != in_length)
232 "heap2.c: heap_allocate was passed unaligned in_length parameter: %ld, \n aligned to %ld. (mistrust)\n",
236 // fprintf(stderr, "heap_allocate: 0x%lx (%ld) requested, 0x%lx (%ld) aligned\n", in_length, in_length, length, length);
239 fprintf(stderr, "finalizer detected\n");
241 #if VERBOSITY >= VERBOSITY_LIFESPAN
242 /* perform garbage collection to collect data for lifespan analysis */
243 if (heap_top > heap_base)
250 /* 1. attempt to get a free block with size >= length from the freelists */
251 free_chunk = allocator_alloc(length);
253 /* 2. if unsuccessful, try alternative allocation strategies */
255 /* 2.a if the collection threshold would be exceeded, collect the heap */
256 if (heap_top + length > heap_next_collection) {
257 /* 2.a.1. collect if the next_collection threshold would be exceeded */
260 /* 2.a.2. we just ran a collection, recheck the freelists */
261 free_chunk = allocator_alloc(length);
265 /* 2.a.3. we can't satisfy the request from the freelists, check
266 against the heap_limit whether growing the heap is possible */
267 if (heap_top + length > heap_limit)
271 /* 2.b. grow the heap */
272 free_chunk = heap_top;
277 /* 3.a. mark all necessary bits, store the finalizer & return the newly allocate block */
279 /* I don't mark the object-start anymore, as it always is at the beginning of a free-block,
280 which already is marked (Note: The first free-block gets marked in heap_init). -- phil. */
281 bitmap_setbit(start_bits, free_chunk); /* mark the new object */
283 bitmap_setbit(start_bits, free_chunk + length); /* mark the freespace behind the new object */
285 bitmap_setbit(reference_bits, free_chunk);
287 bitmap_clearbit(reference_bits, free_chunk);
290 /* store a hint, that there's a finalizer */
292 heap_add_finalizer_for_object_at(free_chunk);
294 # warning "finalizers disabled."
297 #if VERBOSITY >= VERBOSITY_TRACE
298 fprintf(stderr, "heap_allocate: returning free block of 0x%lx bytes at 0x%lx\n", length, free_chunk);
300 #if VERBOSITY >= VERBOSITY_PARANOIA && 0
301 fprintf(stderr, "heap_allocate: reporting heap state variables:\n");
302 fprintf(stderr, "\theap top 0x%lx\n", heap_top);
303 fprintf(stderr, "\theap size 0x%lx (%ld)\n", heap_size, heap_size);
304 fprintf(stderr, "\theap_limit 0x%lx\n", heap_limit);
305 fprintf(stderr, "\theap next collection 0x%lx\n", heap_next_collection);
311 /* 3.b. failure to allocate enough memory... fail gracefully */
312 #if VERBOSITY >= VERBOSITY_MESSAGE
314 "heap2.c: heap_allocate was unable to allocate 0x%lx bytes on the VM heap.\n",
318 #if VERBOSITY >= VERBOSITY_TRACE
319 fprintf(stderr, "heap_allocate: returning NULL\n");
328 heap_addreference (void **reflocation)
330 /* I currently use a separate linked list (as in the original code) to hold
331 the global reference locations, but I'll change this to allocate these
332 in blocks on the heap; we'll have to add JIT-Marker code for those Java
333 objects then. -- phil. */
335 heap_add_address_to_address_list(&references, reflocation);
340 void gc_finalize (void)
342 /* This will have to be slightly rewritten as soon the JIT-marked heap-based lists are used. -- phil. */
344 address_list_node* curr = finalizers;
345 address_list_node* prev;
349 if (!bitmap_testbit(mark_bits, curr->address)) {
350 /* I need a way to save derefs. Any suggestions? -- phil. */
351 asm_calljavamethod(((java_objectheader*)curr->address)->vftbl->class->finalizer,
352 curr->address, NULL, NULL, NULL);
354 prev->next = curr->next;
364 if (!bitmap_testbit(mark_bits, curr->address)) {
365 fprintf(stderr, "executing finalizer\n");
366 asm_calljavamethod(((java_objectheader*)curr->address)->vftbl->class->finalizer,
367 curr->address, NULL, NULL, NULL);
379 void gc_reclaim (void)
382 void* free_end = heap_base;
384 bitmap_t* temp_bitmap;
386 /* 1. reset the freelists */
389 /* 2. reclaim unmarked objects */
390 #if 0 && SIZE_FROM_CLASSINFO
391 free_start = bitmap_find_next_combination_set_unset(start_bitmap,
394 while (free_start < heap_top) {
395 if (!bitmap_testbit(start_bits, free_start) ||
396 bitmap_testbit(mark_bits, free_start)) {
397 fprintf(stderr, "gc_reclaim: inconsistent bit info for 0x%lx\n", free_start);
400 free_end = free_start;
401 while((free_end < heap_top) &&
402 (!bitmap_testbit(mark_bits, free_end)) {
408 bitmap_find_next_setbit(mark_bitmap, free_start + 8); /* FIXME: constant used */
410 // fprintf(stderr, "%lx -- %lx\n", free_start, free_end);
412 if (free_end < heap_top) {
413 allocator_free(free_start, free_end - free_start);
415 // fprintf(stderr, "gc_reclaim: freed 0x%lx bytes at 0x%lx\n", free_end - free_start, free_start);
417 #if !defined(JIT_MARKER_SUPPORT)
418 /* might make trouble with JIT-Marker support. The Marker for unused blocks
419 might be called, leading to a bad dereference. -- phil. */
420 bitmap_setbit(mark_bits, free_start);
424 // fprintf(stderr, "hmmm... found freeable area of 0 bytes at heaptop ?!\n");
429 while (free_end < heap_top) {
430 free_start = bitmap_find_next_combination_set_unset(start_bitmap,
434 if (!bitmap_testbit(start_bits, free_start) ||
435 bitmap_testbit(mark_bits, free_start))
436 fprintf(stderr, "gc_reclaim: inconsistent bit info for 0x%lx\n", free_start);
438 if (free_start < heap_top) {
439 free_end = bitmap_find_next_setbit(mark_bitmap, free_start + 8); /* FIXME: constant used */
441 // fprintf(stderr, "%lx -- %lx\n", free_start, free_end);
443 if (free_end < heap_top) {
444 allocator_free(free_start, free_end - free_start);
446 // fprintf(stderr, "gc_reclaim: freed 0x%lx bytes at 0x%lx\n", free_end - free_start, free_start);
448 #if !defined(JIT_MARKER_SUPPORT)
449 /* might make trouble with JIT-Marker support. The Marker for unused blocks
450 might be called, leading to a bad dereference. -- phil. */
451 bitmap_setbit(mark_bits, free_start);
455 // fprintf(stderr, "hmmm... found freeable area of 0 bytes at heaptop ?!\n");
461 /* 3.1. swap mark & start bitmaps */
462 temp_bits = mark_bits;
463 mark_bits = start_bits;
464 start_bits = temp_bits;
466 temp_bitmap = mark_bitmap;
467 mark_bitmap = start_bitmap;
468 start_bitmap = temp_bitmap;
470 /* 3.2. mask reference bitmap */
471 #warning "bitmap masking unimplemented --- references will not be cleared"
473 /* 3.3. update heap_top */
474 if (free_start < heap_top)
475 heap_top = free_start;
477 if (heap_top < heap_limit)
478 bitmap_setbit(start_bits, heap_top);
480 /* 4. adjust the collection threshold */
481 heap_next_collection = heap_top + (heap_limit - heap_top) / 8;
482 if (heap_next_collection > heap_limit)
483 heap_next_collection = heap_limit;
485 #if VERBOSITY >= VERBOSITY_PARANOIA && 0
486 fprintf(stderr, "gc_reclaim: reporting heap state variables:\n");
487 fprintf(stderr, "\theap top 0x%lx\n", heap_top);
488 fprintf(stderr, "\theap size 0x%lx (%ld)\n", heap_size, heap_size);
489 fprintf(stderr, "\theap_limit 0x%lx\n", heap_limit);
490 fprintf(stderr, "\theap next collection 0x%lx\n", heap_next_collection);
499 gc_mark_object_at (void** addr)
502 // fprintf(stderr, "gc_mark_object_at: called for address 0x%lx\n", addr);
504 if (!((void*)addr >= heap_base &&
505 (void*)addr < heap_top)) {
506 // fprintf(stderr, "not an address on the heap.\n");
508 if (!bitmap_testbit(start_bits, (void*)addr)) {
509 // fprintf(stderr, "not an object.\n");
512 if (bitmap_testbit(mark_bits, (void*)addr)) {
513 // fprintf(stderr, "gc_mark_object_at: called for address 0x%lx: ", addr);
514 // fprintf(stderr, "already marked.\n");
520 /* 1. is the addr aligned, on the heap && the start of an object */
521 if (!((long)addr & ((1 << ALIGN) - 1)) &&
522 (void*)addr >= heap_base &&
523 (void*)addr < heap_top &&
524 bitmap_testbit(start_bits, (void*)addr) &&
525 !bitmap_testbit(mark_bits, (void*)addr)) {
526 bitmap_setbit(mark_bits, (void*)addr);
528 // fprintf(stderr, "gc_mark_object_at: called for address 0x%lx: ", addr);
529 // fprintf(stderr, "marking object.\n");
531 #ifdef JIT_MARKER_SUPPORT
532 /* 1.a. invoke the JIT-marker method */
533 asm_calljavamethod(addr->vftbl->class->marker, addr, NULL, NULL, NULL);
535 /* 1.b. mark the references contained */
536 if (bitmap_testbit(reference_bits, addr)) {
538 #ifdef SIZE_FROM_CLASSINFO
541 if (((java_objectheader*)addr)->vftbl == class_array->vftbl) {
542 end = (void**)((long)addr + (long)((java_arrayheader*)addr)->alignedsize);
543 // fprintf(stderr, "size found for array at 0x%lx: 0x%lx\n", addr, ((java_arrayheader*)addr)->alignedsize);
546 end = (void**)((long)addr + (long)((java_objectheader*)addr)->vftbl->class->alignedsize);
547 // fprintf(stderr, "size found for 0x%lx: 0x%lx\n", addr, ((java_objectheader*)addr)->vftbl->class->alignedsize);
550 old_end = (void**)bitmap_find_next_setbit(start_bitmap, (void*)addr + 8);
551 if (end != old_end) {
552 fprintf(stderr, "inconsistent object length for object at 0x%lx:", addr);
553 fprintf(stderr, " old = 0x%lx ; new = 0x%lx\n", old_end, end);
556 end = (void**)bitmap_find_next_setbit(start_bitmap, addr + 8); /* points just behind the object */
560 gc_mark_object_at(*(addr++));
570 void gc_mark_references (void)
572 address_list_node* curr = references;
574 // fprintf(stderr, "gc_mark_references\n");
577 gc_mark_object_at(*((void**)(curr->address)));
585 markreferences(void** start, void** end)
588 gc_mark_object_at(*(start++));
593 void gc_mark_stack (void)
600 if (currentThread == NULL) {
601 void **top_of_stack = &dummy;
603 if (top_of_stack > stackbottom)
604 markreferences(stackbottom, top_of_stack);
606 markreferences(top_of_stack, stackbottom);
609 for (aThread = liveThreads; aThread != 0;
610 aThread = CONTEXT(aThread).nextlive) {
611 mark_object_at((void*)aThread);
612 if (aThread == currentThread) {
613 void **top_of_stack = &dummy;
615 if (top_of_stack > (void**)CONTEXT(aThread).stackEnd)
616 markreferences((void**)CONTEXT(aThread).stackEnd, top_of_stack);
618 markreferences(top_of_stack, (void**)CONTEXT(aThread).stackEnd);
621 if (CONTEXT(aThread).usedStackTop > CONTEXT(aThread).stackEnd)
622 markreferences((void**)CONTEXT(aThread).stackEnd,
623 (void**)CONTEXT(aThread).usedStackTop);
625 markreferences((void**)CONTEXT(aThread).usedStackTop,
626 (void**)CONTEXT(aThread).stackEnd);
630 markreferences((void**)&threadQhead[0],
631 (void**)&threadQhead[MAX_THREAD_PRIO]);
634 void **top_of_stack = &dummy;
636 // fprintf(stderr, "gc_mark_stack\n");
638 if (top_of_stack > stackbottom) {
639 // fprintf(stderr, "stack growing upward\n");
640 markreferences(stackbottom, top_of_stack);
642 // fprintf(stderr, "stack growing downward\n");
643 markreferences(top_of_stack, stackbottom);
652 static int armageddon_is_near = 0;
654 if (armageddon_is_near) {
655 /* armageddon_is_here! */
656 fprintf(stderr, "Oops, seems like there's a slight problem here: gc_run() called while still running?!\n");
660 armageddon_is_near = true;
661 heap_next_collection = heap_limit; /* try to avoid finalizer-induced collections */
663 bitmap_clear(mark_bitmap);
665 asm_dumpregistersandcall(gc_mark_stack);
666 gc_mark_references();
670 armageddon_is_near = false;
674 /************************* Function: gc_init **********************************
676 Initializes anything that must be initialized to call the gc on the right
679 ******************************************************************************/
686 /************************** Function: gc_call ********************************
688 Calls the garbage collector. The garbage collector should always be called
689 using this function since it ensures that enough stack space is available.
691 ******************************************************************************/
697 assert(blockInts == 0);
700 if (currentThread == NULL || currentThread == mainThread)
703 asm_switchstackandcall(CONTEXT(mainThread).usedStackTop, gc_run);
713 * These are local overrides for various environment variables in Emacs.
714 * Please do not remove this and leave it at the end of the file, where
715 * Emacs will automagically detect them.
716 * ---------------------------------------------------------------------
719 * indent-tabs-mode: t