From 632ac19adf3667d24f37684eeb51e75510558347 Mon Sep 17 00:00:00 2001 From: Jesse McDonald Date: Sat, 10 Apr 2010 03:14:58 -0500 Subject: [PATCH] Make Gen-0 size semi-independent of Gen-1 minimum size. --- gc.c | 43 ++++++++++++++++++++++++++++++------------- gc.h | 13 +++++++------ 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/gc.c b/gc.c index c494bce..c64c3e0 100644 --- a/gc.c +++ b/gc.c @@ -387,10 +387,10 @@ static inline size_t gc_align(size_t nbytes) return ((nbytes + GC_ALIGNMENT - 1) & ~(GC_ALIGNMENT - 1)); } -void gc_init(size_t min_size, size_t max_size) +void gc_init(size_t gen0_size, size_t gen1_min_size, size_t gen1_max_size) { - gc_gen0_init(min_size); - gc_gen1_init(min_size, max_size); + gc_gen0_init(gen0_size); + gc_gen1_init(gen1_min_size, gen1_max_size); gc_weak_box_list = NIL; gc_will_list = NIL; @@ -426,10 +426,10 @@ static void gc_poison_region(void *start, size_t size, value_t tag) /* These private variables are exported ONLY for use by is_gen0_object(). */ char *gc_gen0_range; -size_t gc_gen0_size; +char *gc_gen0_range_end; +static size_t gc_gen0_size; static char *gc_gen0_free_ptr; -static char *gc_gen0_range_end; /* Used to signal that Gen-0 pass has been obviated by Gen-1 collection. */ static jmp_buf gc_gen0_end_ctx; @@ -455,6 +455,10 @@ static void collect_gen0_garbage(void) { if (gc_enabled) { +#ifndef NDEBUG + size_t initial_gen1_free_space; +#endif + #ifndef NO_STATS size_t initial_free_space; #ifndef NO_TIMING_STATS @@ -469,6 +473,10 @@ static void collect_gen0_garbage(void) assert(!gc_in_gen0_collection); assert(!gc_in_gen1_collection); +#ifndef NDEBUG + initial_gen1_free_space = gc_gen1_free_space(); +#endif + /* If we trigger a Gen-1 collection at any point then we are done. */ /* Full collection will pull in any current Gen-0 objects. */ if (setjmp(gc_gen0_end_ctx) == 0) @@ -548,6 +556,8 @@ static void collect_gen0_garbage(void) /* 4. Reset Gen-0 range to 'empty' state. */ gc_gen0_free_ptr = gc_gen0_range; + //debug(("Finished Gen-0 collection; added %d bytes to Gen-1 heap.\n", initial_gen1_free_space - gc_gen1_free_space())); + #ifndef NO_STATS #ifndef NO_TIMING_STATS { @@ -644,7 +654,9 @@ static inline bool gc_object_left_behind(value_t v) static void gc_gen1_init(size_t min_size, size_t max_size) { - release_assert(min_size <= ((max_size+1)/2)); + release_assert(gc_gen0_size > 0); + release_assert(max_size >= gc_gen0_size); + release_assert(min_size <= (max_size - gc_gen0_size)); gc_gen1_ranges[0] = (char*)malloc(max_size); gc_gen1_ranges[1] = (char*)malloc(max_size); @@ -656,7 +668,7 @@ static void gc_gen1_init(size_t min_size, size_t max_size) gc_gen1_min_size = min_size; gc_gen1_max_size = max_size; - gc_gen1_soft_limit = 2*min_size; + gc_gen1_soft_limit = min_size + gc_gen0_size; gc_gen1_range_end = gc_gen1_free_ptr + gc_gen1_soft_limit; gc_gen1_max_blocks = ((size_t)2 << 30) / GC_DIRTY_BLOCK_SIZE; @@ -670,7 +682,8 @@ static void gc_gen1_init(size_t min_size, size_t max_size) static void gc_gen1_clear_dirty_bits(void) { - memset(gc_gen1_dirty_bits, 0, sizeof(uint32_t) * ((gc_gen1_max_blocks + 31) / 32)); + const size_t block_groups = (gc_gen1_max_blocks + 31) / 32; + memset(gc_gen1_dirty_bits, 0, sizeof(uint32_t) * block_groups); } static void *gc_alloc_gen1(size_t nbytes) @@ -679,11 +692,12 @@ static void *gc_alloc_gen1(size_t nbytes) min_free = nbytes = gc_align(nbytes); + /* Ensure there is always enough room for a full collection. */ if (!gc_in_gen1_collection) min_free += gc_gen0_size; if (gc_gen1_free_space() < min_free) - collect_gen1_garbage(nbytes); + collect_gen1_garbage(min_free); assert(nbytes <= gc_gen1_free_space()); @@ -1030,9 +1044,12 @@ static size_t gc_gen1_block_of(void *obj) void _gc_mark_updated_gen1_object(value_t v) { - const size_t block = gc_gen1_block_of(_get_object(v)); - assert(is_object(v) && !is_gen0_object(v) && gc_gen1_block_starts[block]); - gc_gen1_dirty_bits[block / 32] |= (1UL << (block % 32)); + assert(is_object(v)); + { + const size_t block = gc_gen1_block_of(_get_object(v)); + assert(is_object(v) && !is_gen0_object(v) && gc_gen1_block_starts[block]); + gc_gen1_dirty_bits[block / 32] |= (1UL << (block % 32)); + } } static void _out_of_memory(void) __attribute__ ((noreturn)); @@ -1120,7 +1137,7 @@ static void collect_gen1_garbage(size_t min_free) gc_gen0_free_ptr = gc_gen0_range; collected_garbage = true; - //debug(("Finished collection with %d bytes to spare (out of %d bytes).\n", gc_gen1_free_space(), gc_gen1_soft_limit)); + //debug(("Finished Gen-1 collection; active set is %d bytes.\n", gc_gen1_free_ptr - gc_gen1_ranges[gc_gen1_current_range])); gc_in_gen1_collection = false; gc_enabled = true; diff --git a/gc.h b/gc.h index 36d5294..4b61ae9 100644 --- a/gc.h +++ b/gc.h @@ -388,7 +388,7 @@ static inline builtin_fn_t *_get_builtin_fn(value_t v) return ((builtin_fn_object_t*)_get_object(v))->fn; } -void gc_init(size_t min_size, size_t max_size); +void gc_init(size_t gen0_size, size_t gen1_min_size, size_t gen1_max_size); void clear_gc_stats(void); void register_gc_root(gc_root_t *root, value_t v); void unregister_gc_root(gc_root_t *root); @@ -414,18 +414,19 @@ static inline bool is_gen0_object(value_t v) { /* These private variables are exported ONLY for use by this inline function. */ extern char *gc_gen0_range; - extern size_t gc_gen0_size; + extern char *gc_gen0_range_end; const char const *obj = (const char*)_get_object(v); - return is_object(v) - && (obj >= (char*)gc_gen0_range) - && ((obj - (char*)gc_gen0_range) < gc_gen0_size); + return (obj < gc_gen0_range_end) + && (obj >= gc_gen0_range) + && is_object(v); } /* Don't call this directly; use the WRITE_BARRIER macro. */ static inline void _gc_write_barrier(value_t v) { - if (is_object(v) && !is_gen0_object(v)) + assert(is_object(v)); + if (!is_gen0_object(v)) { _gc_mark_updated_gen1_object(v); }