mirror of
https://github.com/justinethier/cyclone.git
synced 2025-05-22 07:09:17 +02:00
Fixing up fixed-size heaps
This commit is contained in:
parent
7994354835
commit
c89a434bf9
1 changed files with 73 additions and 14 deletions
87
gc.c
87
gc.c
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue