1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-01 12:20:26 +02:00

Add "extern space"

This is mostly for static data.
This commit is contained in:
Andy Wingo 2023-08-15 11:34:29 +02:00
parent da5a4633df
commit fbe49598f5
7 changed files with 77 additions and 3 deletions

View file

@ -34,6 +34,10 @@ struct gc_heap_roots;
GC_API_ void gc_heap_set_roots(struct gc_heap *heap,
struct gc_heap_roots *roots);
struct gc_extern_space;
GC_API_ void gc_heap_set_extern_space(struct gc_heap *heap,
struct gc_extern_space *space);
GC_API_ struct gc_mutator* gc_init_for_thread(struct gc_stack_addr *base,
struct gc_heap *heap);
GC_API_ void gc_finish_for_thread(struct gc_mutator *mut);

View file

@ -17,9 +17,17 @@ struct gc_heap_roots;
struct gc_atomic_forward;
struct gc_heap;
struct gc_ephemeron;
struct gc_extern_space;
GC_EMBEDDER_API inline int gc_is_valid_conservative_ref_displacement(uintptr_t displacement);
GC_EMBEDDER_API inline int gc_extern_space_mark(struct gc_extern_space *space,
struct gc_ref ref) GC_ALWAYS_INLINE;
GC_EMBEDDER_API inline void gc_extern_space_start_gc(struct gc_extern_space *space,
int is_minor_gc);
GC_EMBEDDER_API inline void gc_extern_space_finish_gc(struct gc_extern_space *space,
int is_minor_gc);
GC_EMBEDDER_API inline void gc_trace_object(struct gc_ref ref,
void (*visit)(struct gc_edge edge,
struct gc_heap *heap,

View file

@ -18,6 +18,18 @@ gc_is_valid_conservative_ref_displacement(uintptr_t displacement) {
#endif
}
// No external objects in simple benchmarks.
static inline int gc_extern_space_mark(struct gc_extern_space *space,
struct gc_ref ref) {
GC_CRASH();
}
static inline void gc_extern_space_start_gc(struct gc_extern_space *space,
int is_minor_gc) {
}
static inline void gc_extern_space_finish_gc(struct gc_extern_space *space,
int is_minor_gc) {
}
static inline void gc_trace_object(struct gc_ref ref,
void (*trace_edge)(struct gc_edge edge,
struct gc_heap *heap,

View file

@ -163,6 +163,19 @@ embedder should return 1 only if the displacement is 0, but if the
program allows low-bit tagged pointers, then it should also return 1 for
those pointer tags.
### External objects
Sometimes a system will allocate objects outside the GC, for example on
the stack or in static data sections. To support this use case, Whippet
allows the embedder to provide a `struct gc_extern_space`
implementation. Whippet will call `gc_extern_space_start_gc` at the
start of each collection, and `gc_extern_space_finish_gc` at the end.
External objects will be visited by `gc_extern_space_mark`, which should
return nonzero if the object hasn't been seen before and needs to be
traced via `gc_trace_object` (coloring the object grey). Note,
`gc_extern_space_mark` may be called concurrently from many threads; be
prepared!
## Configuration, compilation, and linking
To the user, Whippet presents an abstract API that does not encode the

View file

@ -325,6 +325,9 @@ void gc_mutator_set_roots(struct gc_mutator *mut,
}
void gc_heap_set_roots(struct gc_heap *heap, struct gc_heap_roots *roots) {
}
void gc_heap_set_extern_space(struct gc_heap *heap,
struct gc_extern_space *space) {
}
void gc_print_stats(struct gc_heap *heap) {
printf("Completed %ld collections\n", (long)GC_get_gc_no());

View file

@ -37,12 +37,14 @@ struct gc_heap {
struct semi_space semi_space;
struct large_object_space large_object_space;
struct gc_pending_ephemerons *pending_ephemerons;
struct gc_extern_space *extern_space;
double pending_ephemerons_size_factor;
double pending_ephemerons_size_slop;
size_t size;
long count;
int check_pending_ephemerons;
const struct gc_options *options;
struct gc_heap_roots *roots;
};
// One mutator per space, can just store the heap in the mutator.
struct gc_mutator {
@ -195,6 +197,17 @@ static int semi_space_contains(struct semi_space *space, struct gc_ref ref) {
return region_contains(&space->from_space, addr);
}
static void visit_external_object(struct gc_heap *heap,
struct gc_extern_space *space,
struct gc_ref ref) {
if (gc_extern_space_mark(space, ref)) {
if (GC_UNLIKELY(heap->check_pending_ephemerons))
gc_resolve_pending_ephemerons(ref, heap);
gc_trace_object(ref, trace, heap, NULL, NULL);
}
}
static void visit(struct gc_edge edge, struct gc_heap *heap) {
struct gc_ref ref = gc_edge_ref(edge);
if (!gc_ref_is_heap_object(ref))
@ -204,7 +217,7 @@ static void visit(struct gc_edge edge, struct gc_heap *heap) {
else if (large_object_space_contains(heap_large_object_space(heap), ref))
visit_large_object_space(heap, heap_large_object_space(heap), ref);
else
GC_CRASH();
visit_external_object(heap, heap->extern_space, ref);
}
struct gc_pending_ephemerons *
@ -329,10 +342,13 @@ static void collect(struct gc_mutator *mut, size_t for_alloc) {
struct large_object_space *large = heap_large_object_space(heap);
// fprintf(stderr, "start collect #%ld:\n", space->count);
large_object_space_start_gc(large, 0);
gc_extern_space_start_gc(heap->extern_space, 0);
flip(semi);
heap->count++;
heap->check_pending_ephemerons = 0;
uintptr_t grey = semi->hp;
if (heap->roots)
gc_trace_heap_roots(heap->roots, trace, heap, NULL);
if (mut->roots)
gc_trace_mutator_roots(mut->roots, trace, heap, NULL);
// fprintf(stderr, "pushed %zd bytes in roots\n", space->hp - grey);
@ -344,6 +360,7 @@ static void collect(struct gc_mutator *mut, size_t for_alloc) {
while(grey < semi->hp)
grey = scan(heap, gc_ref(grey));
large_object_space_finish_gc(large, 0);
gc_extern_space_finish_gc(heap->extern_space, 0);
semi_space_finish_gc(semi, large->live_pages_at_last_collection);
gc_sweep_pending_ephemerons(heap->pending_ephemerons, 0, 1);
adjust_heap_size_and_limits(heap, for_alloc);
@ -485,11 +502,13 @@ unsigned gc_heap_ephemeron_trace_epoch(struct gc_heap *heap) {
}
static int heap_init(struct gc_heap *heap, const struct gc_options *options) {
heap->extern_space = NULL;
heap->pending_ephemerons_size_factor = 0.01;
heap->pending_ephemerons_size_slop = 0.5;
heap->count = 0;
heap->options = options;
heap->size = options->common.heap_size;
heap->roots = NULL;
return heap_prepare_pending_ephemerons(heap);
}
@ -559,7 +578,11 @@ void gc_mutator_set_roots(struct gc_mutator *mut,
mut->roots = roots;
}
void gc_heap_set_roots(struct gc_heap *heap, struct gc_heap_roots *roots) {
GC_CRASH();
heap->roots = roots;
}
void gc_heap_set_extern_space(struct gc_heap *heap,
struct gc_extern_space *space) {
heap->extern_space = space;
}
struct gc_mutator* gc_init_for_thread(struct gc_stack_addr *base,

View file

@ -300,6 +300,7 @@ enum gc_kind {
struct gc_heap {
struct mark_space mark_space;
struct large_object_space large_object_space;
struct gc_extern_space *extern_space;
size_t large_object_pages;
pthread_mutex_t lock;
pthread_cond_t collector_cond;
@ -360,6 +361,9 @@ static inline struct mark_space* heap_mark_space(struct gc_heap *heap) {
static inline struct large_object_space* heap_large_object_space(struct gc_heap *heap) {
return &heap->large_object_space;
}
static inline struct gc_extern_space* heap_extern_space(struct gc_heap *heap) {
return heap->extern_space;
}
static inline struct gc_heap* mutator_heap(struct gc_mutator *mutator) {
return mutator->heap;
}
@ -667,7 +671,7 @@ static inline int do_trace(struct gc_heap *heap, struct gc_edge edge,
return large_object_space_mark_object(heap_large_object_space(heap),
ref);
else
GC_CRASH();
return gc_extern_space_mark(heap_extern_space(heap), ref);
}
static inline int trace_edge(struct gc_heap *heap, struct gc_edge edge) {
@ -1078,6 +1082,10 @@ void gc_mutator_set_roots(struct gc_mutator *mut,
void gc_heap_set_roots(struct gc_heap *heap, struct gc_heap_roots *roots) {
heap->roots = roots;
}
void gc_heap_set_extern_space(struct gc_heap *heap,
struct gc_extern_space *space) {
heap->extern_space = space;
}
static void trace_and_enqueue_locally(struct gc_edge edge,
struct gc_heap *heap,
@ -1803,6 +1811,7 @@ static void collect(struct gc_mutator *mut) {
struct gc_heap *heap = mutator_heap(mut);
struct mark_space *space = heap_mark_space(heap);
struct large_object_space *lospace = heap_large_object_space(heap);
struct gc_extern_space *exspace = heap_extern_space(heap);
if (maybe_grow_heap(heap)) {
DEBUG("grew heap instead of collecting #%ld:\n", heap->count);
return;
@ -1811,6 +1820,7 @@ static void collect(struct gc_mutator *mut) {
enum gc_kind gc_kind = determine_collection_kind(heap);
update_mark_patterns(space, !(gc_kind & GC_KIND_FLAG_MINOR));
large_object_space_start_gc(lospace, gc_kind & GC_KIND_FLAG_MINOR);
gc_extern_space_start_gc(exspace, gc_kind & GC_KIND_FLAG_MINOR);
resolve_ephemerons_lazily(heap);
tracer_prepare(heap);
request_mutators_to_stop(heap);
@ -1832,6 +1842,7 @@ static void collect(struct gc_mutator *mut) {
tracer_release(heap);
mark_space_finish_gc(space, gc_kind);
large_object_space_finish_gc(lospace, gc_kind & GC_KIND_FLAG_MINOR);
gc_extern_space_finish_gc(exspace, gc_kind & GC_KIND_FLAG_MINOR);
heap->count++;
heap->last_collection_was_minor = gc_kind & GC_KIND_FLAG_MINOR;
if (heap->last_collection_was_minor)