Make Gen-0 size semi-independent of Gen-1 minimum size.
This commit is contained in:
parent
7f55142d72
commit
632ac19adf
37
gc.c
37
gc.c
|
|
@ -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
13
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;
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue