1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-14 09:40:20 +02:00

More efficient sweep

This commit is contained in:
Andy Wingo 2022-03-10 15:51:11 +01:00
parent 5c8a8a2d3e
commit 5edc4fa81a

View file

@ -312,6 +312,21 @@ static size_t live_object_granules(struct gcobj *obj) {
return small_object_granule_sizes[granules_to_small_object_size(granules)]; return small_object_granule_sizes[granules_to_small_object_size(granules)];
} }
static size_t next_mark(const uint8_t *mark, size_t limit) {
size_t n = 0;
for (; (((uintptr_t)mark) & 7) && n < limit; n++)
if (mark[n])
return n;
uintptr_t *word_mark = (uintptr_t *)(mark + n);
for (; n < limit; n += sizeof(uintptr_t), word_mark++)
if (word_mark)
break;
for (; n < limit; n++)
if (mark[n])
return n;
return limit;
}
// Sweep some heap to reclaim free space. Return 1 if there is more // Sweep some heap to reclaim free space. Return 1 if there is more
// heap to sweep, or 0 if we reached the end. // heap to sweep, or 0 if we reached the end.
static int sweep(struct context *cx) { static int sweep(struct context *cx) {
@ -322,25 +337,26 @@ static int sweep(struct context *cx) {
uintptr_t limit = cx->base + cx->size; uintptr_t limit = cx->base + cx->size;
while (to_reclaim > 0 && sweep < limit) { while (to_reclaim > 0 && sweep < limit) {
uintptr_t sweep_base = sweep; uint8_t* mark = mark_byte(cx, (struct gcobj*)sweep);
struct gcobj *obj = (struct gcobj*)sweep_base; size_t free_granules = next_mark(mark,
uint8_t* mark = mark_byte(cx, obj); (limit - sweep) >> GRANULE_SIZE_LOG_2);
if (*mark) { if (free_granules) {
// Object survived collection; clear mark and continue sweeping. size_t free_bytes = free_granules * GRANULE_SIZE;
ASSERT(*mark == 1); memset((void*)(sweep + GRANULE_SIZE),
*mark = 0;
sweep += live_object_granules(obj) * GRANULE_SIZE;
} else {
// Found a free object. Combine with any following free space.
// To avoid fragmentation, don't limit the amount to reclaim.
do {
sweep += GRANULE_SIZE, to_reclaim--, mark++;
} while (sweep < limit && !*mark);
memset((void*)(sweep_base + GRANULE_SIZE),
0, 0,
sweep - sweep_base - GRANULE_SIZE); free_bytes - GRANULE_SIZE);
reclaim(cx, obj, (sweep - sweep_base) >> GRANULE_SIZE_LOG_2); reclaim(cx, (void*)sweep, free_granules);
sweep += free_bytes;
to_reclaim -= free_granules;
mark += free_granules;
if (sweep == limit)
break;
} }
// Object survived collection; clear mark and continue sweeping.
ASSERT(*mark == 1);
*mark = 0;
sweep += live_object_granules((struct gcobj *)sweep) * GRANULE_SIZE;
} }
cx->sweep = sweep; cx->sweep = sweep;