1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-12 16:50:22 +02:00

mark-sweep: Update markers to deal in heap and spaces

This will let us get rid of "struct context".
This commit is contained in:
Andy Wingo 2022-03-29 08:59:27 +02:00
parent 2401732e31
commit 9b0bc6e975
3 changed files with 67 additions and 58 deletions

View file

@ -136,8 +136,8 @@ static inline struct context* mutator_context(struct mutator *mut) {
return mark_space_context(mutator_mark_space(mut));
}
static inline struct marker* context_marker(struct context *cx) {
return &cx->marker;
static inline struct marker* mark_space_marker(struct mark_space *space) {
return &mark_space_context(space)->marker;
}
static inline struct gcobj_free**
@ -154,15 +154,16 @@ static inline void clear_memory(uintptr_t addr, size_t size) {
static void collect(struct mutator *mut) NEVER_INLINE;
static inline uint8_t* mark_byte(struct context *cx, struct gcobj *obj) {
static inline uint8_t* mark_byte(struct mark_space *space, struct gcobj *obj) {
struct context *cx = mark_space_context(space);
ASSERT(cx->heap_base <= (uintptr_t) obj);
ASSERT((uintptr_t) obj < cx->heap_base + cx->heap_size);
uintptr_t granule = (((uintptr_t) obj) - cx->heap_base) / GRANULE_SIZE;
return &cx->mark_bytes[granule];
}
static inline int mark_object(struct context *cx, struct gcobj *obj) {
uint8_t *byte = mark_byte(cx, obj);
static inline int mark_object(struct mark_space *space, struct gcobj *obj) {
uint8_t *byte = mark_byte(space, obj);
if (*byte)
return 0;
*byte = 1;
@ -189,13 +190,17 @@ static void clear_freelists(struct context *cx) {
}
static void collect(struct mutator *mut) {
struct mark_space *space = mutator_mark_space(mut);
struct context *cx = mutator_context(mut);
DEBUG("start collect #%ld:\n", cx->count);
marker_prepare(cx);
for (struct handle *h = mut->roots; h; h = h->next)
marker_visit_root(&h->v, cx);
marker_trace(cx);
marker_release(cx);
marker_prepare(space);
for (struct handle *h = mut->roots; h; h = h->next) {
struct gcobj *root = h->v;
if (root && mark_object(space, root))
marker_enqueue_root(mark_space_marker(space), root);
}
marker_trace(space);
marker_release(space);
DEBUG("done marking\n");
cx->sweep = cx->heap_base;
clear_freelists(cx);
@ -303,9 +308,10 @@ static size_t next_mark(const uint8_t *mark, size_t limit) {
// Sweep some heap to reclaim free space. Return 1 if there is more
// heap to sweep, or 0 if we reached the end.
static int sweep(struct context *cx, size_t for_granules) {
static int sweep(struct mark_space *space, size_t for_granules) {
// Sweep until we have reclaimed 128 granules (1024 kB), or we reach
// the end of the heap.
struct context *cx = mark_space_context(space);
ssize_t to_reclaim = 128;
uintptr_t sweep = cx->sweep;
uintptr_t limit = cx->heap_base + cx->heap_size;
@ -314,7 +320,7 @@ static int sweep(struct context *cx, size_t for_granules) {
return 0;
while (to_reclaim > 0 && sweep < limit) {
uint8_t* mark = mark_byte(cx, (struct gcobj*)sweep);
uint8_t* mark = mark_byte(space, (struct gcobj*)sweep);
size_t limit_granules = (limit - sweep) >> GRANULE_SIZE_LOG_2;
if (limit_granules > for_granules)
limit_granules = for_granules;
@ -360,7 +366,7 @@ static void* allocate_large(struct mutator *mut, enum alloc_kind kind,
}
}
already_scanned = cx->large_objects;
} while (sweep(cx, granules));
} while (sweep(mutator_mark_space(mut), granules));
// No large object, and we swept across the whole heap. Collect.
if (swept_from_beginning) {
@ -403,7 +409,7 @@ static void fill_small(struct mutator *mut, enum small_object_size kind) {
return;
}
if (!sweep(cx, LARGE_OBJECT_GRANULE_THRESHOLD)) {
if (!sweep(mutator_mark_space(mut), LARGE_OBJECT_GRANULE_THRESHOLD)) {
if (swept_from_beginning) {
fprintf(stderr, "ran out of space, heap size %zu\n", cx->heap_size);
abort();
@ -495,7 +501,7 @@ static int initialize_gc(size_t size, struct heap **heap,
clear_freelists(cx);
cx->sweep = cx->heap_base + cx->heap_size;
cx->count = 0;
if (!marker_init(cx))
if (!marker_init(space))
abort();
reclaim(cx, (void*)cx->heap_base, size_to_granules(cx->heap_size));

View file

@ -276,7 +276,7 @@ enum mark_worker_state {
};
struct mark_worker {
struct context *cx;
struct mark_space *space;
size_t id;
size_t steal_id;
pthread_t thread;
@ -301,19 +301,19 @@ struct marker {
struct local_marker {
struct mark_worker *worker;
struct mark_deque *share_deque;
struct context *cx;
struct mark_space *space;
struct local_mark_queue local;
};
struct context;
static inline struct marker* context_marker(struct context *cx);
static inline struct marker* mark_space_marker(struct mark_space *space);
static size_t number_of_current_processors(void) { return 1; }
static int
mark_worker_init(struct mark_worker *worker, struct context *cx,
mark_worker_init(struct mark_worker *worker, struct mark_space *space,
struct marker *marker, size_t id) {
worker->cx = cx;
worker->space = space;
worker->id = id;
worker->steal_id = 0;
worker->thread = 0;
@ -367,7 +367,7 @@ mark_worker_spawn(struct mark_worker *worker) {
static void
mark_worker_request_mark(struct mark_worker *worker) {
struct marker *marker = context_marker(worker->cx);
struct marker *marker = mark_space_marker(worker->space);
pthread_mutex_lock(&worker->lock);
ASSERT(worker->state == MARK_WORKER_IDLE);
@ -379,7 +379,7 @@ mark_worker_request_mark(struct mark_worker *worker) {
static void
mark_worker_finished_marking(struct mark_worker *worker) {
// Signal controller that we are done with marking.
struct marker *marker = context_marker(worker->cx);
struct marker *marker = mark_space_marker(worker->space);
if (atomic_fetch_sub(&marker->running_markers, 1) == 1) {
pthread_mutex_lock(&marker->lock);
@ -399,8 +399,8 @@ mark_worker_request_stop(struct mark_worker *worker) {
}
static int
marker_init(struct context *cx) {
struct marker *marker = context_marker(cx);
marker_init(struct mark_space *space) {
struct marker *marker = mark_space_marker(space);
atomic_init(&marker->active_markers, 0);
atomic_init(&marker->running_markers, 0);
marker->count = 0;
@ -414,7 +414,7 @@ marker_init(struct context *cx) {
if (desired_worker_count > MARK_WORKERS_MAX_COUNT)
desired_worker_count = MARK_WORKERS_MAX_COUNT;
for (size_t i = 0; i < desired_worker_count; i++) {
if (!mark_worker_init(&marker->workers[i], cx, marker, i))
if (!mark_worker_init(&marker->workers[i], space, marker, i))
break;
if (mark_worker_spawn(&marker->workers[i]))
marker->worker_count++;
@ -424,13 +424,13 @@ marker_init(struct context *cx) {
return marker->worker_count > 0;
}
static void marker_prepare(struct context *cx) {
struct marker *marker = context_marker(cx);
static void marker_prepare(struct mark_space *space) {
struct marker *marker = mark_space_marker(space);
for (size_t i = 0; i < marker->worker_count; i++)
marker->workers[i].steal_id = 0;
}
static void marker_release(struct context *cx) {
struct marker *marker = context_marker(cx);
static void marker_release(struct mark_space *space) {
struct marker *marker = mark_space_marker(space);
for (size_t i = 0; i < marker->worker_count; i++)
mark_deque_release(&marker->workers[i].deque);
}
@ -438,7 +438,7 @@ static void marker_release(struct context *cx) {
struct gcobj;
static inline void marker_visit(void **loc, void *mark_data) ALWAYS_INLINE;
static inline void trace_one(struct gcobj *obj, void *mark_data) ALWAYS_INLINE;
static inline int mark_object(struct context *cx,
static inline int mark_object(struct mark_space *space,
struct gcobj *obj) ALWAYS_INLINE;
static inline void
@ -452,7 +452,7 @@ static inline void
marker_visit(void **loc, void *mark_data) {
struct local_marker *mark = mark_data;
struct gcobj *obj = *loc;
if (obj && mark_object(mark->cx, obj)) {
if (obj && mark_object(mark->space, obj)) {
if (local_mark_queue_full(&mark->local))
marker_share(mark);
local_mark_queue_push(&mark->local, (uintptr_t)obj);
@ -550,7 +550,7 @@ mark_worker_check_termination(struct mark_worker *worker,
static uintptr_t
mark_worker_steal(struct local_marker *mark) {
struct marker *marker = context_marker(mark->cx);
struct marker *marker = mark_space_marker(mark->space);
struct mark_worker *worker = mark->worker;
while (1) {
@ -569,7 +569,7 @@ mark_worker_mark(struct mark_worker *worker) {
struct local_marker mark;
mark.worker = worker;
mark.share_deque = &worker->deque;
mark.cx = worker->cx;
mark.space = worker->space;
local_mark_queue_init(&mark.local);
size_t n = 0;
@ -592,16 +592,14 @@ mark_worker_mark(struct mark_worker *worker) {
}
static inline void
marker_visit_root(void **loc, struct context *cx) {
struct gcobj *obj = *loc;
struct mark_deque *worker0_deque = &context_marker(cx)->workers[0].deque;
if (obj && mark_object(cx, obj))
marker_enqueue_root(struct marker *marker, struct gcobj *obj) {
struct mark_deque *worker0_deque = &marker->workers[0].deque;
mark_deque_push(worker0_deque, (uintptr_t)obj);
}
static inline void
marker_trace(struct context *cx) {
struct marker *marker = context_marker(cx);
marker_trace(struct mark_space *space) {
struct marker *marker = mark_space_marker(space);
pthread_mutex_lock(&marker->lock);
long mark_count = marker->count;

View file

@ -124,40 +124,45 @@ struct marker {
struct mark_queue queue;
};
struct context;
static inline struct marker* context_marker(struct context *cx);
struct mark_space;
static inline struct marker* mark_space_marker(struct mark_space *space);
static int
marker_init(struct context *cx) {
return mark_queue_init(&context_marker(cx)->queue);
marker_init(struct mark_space *space) {
return mark_queue_init(&mark_space_marker(space)->queue);
}
static void marker_prepare(struct context *cx) {}
static void marker_release(struct context *cx) {
mark_queue_release(&context_marker(cx)->queue);
static void marker_prepare(struct mark_space *space) {}
static void marker_release(struct mark_space *space) {
mark_queue_release(&mark_space_marker(space)->queue);
}
struct gcobj;
static inline void marker_visit(void **loc, void *mark_data) ALWAYS_INLINE;
static inline void trace_one(struct gcobj *obj, void *mark_data) ALWAYS_INLINE;
static inline int mark_object(struct context *cx,
static inline int mark_object(struct mark_space *space,
struct gcobj *obj) ALWAYS_INLINE;
static inline void
marker_enqueue_root(struct marker *marker, struct gcobj *obj) {
mark_queue_push(&marker->queue, obj);
}
static inline void
marker_enqueue_roots(struct marker *marker, struct gcobj **objs,
size_t count) {
mark_queue_push_many(&marker->queue, objs, count);
}
static inline void
marker_visit(void **loc, void *mark_data) {
struct context *cx = mark_data;
struct mark_space *space = mark_data;
struct gcobj *obj = *loc;
if (obj && mark_object(cx, obj))
mark_queue_push(&context_marker(cx)->queue, obj);
if (obj && mark_object(space, obj))
marker_enqueue_root(mark_space_marker(space), obj);
}
static inline void
marker_visit_root(void **loc, struct context *cx) {
marker_visit(loc, cx);
}
static inline void
marker_trace(struct context *cx) {
marker_trace(struct mark_space *space) {
struct gcobj *obj;
while ((obj = mark_queue_pop(&context_marker(cx)->queue)))
trace_one(obj, cx);
while ((obj = mark_queue_pop(&mark_space_marker(space)->queue)))
trace_one(obj, space);
}
#endif // SERIAL_MARK_H