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:
parent
da5a4633df
commit
fbe49598f5
7 changed files with 77 additions and 3 deletions
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
27
src/semi.c
27
src/semi.c
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue