Fixing up fixed-size heaps

This commit is contained in:
Justin Ethier 2018-07-16 18:33:30 -04:00
parent 7994354835
commit c89a434bf9

87
gc.c
View file

@ -528,8 +528,6 @@ size_t gc_convert_heap_page_to_free_list(gc_heap *h, gc_thread_data *thd)
* @brief Sweep portion of the GC algorithm
* @param h Heap to sweep
* @param heap_type Type of heap, based on object sizes allocated on it
* @param sum_freed_ptr Out parameter tracking the sum of freed data, in bytes.
* This parameter is ignored if NULL is passed.
* @param thd Thread data object for the mutator using this heap
* @return Return the size of the largest object freed, in bytes
*
@ -537,17 +535,17 @@ size_t gc_convert_heap_page_to_free_list(gc_heap *h, gc_thread_data *thd)
* memory slots to the heap. It is only called by the collector thread after
* the heap has been traced to identify live objects.
*/
void gc_sweep_fixed_size(gc_heap * h, int heap_type, size_t * sum_freed_ptr, gc_thread_data *thd)
gc_heap *gc_sweep_fixed_size(gc_heap * h, int heap_type, gc_thread_data *thd)
{
// TODO: all of this needs to be reworked, see gc_sweep
size_t heap_freed = 0, sum_freed = 0;
//size_t heap_freed = 0, sum_freed = 0;
short heap_is_empty;
object p;
gc_free_list *q, *r, *s;
#if GC_DEBUG_SHOW_SWEEP_DIAG
gc_heap *orig_heap_ptr = h;
#endif
gc_heap *prev_h = NULL;
//gc_heap *prev_h = NULL;
gc_heap *rv = h;
h->next_free = h;
@ -561,7 +559,7 @@ void gc_sweep_fixed_size(gc_heap * h, int heap_type, size_t * sum_freed_ptr, gc_
if (h->data_end != NULL) {
// Special case, bump&pop heap
heap_freed = gc_convert_heap_page_to_free_list(h, thd);
gc_convert_heap_page_to_free_list(h, thd);
heap_is_empty = 0; // For now, don't try to free bump&pop
} else {
//gc_free_list *next;
@ -629,7 +627,7 @@ void gc_sweep_fixed_size(gc_heap * h, int heap_type, size_t * sum_freed_ptr, gc_
}
// free p
heap_freed += h->block_size;
//heap_freed += h->block_size;
if (h->free_list == NULL) {
// No free list, start one at p
q = h->free_list = p;
@ -650,7 +648,7 @@ void gc_sweep_fixed_size(gc_heap * h, int heap_type, size_t * sum_freed_ptr, gc_
q->next = s;
//printf("sweep reclaimed remaining=%d, %p, q=%p, r=%p\n", remaining, p, q, r);
}
h->free_size += h->block_size;
} else {
//printf("sweep block is still used remaining=%d p = %p\n", remaining, p);
}
@ -749,7 +747,13 @@ gc_heap *gc_heap_free(gc_heap *page, gc_heap *prev_page)
int gc_is_heap_empty(gc_heap *h)
{
gc_free_list *f;
if (!h || !h->free_list) return 0;
if (!h) return 0;
if (h->data_end) { // Bump&pop
return (h->remaining == (h->size - (h->size % h->block_size)));
}
if (!h->free_list) return 0;
f = h->free_list;
if (f->size != 0 || !f->next) return 0;
@ -1232,12 +1236,63 @@ void *gc_try_alloc_fixed_size(gc_heap * h, int heap_type, size_t size, char *obj
ck_pr_sub_ptr(&(thd->cached_heap_free_sizes[heap_type]), size);
h_passed->next_free = h;
h->free_size -= size;
return result;
}
}
return NULL;
}
void *gc_try_alloc_slow_fixed_size(gc_heap *h_passed, gc_heap *h, int heap_type, size_t size, char *obj, gc_thread_data *thd)
{
gc_heap *h_start = h, *h_prev;
void *result = NULL;
// Find next heap
while (result == NULL) {
h_prev = h;
h = h->next;
if (h == NULL) {
// Wrap around to the first heap block
h_prev = NULL;
h = h_passed;
}
if (h == h_start) {
// Tried all and no heap exists with free space
break;
}
// check allocation status to make sure we can use it
if (h->is_full) {
continue; // Cannot sweep until next GC cycle
} else if (h->cached_free_size_status == 1 && !gc_is_heap_empty(h)) {
unsigned int h_size = h->size;
gc_heap *keep = gc_sweep_fixed_size(h, heap_type, thd); // Clean up garbage objects
if (!keep) {
// Heap marked for deletion, remove it and keep searching
gc_heap *freed = gc_heap_free(h, h_prev);
if (freed) {
if (h_prev) {
h = h_prev;
} else {
h = h_passed;
}
//thd->cached_heap_free_sizes[heap_type] -= prev_free_size;
thd->cached_heap_total_sizes[heap_type] -= h_size;
continue;
}
}
}
result = gc_try_alloc_fixed_size(h, heap_type, size, obj, thd);
if (result) {
h_passed->next_free = h;
h_passed->last_alloc_size = size;
} else {
// TODO: else, assign heap full? YES for fixed-size, for REST maybe not??
h->is_full = 1;
}
}
return result;
}
/**
* @brief A convenience function for allocating bignums
* @param data The mutator's thread data object
@ -1294,6 +1349,7 @@ void *gc_alloc(gc_heap_root * hrt, size_t size, char *obj, gc_thread_data * thd,
gc_heap *h_passed, *h = NULL;
int heap_type;
void *(*try_alloc)(gc_heap * h, int heap_type, size_t size, char *obj, gc_thread_data * thd);
void *(*try_alloc_slow)(gc_heap *h_passed, gc_heap *h, int heap_type, size_t size, char *obj, gc_thread_data *thd);
// TODO: check return value, if null (could not alloc) then
// run a collection and check how much free space there is. if less
// the allowed ratio, try growing heap.
@ -1302,26 +1358,29 @@ void *gc_alloc(gc_heap_root * hrt, size_t size, char *obj, gc_thread_data * thd,
if (size <= 32) {
heap_type = HEAP_SM;
try_alloc = &gc_try_alloc_fixed_size;
try_alloc_slow = &gc_try_alloc_slow_fixed_size;
} else if (size <= 64) {
heap_type = HEAP_64;
try_alloc = &gc_try_alloc_fixed_size;
try_alloc_slow = &gc_try_alloc_slow_fixed_size;
// Only use this heap on 64-bit platforms, where larger objs are used more often
// Code from http://stackoverflow.com/a/32717129/101258
#if INTPTR_MAX == INT64_MAX
} else if (size <= 96) {
heap_type = HEAP_96;
try_alloc = &gc_try_alloc_fixed_size;
try_alloc_slow = &gc_try_alloc_slow_fixed_size;
#endif
} else if (size >= MAX_STACK_OBJ) {
heap_type = HEAP_HUGE;
try_alloc = &gc_try_alloc;
try_alloc_slow = &gc_try_alloc_slow;
} else {
heap_type = HEAP_REST;
try_alloc = &gc_try_alloc;
try_alloc_slow = &gc_try_alloc_slow;
}
TODO: in addition to below, probably need to update fixed size code to work with gc_heap_free_size and gc_is_heap_empty (though for that one we may just call another function in the fixed-size heap code
TODO: convert fixed-size heap code and use that here. BUT, create a version of gc_alloc (maybe using macros?)
//TODO: convert fixed-size heap code and use that here. BUT, create a version of gc_alloc (maybe using macros?)
//that accepts heap type as an arg and can assume free lists. we can modify gc_move to use the proper new
//version of gc_alloc (just ifdef if need be for 32 vs 64 bit. this might speed things up a bit
h = hrt->heap[heap_type];
@ -1341,7 +1400,7 @@ TODO: convert fixed-size heap code and use that here. BUT, create a version of g
} else {
// Slow path, find another heap block
h->is_full = 1;
result = gc_try_alloc_slow(h_passed, h, heap_type, size, obj, thd);
result = try_alloc_slow(h_passed, h, heap_type, size, obj, thd);
#if GC_DEBUG_VERBOSE
fprintf(stderr, "slow alloc of %p\n", result);
#endif
@ -1361,7 +1420,7 @@ fprintf(stderr, "slow alloc of %p\n", result);
// TODO: would be nice if gc_grow_heap returns new page (maybe it does) then we can start from there
// otherwise will be a bit of a bottleneck since with lazy sweeping there is no guarantee we are at
// the end of the heap anymore
result = gc_try_alloc_slow(h_passed, h, heap_type, size, obj, thd);
result = try_alloc_slow(h_passed, h, heap_type, size, obj, thd);
#if GC_DEBUG_VERBOSE
fprintf(stderr, "slowest alloc of %p\n", result);
#endif