Make Gen-0 size semi-independent of Gen-1 minimum size.

This commit is contained in:
Jesse D. McDonald 2010-04-10 03:14:58 -05:00
parent 7f55142d72
commit 632ac19adf
2 changed files with 37 additions and 19 deletions

37
gc.c
View File

@ -387,10 +387,10 @@ static inline size_t gc_align(size_t nbytes)
return ((nbytes + GC_ALIGNMENT - 1) & ~(GC_ALIGNMENT - 1)); 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_gen0_init(gen0_size);
gc_gen1_init(min_size, max_size); gc_gen1_init(gen1_min_size, gen1_max_size);
gc_weak_box_list = NIL; gc_weak_box_list = NIL;
gc_will_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(). */ /* These private variables are exported ONLY for use by is_gen0_object(). */
char *gc_gen0_range; 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_free_ptr;
static char *gc_gen0_range_end;
/* Used to signal that Gen-0 pass has been obviated by Gen-1 collection. */ /* Used to signal that Gen-0 pass has been obviated by Gen-1 collection. */
static jmp_buf gc_gen0_end_ctx; static jmp_buf gc_gen0_end_ctx;
@ -455,6 +455,10 @@ static void collect_gen0_garbage(void)
{ {
if (gc_enabled) if (gc_enabled)
{ {
#ifndef NDEBUG
size_t initial_gen1_free_space;
#endif
#ifndef NO_STATS #ifndef NO_STATS
size_t initial_free_space; size_t initial_free_space;
#ifndef NO_TIMING_STATS #ifndef NO_TIMING_STATS
@ -469,6 +473,10 @@ static void collect_gen0_garbage(void)
assert(!gc_in_gen0_collection); assert(!gc_in_gen0_collection);
assert(!gc_in_gen1_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. */ /* If we trigger a Gen-1 collection at any point then we are done. */
/* Full collection will pull in any current Gen-0 objects. */ /* Full collection will pull in any current Gen-0 objects. */
if (setjmp(gc_gen0_end_ctx) == 0) 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. */ /* 4. Reset Gen-0 range to 'empty' state. */
gc_gen0_free_ptr = gc_gen0_range; 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_STATS
#ifndef NO_TIMING_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) 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[0] = (char*)malloc(max_size);
gc_gen1_ranges[1] = (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_min_size = min_size;
gc_gen1_max_size = max_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_range_end = gc_gen1_free_ptr + gc_gen1_soft_limit;
gc_gen1_max_blocks = ((size_t)2 << 30) / GC_DIRTY_BLOCK_SIZE; 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) 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) 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); min_free = nbytes = gc_align(nbytes);
/* Ensure there is always enough room for a full collection. */
if (!gc_in_gen1_collection) if (!gc_in_gen1_collection)
min_free += gc_gen0_size; min_free += gc_gen0_size;
if (gc_gen1_free_space() < min_free) if (gc_gen1_free_space() < min_free)
collect_gen1_garbage(nbytes); collect_gen1_garbage(min_free);
assert(nbytes <= gc_gen1_free_space()); assert(nbytes <= gc_gen1_free_space());
@ -1029,11 +1043,14 @@ static size_t gc_gen1_block_of(void *obj)
} }
void _gc_mark_updated_gen1_object(value_t v) void _gc_mark_updated_gen1_object(value_t v)
{
assert(is_object(v));
{ {
const size_t block = gc_gen1_block_of(_get_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]); assert(is_object(v) && !is_gen0_object(v) && gc_gen1_block_starts[block]);
gc_gen1_dirty_bits[block / 32] |= (1UL << (block % 32)); gc_gen1_dirty_bits[block / 32] |= (1UL << (block % 32));
} }
}
static void _out_of_memory(void) __attribute__ ((noreturn)); static void _out_of_memory(void) __attribute__ ((noreturn));
static void _out_of_memory(void) static void _out_of_memory(void)
@ -1120,7 +1137,7 @@ static void collect_gen1_garbage(size_t min_free)
gc_gen0_free_ptr = gc_gen0_range; gc_gen0_free_ptr = gc_gen0_range;
collected_garbage = true; 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_in_gen1_collection = false;
gc_enabled = true; gc_enabled = true;

13
gc.h
View File

@ -388,7 +388,7 @@ static inline builtin_fn_t *_get_builtin_fn(value_t v)
return ((builtin_fn_object_t*)_get_object(v))->fn; 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 clear_gc_stats(void);
void register_gc_root(gc_root_t *root, value_t v); void register_gc_root(gc_root_t *root, value_t v);
void unregister_gc_root(gc_root_t *root); 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. */ /* These private variables are exported ONLY for use by this inline function. */
extern char *gc_gen0_range; 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); const char const *obj = (const char*)_get_object(v);
return is_object(v) return (obj < gc_gen0_range_end)
&& (obj >= (char*)gc_gen0_range) && (obj >= gc_gen0_range)
&& ((obj - (char*)gc_gen0_range) < gc_gen0_size); && is_object(v);
} }
/* Don't call this directly; use the WRITE_BARRIER macro. */ /* Don't call this directly; use the WRITE_BARRIER macro. */
static inline void _gc_write_barrier(value_t v) 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); _gc_mark_updated_gen1_object(v);
} }