1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-01 20:30:28 +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, GC_API_ void gc_heap_set_roots(struct gc_heap *heap,
struct gc_heap_roots *roots); 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, GC_API_ struct gc_mutator* gc_init_for_thread(struct gc_stack_addr *base,
struct gc_heap *heap); struct gc_heap *heap);
GC_API_ void gc_finish_for_thread(struct gc_mutator *mut); 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_atomic_forward;
struct gc_heap; struct gc_heap;
struct gc_ephemeron; 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_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, GC_EMBEDDER_API inline void gc_trace_object(struct gc_ref ref,
void (*visit)(struct gc_edge edge, void (*visit)(struct gc_edge edge,
struct gc_heap *heap, struct gc_heap *heap,

View file

@ -18,6 +18,18 @@ gc_is_valid_conservative_ref_displacement(uintptr_t displacement) {
#endif #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, static inline void gc_trace_object(struct gc_ref ref,
void (*trace_edge)(struct gc_edge edge, void (*trace_edge)(struct gc_edge edge,
struct gc_heap *heap, 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 program allows low-bit tagged pointers, then it should also return 1 for
those pointer tags. 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 ## Configuration, compilation, and linking
To the user, Whippet presents an abstract API that does not encode the 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_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) { void gc_print_stats(struct gc_heap *heap) {
printf("Completed %ld collections\n", (long)GC_get_gc_no()); 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 semi_space semi_space;
struct large_object_space large_object_space; struct large_object_space large_object_space;
struct gc_pending_ephemerons *pending_ephemerons; struct gc_pending_ephemerons *pending_ephemerons;
struct gc_extern_space *extern_space;
double pending_ephemerons_size_factor; double pending_ephemerons_size_factor;
double pending_ephemerons_size_slop; double pending_ephemerons_size_slop;
size_t size; size_t size;
long count; long count;
int check_pending_ephemerons; int check_pending_ephemerons;
const struct gc_options *options; const struct gc_options *options;
struct gc_heap_roots *roots;
}; };
// One mutator per space, can just store the heap in the mutator. // One mutator per space, can just store the heap in the mutator.
struct gc_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); 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) { static void visit(struct gc_edge edge, struct gc_heap *heap) {
struct gc_ref ref = gc_edge_ref(edge); struct gc_ref ref = gc_edge_ref(edge);
if (!gc_ref_is_heap_object(ref)) 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)) else if (large_object_space_contains(heap_large_object_space(heap), ref))
visit_large_object_space(heap, heap_large_object_space(heap), ref); visit_large_object_space(heap, heap_large_object_space(heap), ref);
else else
GC_CRASH(); visit_external_object(heap, heap->extern_space, ref);
} }
struct gc_pending_ephemerons * 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); struct large_object_space *large = heap_large_object_space(heap);
// fprintf(stderr, "start collect #%ld:\n", space->count); // fprintf(stderr, "start collect #%ld:\n", space->count);
large_object_space_start_gc(large, 0); large_object_space_start_gc(large, 0);
gc_extern_space_start_gc(heap->extern_space, 0);
flip(semi); flip(semi);
heap->count++; heap->count++;
heap->check_pending_ephemerons = 0; heap->check_pending_ephemerons = 0;
uintptr_t grey = semi->hp; uintptr_t grey = semi->hp;
if (heap->roots)
gc_trace_heap_roots(heap->roots, trace, heap, NULL);
if (mut->roots) if (mut->roots)
gc_trace_mutator_roots(mut->roots, trace, heap, NULL); gc_trace_mutator_roots(mut->roots, trace, heap, NULL);
// fprintf(stderr, "pushed %zd bytes in roots\n", space->hp - grey); // 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) while(grey < semi->hp)
grey = scan(heap, gc_ref(grey)); grey = scan(heap, gc_ref(grey));
large_object_space_finish_gc(large, 0); 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); semi_space_finish_gc(semi, large->live_pages_at_last_collection);
gc_sweep_pending_ephemerons(heap->pending_ephemerons, 0, 1); gc_sweep_pending_ephemerons(heap->pending_ephemerons, 0, 1);
adjust_heap_size_and_limits(heap, for_alloc); 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) { 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_factor = 0.01;
heap->pending_ephemerons_size_slop = 0.5; heap->pending_ephemerons_size_slop = 0.5;
heap->count = 0; heap->count = 0;
heap->options = options; heap->options = options;
heap->size = options->common.heap_size; heap->size = options->common.heap_size;
heap->roots = NULL;
return heap_prepare_pending_ephemerons(heap); return heap_prepare_pending_ephemerons(heap);
} }
@ -559,7 +578,11 @@ void gc_mutator_set_roots(struct gc_mutator *mut,
mut->roots = roots; mut->roots = roots;
} }
void gc_heap_set_roots(struct gc_heap *heap, struct gc_heap_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, 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 gc_heap {
struct mark_space mark_space; struct mark_space mark_space;
struct large_object_space large_object_space; struct large_object_space large_object_space;
struct gc_extern_space *extern_space;
size_t large_object_pages; size_t large_object_pages;
pthread_mutex_t lock; pthread_mutex_t lock;
pthread_cond_t collector_cond; 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) { static inline struct large_object_space* heap_large_object_space(struct gc_heap *heap) {
return &heap->large_object_space; 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) { static inline struct gc_heap* mutator_heap(struct gc_mutator *mutator) {
return mutator->heap; 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), return large_object_space_mark_object(heap_large_object_space(heap),
ref); ref);
else 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) { 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) { void gc_heap_set_roots(struct gc_heap *heap, struct gc_heap_roots *roots) {
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, static void trace_and_enqueue_locally(struct gc_edge edge,
struct gc_heap *heap, struct gc_heap *heap,
@ -1803,6 +1811,7 @@ static void collect(struct gc_mutator *mut) {
struct gc_heap *heap = mutator_heap(mut); struct gc_heap *heap = mutator_heap(mut);
struct mark_space *space = heap_mark_space(heap); struct mark_space *space = heap_mark_space(heap);
struct large_object_space *lospace = heap_large_object_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)) { if (maybe_grow_heap(heap)) {
DEBUG("grew heap instead of collecting #%ld:\n", heap->count); DEBUG("grew heap instead of collecting #%ld:\n", heap->count);
return; return;
@ -1811,6 +1820,7 @@ static void collect(struct gc_mutator *mut) {
enum gc_kind gc_kind = determine_collection_kind(heap); enum gc_kind gc_kind = determine_collection_kind(heap);
update_mark_patterns(space, !(gc_kind & GC_KIND_FLAG_MINOR)); update_mark_patterns(space, !(gc_kind & GC_KIND_FLAG_MINOR));
large_object_space_start_gc(lospace, 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); resolve_ephemerons_lazily(heap);
tracer_prepare(heap); tracer_prepare(heap);
request_mutators_to_stop(heap); request_mutators_to_stop(heap);
@ -1832,6 +1842,7 @@ static void collect(struct gc_mutator *mut) {
tracer_release(heap); tracer_release(heap);
mark_space_finish_gc(space, gc_kind); mark_space_finish_gc(space, gc_kind);
large_object_space_finish_gc(lospace, gc_kind & GC_KIND_FLAG_MINOR); 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->count++;
heap->last_collection_was_minor = gc_kind & GC_KIND_FLAG_MINOR; heap->last_collection_was_minor = gc_kind & GC_KIND_FLAG_MINOR;
if (heap->last_collection_was_minor) if (heap->last_collection_was_minor)