mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-30 03:40:34 +02:00
Trim remembered-set during minor GC
When visiting remembered-set roots, if the target is no longer in newspace, forget the edge.
This commit is contained in:
parent
cc68a9a610
commit
685c63ab3a
4 changed files with 52 additions and 10 deletions
|
@ -174,21 +174,26 @@ gc_field_set_clear(struct gc_field_set *set,
|
|||
static inline void
|
||||
gc_field_set_visit_edge_buffer(struct gc_field_set *set,
|
||||
struct gc_edge_buffer *buf,
|
||||
void (*visit)(struct gc_edge,
|
||||
struct gc_heap*,
|
||||
void *data),
|
||||
int (*visit)(struct gc_edge,
|
||||
struct gc_heap*,
|
||||
void *data),
|
||||
struct gc_heap *heap,
|
||||
void *data) GC_ALWAYS_INLINE;
|
||||
static inline void
|
||||
gc_field_set_visit_edge_buffer(struct gc_field_set *set,
|
||||
struct gc_edge_buffer *buf,
|
||||
void (*visit)(struct gc_edge,
|
||||
struct gc_heap*,
|
||||
void *data),
|
||||
int (*visit)(struct gc_edge,
|
||||
struct gc_heap*,
|
||||
void *data),
|
||||
struct gc_heap *heap,
|
||||
void *data) {
|
||||
for (size_t i = 0; i < buf->size; i++)
|
||||
visit(buf->edges[i], heap, data);
|
||||
size_t i = 0;
|
||||
while (i < buf->size) {
|
||||
if (visit(buf->edges[i], heap, data))
|
||||
i++;
|
||||
else
|
||||
buf->edges[i] = buf->edges[--buf->size];
|
||||
}
|
||||
gc_field_set_release_buffer(set, buf);
|
||||
}
|
||||
|
||||
|
|
|
@ -249,6 +249,16 @@ large_object_space_remember_edge(struct large_object_space *space,
|
|||
return remembered;
|
||||
}
|
||||
|
||||
static void
|
||||
large_object_space_forget_edge(struct large_object_space *space,
|
||||
struct gc_edge edge) {
|
||||
uintptr_t edge_addr = gc_edge_address(edge);
|
||||
pthread_mutex_lock(&space->lock);
|
||||
GC_ASSERT(address_set_contains(&space->remembered_edges, edge_addr));
|
||||
address_set_remove(&space->remembered_edges, edge_addr);
|
||||
pthread_mutex_unlock(&space->lock);
|
||||
}
|
||||
|
||||
static void
|
||||
large_object_space_clear_remembered_edges(struct large_object_space *space) {
|
||||
address_set_clear(&space->remembered_edges);
|
||||
|
|
|
@ -264,6 +264,13 @@ tracer_visit(struct gc_edge edge, struct gc_heap *heap, void *trace_data) {
|
|||
gc_trace_worker_enqueue(worker, gc_edge_ref(edge));
|
||||
}
|
||||
|
||||
static inline int
|
||||
trace_remembered_edge(struct gc_edge edge, struct gc_heap *heap, void *trace_data) {
|
||||
tracer_visit(edge, heap, trace_data);
|
||||
// Keep the edge in the remembered set; we clear these in bulk later.
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline struct gc_ref
|
||||
do_trace_conservative_ref(struct gc_heap *heap, struct gc_conservative_ref ref,
|
||||
int possibly_interior) {
|
||||
|
@ -380,7 +387,7 @@ trace_root(struct gc_root root, struct gc_heap *heap,
|
|||
break;
|
||||
case GC_ROOT_KIND_EDGE_BUFFER:
|
||||
gc_field_set_visit_edge_buffer(&heap->remembered_set, root.edge_buffer,
|
||||
tracer_visit, heap, worker);
|
||||
trace_remembered_edge, heap, worker);
|
||||
break;
|
||||
default:
|
||||
GC_CRASH();
|
||||
|
|
22
src/pcc.c
22
src/pcc.c
|
@ -544,6 +544,26 @@ tracer_visit(struct gc_edge edge, struct gc_heap *heap, void *trace_data) {
|
|||
gc_trace_worker_enqueue(worker, gc_edge_ref(edge));
|
||||
}
|
||||
|
||||
static inline int
|
||||
trace_remembered_edge(struct gc_edge edge, struct gc_heap *heap,
|
||||
void *trace_data) {
|
||||
GC_ASSERT(is_minor_collection(heap));
|
||||
tracer_visit(edge, heap, trace_data);
|
||||
|
||||
// Return 1 if the edge should be kept in the remset, which is the
|
||||
// case only for new objects that survive the minor GC, and only the
|
||||
// nursery copy space has survivors.
|
||||
if (new_space_contains(heap, gc_edge_ref(edge)))
|
||||
return 1; // Keep edge in remset.
|
||||
// Otherwise remove field-logging bit and return 0 to indicate that
|
||||
// the remembered field set should remove this edge.
|
||||
if (copy_space_contains_edge(heap_old_space(heap), edge))
|
||||
copy_space_forget_edge(heap_old_space(heap), edge);
|
||||
else
|
||||
large_object_space_forget_edge(heap_large_object_space(heap), edge);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void trace_one(struct gc_ref ref, struct gc_heap *heap,
|
||||
struct gc_trace_worker *worker) {
|
||||
#ifdef DEBUG
|
||||
|
@ -582,7 +602,7 @@ static inline void trace_root(struct gc_root root, struct gc_heap *heap,
|
|||
break;
|
||||
case GC_ROOT_KIND_EDGE_BUFFER:
|
||||
gc_field_set_visit_edge_buffer(heap_remembered_set(heap), root.edge_buffer,
|
||||
tracer_visit, heap, worker);
|
||||
trace_remembered_edge, heap, worker);
|
||||
break;
|
||||
default:
|
||||
GC_CRASH();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue