mirror of
https://github.com/justinethier/cyclone.git
synced 2025-07-08 05:27:33 +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
|
* @brief Sweep portion of the GC algorithm
|
||||||
* @param h Heap to sweep
|
* @param h Heap to sweep
|
||||||
* @param heap_type Type of heap, based on object sizes allocated on it
|
* @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
|
* @param thd Thread data object for the mutator using this heap
|
||||||
* @return Return the size of the largest object freed, in bytes
|
* @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
|
* memory slots to the heap. It is only called by the collector thread after
|
||||||
* the heap has been traced to identify live objects.
|
* 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
|
// 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;
|
short heap_is_empty;
|
||||||
object p;
|
object p;
|
||||||
gc_free_list *q, *r, *s;
|
gc_free_list *q, *r, *s;
|
||||||
#if GC_DEBUG_SHOW_SWEEP_DIAG
|
#if GC_DEBUG_SHOW_SWEEP_DIAG
|
||||||
gc_heap *orig_heap_ptr = h;
|
gc_heap *orig_heap_ptr = h;
|
||||||
#endif
|
#endif
|
||||||
gc_heap *prev_h = NULL;
|
//gc_heap *prev_h = NULL;
|
||||||
gc_heap *rv = h;
|
gc_heap *rv = h;
|
||||||
|
|
||||||
h->next_free = 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) {
|
if (h->data_end != NULL) {
|
||||||
// Special case, bump&pop heap
|
// 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
|
heap_is_empty = 0; // For now, don't try to free bump&pop
|
||||||
} else {
|
} else {
|
||||||
//gc_free_list *next;
|
//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
|
// free p
|
||||||
heap_freed += h->block_size;
|
//heap_freed += h->block_size;
|
||||||
if (h->free_list == NULL) {
|
if (h->free_list == NULL) {
|
||||||
// No free list, start one at p
|
// No free list, start one at p
|
||||||
q = h->free_list = 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;
|
q->next = s;
|
||||||
//printf("sweep reclaimed remaining=%d, %p, q=%p, r=%p\n", remaining, p, q, r);
|
//printf("sweep reclaimed remaining=%d, %p, q=%p, r=%p\n", remaining, p, q, r);
|
||||||
}
|
}
|
||||||
|
h->free_size += h->block_size;
|
||||||
} else {
|
} else {
|
||||||
//printf("sweep block is still used remaining=%d p = %p\n", remaining, p);
|
//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)
|
int gc_is_heap_empty(gc_heap *h)
|
||||||
{
|
{
|
||||||
gc_free_list *f;
|
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;
|
f = h->free_list;
|
||||||
if (f->size != 0 || !f->next) return 0;
|
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);
|
ck_pr_sub_ptr(&(thd->cached_heap_free_sizes[heap_type]), size);
|
||||||
|
|
||||||
h_passed->next_free = h;
|
h_passed->next_free = h;
|
||||||
|
h->free_size -= size;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
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
|
* @brief A convenience function for allocating bignums
|
||||||
* @param data The mutator's thread data object
|
* @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;
|
gc_heap *h_passed, *h = NULL;
|
||||||
int heap_type;
|
int heap_type;
|
||||||
void *(*try_alloc)(gc_heap * h, int heap_type, size_t size, char *obj, gc_thread_data * thd);
|
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
|
// TODO: check return value, if null (could not alloc) then
|
||||||
// run a collection and check how much free space there is. if less
|
// run a collection and check how much free space there is. if less
|
||||||
// the allowed ratio, try growing heap.
|
// 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) {
|
if (size <= 32) {
|
||||||
heap_type = HEAP_SM;
|
heap_type = HEAP_SM;
|
||||||
try_alloc = &gc_try_alloc_fixed_size;
|
try_alloc = &gc_try_alloc_fixed_size;
|
||||||
|
try_alloc_slow = &gc_try_alloc_slow_fixed_size;
|
||||||
} else if (size <= 64) {
|
} else if (size <= 64) {
|
||||||
heap_type = HEAP_64;
|
heap_type = HEAP_64;
|
||||||
try_alloc = &gc_try_alloc_fixed_size;
|
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
|
// Only use this heap on 64-bit platforms, where larger objs are used more often
|
||||||
// Code from http://stackoverflow.com/a/32717129/101258
|
// Code from http://stackoverflow.com/a/32717129/101258
|
||||||
#if INTPTR_MAX == INT64_MAX
|
#if INTPTR_MAX == INT64_MAX
|
||||||
} else if (size <= 96) {
|
} else if (size <= 96) {
|
||||||
heap_type = HEAP_96;
|
heap_type = HEAP_96;
|
||||||
try_alloc = &gc_try_alloc_fixed_size;
|
try_alloc = &gc_try_alloc_fixed_size;
|
||||||
|
try_alloc_slow = &gc_try_alloc_slow_fixed_size;
|
||||||
#endif
|
#endif
|
||||||
} else if (size >= MAX_STACK_OBJ) {
|
} else if (size >= MAX_STACK_OBJ) {
|
||||||
heap_type = HEAP_HUGE;
|
heap_type = HEAP_HUGE;
|
||||||
try_alloc = &gc_try_alloc;
|
try_alloc = &gc_try_alloc;
|
||||||
|
try_alloc_slow = &gc_try_alloc_slow;
|
||||||
} else {
|
} else {
|
||||||
heap_type = HEAP_REST;
|
heap_type = HEAP_REST;
|
||||||
try_alloc = &gc_try_alloc;
|
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
|
//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
|
//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];
|
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 {
|
} else {
|
||||||
// Slow path, find another heap block
|
// Slow path, find another heap block
|
||||||
h->is_full = 1;
|
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
|
#if GC_DEBUG_VERBOSE
|
||||||
fprintf(stderr, "slow alloc of %p\n", result);
|
fprintf(stderr, "slow alloc of %p\n", result);
|
||||||
#endif
|
#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
|
// 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
|
// 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
|
// 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
|
#if GC_DEBUG_VERBOSE
|
||||||
fprintf(stderr, "slowest alloc of %p\n", result);
|
fprintf(stderr, "slowest alloc of %p\n", result);
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Reference in a new issue