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"
13 #include "../sysdep/threads.h"
19 #define PAGESIZE_MINUS_ONE (getpagesize() - 1)
24 #define HEURISTIC_SEL 0
25 #define HEURISTIC_PARAM 2UL
28 #define next_collection_heuristic_init() \
29 (void*)((long)heap_top + (((long)heap_limit - (long)heap_top) >> 4))
31 #if HEURISTIC_SEL == 0
32 #define next_collection_heuristic() \
33 (void*)((long)heap_top + (((long)heap_limit - (long)heap_top) >> HEURISTIC_PARAM))
34 #elif HEURISTIC_SEL == 1
35 #define next_collection_heuristic() \
36 (void*)((long)heap_top + (((long)heap_top - (long)heap_base) << HEURISTIC_PARAM))
37 #elif HEURISTIC_SEL == 2
38 #define next_collection_heuristic() \
39 (void*)((long)heap_top + HEURISTIC_PARAM)
42 //#define PSEUDO_GENERATIONAL
43 //#define COLLECT_LIFESPAN
44 //#define NEW_COLLECT_LIFESPAN
45 //#define COLLECT_FRAGMENTATION
46 //#define GC_COLLECT_STATISTICS
47 //#define FINALIZER_COUNTING
49 #undef STRUCTURES_ON_HEAP
50 //#define STRUCTURES_ON_HEAP
55 #include "allocator.h" /* rev. 1 allocator */
56 #include "bitmap2.h" /* rev. 2 bitmap management */
64 #define align_size(size) ((size) & ~((1 << ALIGN) - 1))
65 #define MAP_ADDRESS (void*) 0x10000000
67 /* --- file-wide variables */
69 static void* heap_base = NULL;
70 static SIZE heap_size = 0;
71 static void* heap_top = NULL;
72 static void* heap_limit = NULL;
73 static void* heap_next_collection = NULL;
75 static bitmap_t* start_bitmap = NULL;
76 static BITBLOCK* start_bits = NULL;
77 static bitmap_t* reference_bitmap = NULL;
78 static BITBLOCK* reference_bits = NULL;
79 static bitmap_t* mark_bitmap = NULL;
80 static BITBLOCK* mark_bits = NULL;
82 static void** stackbottom = NULL;
84 typedef struct address_list_node {
86 struct address_list_node* prev;
87 struct address_list_node* next;
90 static address_list_node* references = NULL;
91 static address_list_node* finalizers = NULL;
93 #ifdef GC_COLLECT_STATISTICS
95 static unsigned long gc_collections_count = 0;
97 static unsigned long gc_alloc_total = 0;
98 static unsigned long gc_alloc_count = 0;
100 static unsigned long gc_mark_heapblocks_visited = 0;
101 static unsigned long gc_mark_not_aligned = 0;
102 static unsigned long gc_mark_not_inheap = 0;
103 static unsigned long gc_mark_not_object = 0;
104 static unsigned long gc_mark_objects_marked = 0;
105 static unsigned long gc_mark_already_marked = 0;
109 #ifdef FINALIZER_COUNTING
111 static unsigned long gc_finalizers_executed = 0;
112 static unsigned long gc_finalizers_detected = 0;
117 static iMux alloc_mutex;
120 #ifdef COLLECT_LIFESPAN
121 static FILE* tracefile;
124 #ifdef COLLECT_FRAGMENTATION
125 static FILE* fragfile;
126 static FILE* fragsizefile;
129 /* --- implementation */
132 heap_init (SIZE size,
133 SIZE startsize, /* when should we collect for the first time ? */
134 void **in_stackbottom)
136 /* 1. Initialise the freelists & reset the allocator's state */
139 /* 2. Allocate at least (alignment!) size bytes of memory for the heap */
140 heap_size = align_size(size + ((1 << ALIGN) - 1));
143 heap_base = malloc(heap_size);
145 heap_base = (void*) mmap (NULL,
146 ((size_t)heap_size + PAGESIZE_MINUS_ONE) & ~PAGESIZE_MINUS_ONE,
147 PROT_READ | PROT_WRITE,
148 MAP_PRIVATE | MAP_ANONYMOUS,
153 if (heap_base == (void*)MAP_FAILED) {
154 /* unable to allocate the requested amount of memory */
155 fprintf(stderr, "heap2.c: The queen, mylord, is dead! (mmap failed)\n");
159 /* 3. Allocate the bitmaps */
160 start_bitmap = bitmap_allocate(heap_base, heap_size);
161 reference_bitmap = bitmap_allocate(heap_base, heap_size);
162 mark_bitmap = bitmap_allocate(heap_base, heap_size);
164 start_bits = start_bitmap->bitmap;
165 reference_bits = reference_bitmap->bitmap;
166 mark_bits = mark_bitmap->bitmap;
168 /* 4. Mark the first free-area as an object-start */
169 bitmap_setbit(start_bits, heap_base);
171 /* 5. Initialise the heap's state (heap_top, etc.) */
172 stackbottom = in_stackbottom; /* copy the stackbottom */
174 heap_top = heap_base; /* the current end of the heap (just behind the last allocated object) */
175 heap_limit = (void*)((long)heap_base + heap_size); /* points just behind the last accessible block of the heap */
177 /* 6. calculate a useful first collection limit */
178 /* This is extremly primitive at this point...
179 we should replace it with something more useful -- phil. */
180 heap_next_collection = next_collection_heuristic_init();
182 /* 7. Init the global reference lists & finalizer addresses */
186 #ifdef STRUCTURES_ON_HEAP
187 heap_addreference(&references);
188 heap_addreference(&finalizers);
192 /* 8. Init the mutexes for synchronization */
193 alloc_mutex.holder = 0;
196 /* 9. Set up collection of lifespan data */
197 #ifdef COLLECT_LIFESPAN
199 tracefile = fopen("heap.trace", "w");
201 tracefile = popen("gzip -9 >heap.trace.gz", "w");
204 fprintf(stderr, "heap2.c: Radio Ga Ga! (fopen failed)\n");
208 fprintf(tracefile, "heap_base\t0x%lx\n", heap_base);
209 fprintf(tracefile, "heap_limit\t0x%lx\n", heap_limit);
210 fprintf(tracefile, "heap_top\t0x%lx\n", heap_top);
213 #ifdef NEW_COLLECT_LIFESPAN
214 lifespan_init(heap_base, heap_size);
217 /* 10. Set up collection of fragmentation data */
218 #ifdef COLLECT_FRAGMENTATION
219 fragfile = popen("gzip -9 >fragmentation.gz", "w");
220 fragsizefile = popen("gzip -9 >freeblocks.gz", "w");
227 heap_call_finalizer_for_object_at(java_objectheader* object_addr)
229 asm_calljavamethod(object_addr->vftbl->class->finalizer, object_addr, NULL, NULL, NULL);
230 #ifdef FINALIZER_COUNTING
231 ++gc_finalizers_executed;
238 address_list_node* curr = finalizers;
240 /* 0. clean up lifespan module */
241 #ifdef COLLECT_LIFESPAN
249 #ifdef NEW_COLLECT_LIFESPAN
253 #ifdef COLLECT_FRAGMENTATION
255 pclose(fragsizefile);
258 /* 1. Clean up on the heap... finalize all remaining objects */
261 address_list_node* prev = curr;
262 java_objectheader* addr = (java_objectheader*)(curr->address);
264 if (addr && bitmap_testbit(start_bits, addr))
265 heap_call_finalizer_for_object_at(addr);
272 /* 2. Release the bitmaps */
273 bitmap_release(start_bitmap);
274 bitmap_release(reference_bitmap);
275 bitmap_release(mark_bitmap);
277 /* 3. Release the memory allocated to the heap */
279 munmap(heap_base, heap_size);
281 /* 4. emit statistical data */
282 #ifdef GC_COLLECT_STATISTICS
283 sprintf(logtext, "%ld bytes for %ld objects allocated.",
284 gc_alloc_total, gc_alloc_count);
286 sprintf(logtext, "%ld garbage collections performed.", gc_collections_count);
288 sprintf(logtext, "%ld heapblocks visited, %ld objects marked",
289 gc_mark_heapblocks_visited, gc_mark_objects_marked);
291 sprintf(logtext, " %ld out of heap.", gc_mark_not_inheap);
293 sprintf(logtext, " %ld visits to objects already marked.", gc_mark_already_marked);
295 sprintf(logtext, " %ld not an object.", gc_mark_not_object);
297 sprintf(logtext, " %ld potential references not aligned.", gc_mark_not_aligned);
301 #ifdef FINALIZER_COUNTING
302 sprintf(logtext, "%ld objects with a finalizer", gc_finalizers_detected);
305 if (gc_finalizers_detected == gc_finalizers_executed)
306 sprintf(logtext, " all finalizers executed.");
308 sprintf(logtext, " only %ld finalizers executed.", gc_finalizers_executed);
312 #ifdef NEW_COLLECT_LIFESPAN
320 heap_add_address_to_address_list(address_list_node** list, void* address)
322 /* Note: address lists are kept sorted to simplify finalization */
324 address_list_node* new_node = malloc(sizeof(address_list_node));
325 new_node->address = address;
326 new_node->next = NULL;
328 while (*list && (*list)->next) {
329 if ((*list)->next->address < address)
330 list = &(*list)->next;
332 new_node->next = *list;
338 new_node->next = *list;
346 heap_add_finalizer_for_object_at(void* addr)
348 /* Finalizers seem to be very rare... for this reason, I keep a linked
349 list of object addresses, which have a finalizer attached. This list
350 is kept in ascending order according to the order garbage is freed.
351 This list is currently kept separate from the heap, but should be
352 moved onto it, but some JIT-marker code to handle these special
353 objects will need to be added first. -- phil. */
355 heap_add_address_to_address_list(&finalizers, addr);
357 #ifdef COLLECT_LIFESPAN
358 fprintf(tracefile, "finalizer\t0x%lx\n", addr);
363 heap_allocate (SIZE in_length,
365 methodinfo *finalizer)
367 SIZE length = align_size(in_length + ((1 << ALIGN) - 1));
368 void* free_chunk = NULL;
371 /* check for misaligned in_length parameter */
372 if (length != in_length)
374 "heap2.c: heap_allocate was passed unaligned in_length parameter: %ld, \n aligned to %ld. (mistrust)\n",
378 #ifdef FINALIZER_COUNTING
380 ++gc_finalizers_detected;
383 #if defined(COLLECT_LIFESPAN) || defined(NEW_COLLECT_LIFESPAN)
384 /* perform garbage collection to collect data for lifespan analysis */
385 if (heap_top > heap_base)
390 lock_mutex(&alloc_mutex);
393 /* 1. attempt to get a free block with size >= length from the freelists */
394 free_chunk = allocator_alloc(length);
396 /* 2. if unsuccessful, try alternative allocation strategies */
398 /* 2.a if the collection threshold would be exceeded, collect the heap */
399 if ((long)heap_top + length > (long)heap_next_collection) {
400 /* 2.a.1. collect if the next_collection threshold would be exceeded */
403 /* 2.a.2. we just ran a collection, recheck the freelists */
404 free_chunk = allocator_alloc(length);
408 /* 2.a.3. we can't satisfy the request from the freelists, check
409 against the heap_limit whether growing the heap is possible */
410 if ((long)heap_top + length > (long)heap_limit)
414 /* 2.b. grow the heap */
415 free_chunk = heap_top;
416 heap_top = (void*)((long)heap_top + length);
420 /* 3.a. mark all necessary bits, store the finalizer & return the newly allocated block */
422 /* I don't mark the object-start anymore, as it always is at the beginning of a free-block,
423 which already is marked (Note: The first free-block gets marked in heap_init). -- phil. */
424 bitmap_setbit(start_bits, free_chunk); /* mark the new object */
426 #ifndef SIZE_FROM_CLASSINFO
427 bitmap_setbit(start_bits, (void*)((long)free_chunk + (long)length)); /* mark the freespace behind the new object */
431 bitmap_setbit(reference_bits, free_chunk);
433 bitmap_clearbit(reference_bits, free_chunk);
435 /* store a hint, that there's a finalizer for this address */
437 heap_add_finalizer_for_object_at(free_chunk);
439 #ifdef GC_COLLECT_STATISTICS
440 gc_alloc_total += length;
444 #ifdef COLLECT_LIFESPAN
445 fprintf(tracefile, "alloc\t0x%lx\t0x%lx\n",
446 free_chunk, (long)free_chunk + length);
449 #ifdef NEW_COLLECT_LIFESPAN
450 lifespan_alloc(free_chunk, length);
455 unlock_mutex(&alloc_mutex);
461 heap_addreference (void **reflocation)
463 /* I currently use a separate linked list (as in the original code) to hold
464 the global reference locations, but I'll change this to allocate these
465 in blocks on the heap; we'll have to add JIT-Marker code for those Java
466 objects then. -- phil. */
468 heap_add_address_to_address_list(&references, reflocation);
473 void gc_finalize (void)
475 /* This will have to be slightly rewritten as soon the JIT-marked heap-based lists are used. -- phil. */
477 address_list_node* curr = finalizers;
478 address_list_node* prev;
481 /* FIXME: new code, please! */
485 if (!bitmap_testbit(mark_bits, curr->address)) {
487 #ifdef FINALIZER_COUNTING
488 ++gc_finalizers_executed;
490 asm_calljavamethod(((java_objectheader*)curr->address)->vftbl->class->finalizer,
491 curr->address, NULL, NULL, NULL);
504 void gc_reclaim (void)
506 #ifdef PSEUDO_GENERATIONAL
507 static void* generation_start = 0;
508 static int generation_num = 0;
509 void* addr = heap_base;
512 void* free_end = heap_base;
514 bitmap_t* temp_bitmap;
516 #ifdef COLLECT_FRAGMENTATION
517 unsigned long free_size = 0;
518 unsigned long free_fragments = 0;
521 #ifdef PSEUDO_GENERATIONAL
522 if (!generation_start || !(generation_num % 5))
523 generation_start = heap_base;
528 /* 1. reset the freelists */
531 allocator_mark_free_kludge(start_bits); /* this line will be kicked out, when
532 the SIZE_FROM_CLASSINFO reclaim
533 is implemented (very soon!!) */
536 #ifdef PSEUDO_GENERATIONAL
537 for (addr = heap_base; addr <= generation_start; ++addr) {
538 if (bitmap_testbit(start_bits, addr))
539 bitmap_setbit(mark_bits, addr);
542 allocator_mark_free_kludge(start_bits); /* this line will be kicked out, when
543 the SIZE_FROM_CLASSINFO reclaim
544 is implemented (very soon!!) */
549 /* 2. reclaim unmarked objects */
551 if (!testbit(start_bits, heap_base))
552 free_start = heap_base;
554 free_start = bitmap_find_next_combination_set_unset(start_bitmap,
559 while (free_end < heap_top) {
560 free_start = bitmap_find_next_combination_set_unset(start_bitmap,
564 if (free_start < heap_top) {
565 free_end = bitmap_find_next_setbit(mark_bitmap, (void*)((long)free_start + 8)); /* FIXME: constant used */
567 if (free_end < heap_top) {
568 allocator_free(free_start, (long)free_end - (long)free_start);
570 #ifdef COLLECT_FRAGMENTATION
571 free_size += (long)free_end - (long)free_start;
575 #ifdef COLLECT_LIFESPAN
577 "free\t0x%lx\t0x%lx\n",
582 #ifdef NEW_COLLECT_LIFESPAN
583 lifespan_free(free_start, free_end);
586 #ifndef SIZE_FROM_CLASSINFO
587 /* would make trouble with JIT-Marker support. The Marker for unused blocks
588 might be called, leading to a bad dereference. -- phil. */
589 bitmap_setbit(mark_bits, free_start); /* necessary to calculate obj-size bitmap based. */
598 /* 3.1. swap mark & start bitmaps */
599 temp_bits = mark_bits;
600 mark_bits = start_bits;
601 start_bits = temp_bits;
603 temp_bitmap = mark_bitmap;
604 mark_bitmap = start_bitmap;
605 start_bitmap = temp_bitmap;
607 #if 0 /* operation already handled in allocate */
608 /* 3.2. mask reference bitmap */
609 bitmap_mask_with_bitmap(reference_bitmap, start_bitmap);
612 /* 3.3. update heap_top */
613 if (free_start < heap_top) {
614 heap_top = free_start;
615 #ifdef NEW_COLLECT_LIFESPAN
616 lifespan_free(free_start, free_end);
621 if (heap_top < heap_limit)
622 bitmap_setbit(start_bits, heap_top);
625 /* 3.4. emit fragmentation info */
626 #ifdef COLLECT_FRAGMENTATION
628 unsigned long heap_full = (unsigned long)heap_top - (unsigned long)heap_base;
629 unsigned long heap_life = (unsigned long)heap_top - (unsigned long)heap_base - free_size;
632 "%ld\t%ld\t%ld\t%ld\t%f\t%f\t%f\n",
637 100*(float)free_size/free_fragments,
638 100*(float)heap_life/heap_full,
639 100*(float)free_size/heap_full
644 allocator_dump_to_file(fragsizefile);
647 /* 4. adjust the collection threshold */
648 heap_next_collection = next_collection_heuristic();
649 if (heap_next_collection > heap_limit)
650 heap_next_collection = heap_limit;
652 #ifdef COLLECT_LIFESPAN
653 fprintf(tracefile, "heap_top\t0x%lx\n", heap_top);
656 #ifdef PSEUDO_GENERATIONAL
657 generation_start = heap_top;
664 gc_mark_object_at (void** addr)
667 * A note concerning the order of the tests:
669 * Statistics collected during a test run, where alignment
670 * was tested before checking whether the addr points into
672 * >> LOG: 9301464 bytes for 196724 objects allocated.
673 * >> LOG: 15 garbage collections performed.
674 * >> LOG: 6568440 heapblocks visited, 469249 objects marked
675 * >> LOG: 1064447 visits to objects already marked.
676 * >> LOG: 988270 potential references not aligned.
677 * >> LOG: 4049446 out of heap.
678 * >> LOG: 5236 not an object.
680 * These results show, that only about 1/4 of all heapblocks
681 * point to objects; The single most important reason why a
682 * heapblock can not point at an object is, that it's value
683 * doesn't fall within the heap area (this test was performed
686 * From the results, the various tests have to be conducted
687 * in the following order for maximum efficiency:
689 * 2. already marked ?
693 * The results after reordering:
694 * >> LOG: 9301464 bytes for 196724 objects allocated.
695 * >> LOG: 15 garbage collections performed.
696 * >> LOG: 6568440 heapblocks visited, 469249 objects marked
697 * >> LOG: 1064447 visits to objects already marked.
698 * >> LOG: 350 potential references not aligned.
699 * >> LOG: 5037366 out of heap.
700 * >> LOG: 5236 not an object.
704 * 2. already marked ?
708 * >> LOG: 9301464 bytes for 196724 objects allocated.
709 * >> LOG: 15 garbage collections performed.
710 * >> LOG: 6568440 heapblocks visited, 469249 objects marked
711 * >> LOG: 5037366 out of heap.
712 * >> LOG: 1064456 visits to objects already marked.
713 * >> LOG: 5539 not an object.
714 * >> LOG: 38 potential references not aligned.
716 * Apparently, most unaligned values will already be eliminated
717 * when checking against the bounds of the heap. Checking this
718 * property first, should thus improve collection times.
722 /* 1.a. if addr doesn't point into the heap, return. */
723 if ((unsigned long)addr - (unsigned long)heap_base >=
724 ((long)heap_top - (long)heap_base)) {
725 #ifdef GC_COLLECT_STATISTICS
726 ++gc_mark_not_inheap;
731 /* 1.b. if align(addr) has already been marked during this collection, return. */
732 if (bitmap_testbit(mark_bits, (void*)addr)) {
733 #ifdef GC_COLLECT_STATISTICS
734 ++gc_mark_already_marked;
739 /* 1.c. if align(addr) doesn't point to the start of an object, return. */
740 if (!bitmap_testbit(start_bits, (void*)addr)) {
741 #ifdef GC_COLLECT_STATISTICS
742 ++gc_mark_not_object;
747 /* 1.d. if addr is not properly aligned, return. */
748 if ((long)addr & ((1 << ALIGN) - 1)) {
749 #ifdef GC_COLLECT_STATISTICS
750 ++gc_mark_not_aligned;
755 /* 2. Mark the object at addr */
756 bitmap_setbit(mark_bits, (void*)addr);
757 #ifdef GC_COLLECT_STATISTICS
758 ++gc_mark_objects_marked;
761 #ifdef JIT_MARKER_SUPPORT
762 asm_calljavamethod(addr->vftbl->class->marker, addr, NULL, NULL, NULL);
765 /* 3. mark the references contained within the extents of the object at addr */
766 if (bitmap_testbit(reference_bits, addr)) {
767 /* 3.1. find the end of the object */
770 #ifdef SIZE_FROM_CLASSINFO
771 if (((java_objectheader*)addr)->vftbl == class_array->vftbl)
772 end = (void**)((long)addr + (long)((java_arrayheader*)addr)->alignedsize);
774 end = (void**)((long)addr + (long)((java_objectheader*)addr)->vftbl->class->alignedsize);
776 end = (void**)bitmap_find_next_setbit(start_bitmap, addr + 1); /* points just behind the object */
779 /* 3.2. mark the references within the object at addr */
780 #ifdef GC_COLLECT_STATISTICS
781 gc_mark_heapblocks_visited += ((long)end - (long)addr) >> ALIGN;
784 gc_mark_object_at(*(addr++));
794 void gc_mark_references (void)
796 address_list_node* curr = references;
799 gc_mark_object_at(*((void**)(curr->address)));
807 markreferences(void** start, void** end)
810 gc_mark_object_at(*(start++));
815 void gc_mark_stack (void)
822 if (currentThread == NULL) {
823 void **top_of_stack = &dummy;
825 if (top_of_stack > stackbottom)
826 markreferences(stackbottom, top_of_stack);
828 markreferences(top_of_stack, stackbottom);
831 for (aThread = liveThreads; aThread != 0;
832 aThread = CONTEXT(aThread).nextlive) {
833 gc_mark_object_at((void*)aThread);
834 if (CONTEXT(aThread).usedStackTop > CONTEXT(aThread).stackEnd)
835 markreferences((void**)CONTEXT(aThread).stackEnd,
836 (void**)CONTEXT(aThread).usedStackTop);
838 markreferences((void**)CONTEXT(aThread).usedStackTop,
839 (void**)CONTEXT(aThread).stackEnd);
842 markreferences((void**)&threadQhead[0],
843 (void**)&threadQhead[MAX_THREAD_PRIO]);
846 void **top_of_stack = &dummy;
848 if (top_of_stack > stackbottom)
849 markreferences(stackbottom, top_of_stack);
851 markreferences(top_of_stack, stackbottom);
859 static int armageddon_is_near = 0;
861 if (armageddon_is_near) {
862 /* armageddon_is_here! */
863 fprintf(stderr, "Oops, seems like there's a slight problem here: gc_run() called while still running?!\n");
867 armageddon_is_near = true;
868 heap_next_collection = heap_limit; /* try to avoid finalizer-induced collections */
870 bitmap_clear(mark_bitmap);
872 asm_dumpregistersandcall(gc_mark_stack);
873 gc_mark_references();
877 armageddon_is_near = false;
879 #ifdef GC_COLLECT_STATISTICS
880 ++gc_collections_count;
885 /************************* Function: gc_init **********************************
887 Initializes anything that must be initialized to call the gc on the right
890 ******************************************************************************/
897 /************************** Function: gc_call ********************************
899 Calls the garbage collector. The garbage collector should always be called
900 using this function since it ensures that enough stack space is available.
902 ******************************************************************************/
910 assert(blockInts == 0);
913 if (currentThread == NULL || currentThread == mainThread) {
914 CONTEXT(mainThread).usedStackTop = &dummy;
918 asm_switchstackandcall(CONTEXT(mainThread).usedStackTop, gc_run,
919 (void**)&(CONTEXT(currentThread).usedStackTop));
929 * These are local overrides for various environment variables in Emacs.
930 * Please do not remove this and leave it at the end of the file, where
931 * Emacs will automagically detect them.
932 * ---------------------------------------------------------------------
935 * indent-tabs-mode: t