mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-09 23:20:21 +02:00
Whippet can trace conservative roots
Next up, enabling it via the makefiles.
This commit is contained in:
parent
deed415a06
commit
1944b54a19
8 changed files with 311 additions and 73 deletions
|
@ -16,16 +16,34 @@ static inline int gc_has_conservative_intraheap_edges(void) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void gc_trace_precise_mutator_roots(struct gc_mutator_roots *roots,
|
static inline int
|
||||||
void (*trace_edge)(struct gc_edge edge,
|
gc_is_valid_conservative_ref_displacement(uintptr_t displacement) {
|
||||||
void *trace_data),
|
// Here is where you would allow tagged heap object references.
|
||||||
void *trace_data) {
|
return displacement == 0;
|
||||||
|
}
|
||||||
|
static inline int
|
||||||
|
gc_conservative_ref_might_be_a_heap_object(struct gc_conservative_ref ref,
|
||||||
|
int possibly_interior) {
|
||||||
|
// Assume that the minimum page size is 4096, and that the first page
|
||||||
|
// will contain no heap objects.
|
||||||
|
if (gc_conservative_ref_value(ref) < 4096)
|
||||||
|
return 0;
|
||||||
|
if (possibly_interior)
|
||||||
|
return 1;
|
||||||
|
return gc_is_valid_conservative_ref_displacement
|
||||||
|
(gc_conservative_ref_value(ref) & (sizeof(uintptr_t) - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void gc_trace_precise_heap_roots(struct gc_heap_roots *roots,
|
static inline void gc_trace_mutator_roots(struct gc_mutator_roots *roots,
|
||||||
void (*trace_edge)(struct gc_edge edge,
|
void (*trace_edge)(struct gc_edge edge,
|
||||||
void *trace_data),
|
void *trace_data),
|
||||||
void *trace_data) {
|
void *trace_data) {
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void gc_trace_heap_roots(struct gc_heap_roots *roots,
|
||||||
|
void (*trace_edge)(struct gc_edge edge,
|
||||||
|
void *trace_data),
|
||||||
|
void *trace_data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CONSERVATIVE_ROOTS_EMBEDDER_H
|
#endif // CONSERVATIVE_ROOTS_EMBEDDER_H
|
||||||
|
|
17
gc-conservative-ref.h
Normal file
17
gc-conservative-ref.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef GC_CONSERVATIVE_REF_H
|
||||||
|
#define GC_CONSERVATIVE_REF_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct gc_conservative_ref {
|
||||||
|
uintptr_t value;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct gc_conservative_ref gc_conservative_ref(uintptr_t value) {
|
||||||
|
return (struct gc_conservative_ref){value};
|
||||||
|
}
|
||||||
|
static inline uintptr_t gc_conservative_ref_value(struct gc_conservative_ref ref) {
|
||||||
|
return ref.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // GC_CONSERVATIVE_REF_H
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef GC_EMBEDDER_API_H
|
#ifndef GC_EMBEDDER_API_H
|
||||||
#define GC_EMBEDDER_API_H
|
#define GC_EMBEDDER_API_H
|
||||||
|
|
||||||
|
#include "gc-conservative-ref.h"
|
||||||
#include "gc-edge.h"
|
#include "gc-edge.h"
|
||||||
#include "gc-forwarding.h"
|
#include "gc-forwarding.h"
|
||||||
|
|
||||||
|
@ -17,19 +18,24 @@ GC_EMBEDDER_API inline int gc_has_global_conservative_roots(void);
|
||||||
GC_EMBEDDER_API inline int gc_has_conservative_intraheap_edges(void);
|
GC_EMBEDDER_API inline int gc_has_conservative_intraheap_edges(void);
|
||||||
GC_EMBEDDER_API inline int gc_mutator_conservative_roots_may_be_interior(void);
|
GC_EMBEDDER_API inline int gc_mutator_conservative_roots_may_be_interior(void);
|
||||||
|
|
||||||
|
GC_EMBEDDER_API inline int gc_is_valid_conservative_ref_displacement(uintptr_t displacement);
|
||||||
|
GC_EMBEDDER_API inline int gc_conservative_ref_might_be_a_heap_object(struct gc_conservative_ref,
|
||||||
|
int possibly_interior);
|
||||||
|
|
||||||
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 (*trace_edge)(struct gc_edge edge,
|
void (*trace_edge)(struct gc_edge edge,
|
||||||
void *trace_data),
|
void *trace_data),
|
||||||
void *trace_data,
|
void *trace_data,
|
||||||
size_t *size) GC_ALWAYS_INLINE;
|
size_t *size) GC_ALWAYS_INLINE;
|
||||||
GC_EMBEDDER_API inline void gc_trace_precise_mutator_roots(struct gc_mutator_roots *roots,
|
|
||||||
|
GC_EMBEDDER_API inline void gc_trace_mutator_roots(struct gc_mutator_roots *roots,
|
||||||
void (*trace_edge)(struct gc_edge edge,
|
void (*trace_edge)(struct gc_edge edge,
|
||||||
void *trace_data),
|
void *trace_data),
|
||||||
void *trace_data);
|
void *trace_data);
|
||||||
GC_EMBEDDER_API inline void gc_trace_precise_heap_roots(struct gc_heap_roots *roots,
|
GC_EMBEDDER_API inline void gc_trace_heap_roots(struct gc_heap_roots *roots,
|
||||||
void (*trace_edge)(struct gc_edge edge,
|
void (*trace_edge)(struct gc_edge edge,
|
||||||
void *trace_data),
|
void *trace_data),
|
||||||
void *trace_data);
|
void *trace_data);
|
||||||
|
|
||||||
GC_EMBEDDER_API inline uintptr_t gc_object_forwarded_nonatomic(struct gc_ref ref);
|
GC_EMBEDDER_API inline uintptr_t gc_object_forwarded_nonatomic(struct gc_ref ref);
|
||||||
GC_EMBEDDER_API inline void gc_object_forward_nonatomic(struct gc_ref ref,
|
GC_EMBEDDER_API inline void gc_object_forward_nonatomic(struct gc_ref ref,
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "gc-ref.h"
|
#include "gc-ref.h"
|
||||||
|
#include "gc-conservative-ref.h"
|
||||||
#include "address-map.h"
|
#include "address-map.h"
|
||||||
#include "address-set.h"
|
#include "address-set.h"
|
||||||
|
|
||||||
|
@ -90,6 +91,11 @@ done:
|
||||||
return copied;
|
return copied;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int large_object_space_mark_object(struct large_object_space *space,
|
||||||
|
struct gc_ref ref) {
|
||||||
|
return large_object_space_copy(space, ref);
|
||||||
|
}
|
||||||
|
|
||||||
static void large_object_space_reclaim_one(uintptr_t addr, void *data) {
|
static void large_object_space_reclaim_one(uintptr_t addr, void *data) {
|
||||||
struct large_object_space *space = data;
|
struct large_object_space *space = data;
|
||||||
size_t npages = address_map_lookup(&space->object_pages, addr, 0);
|
size_t npages = address_map_lookup(&space->object_pages, addr, 0);
|
||||||
|
@ -145,6 +151,38 @@ static void large_object_space_finish_gc(struct large_object_space *space,
|
||||||
pthread_mutex_unlock(&space->lock);
|
pthread_mutex_unlock(&space->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline struct gc_ref
|
||||||
|
large_object_space_mark_conservative_ref(struct large_object_space *space,
|
||||||
|
struct gc_conservative_ref ref,
|
||||||
|
int possibly_interior) {
|
||||||
|
uintptr_t addr = gc_conservative_ref_value(ref);
|
||||||
|
|
||||||
|
if (possibly_interior) {
|
||||||
|
// FIXME: This only allows interior pointers within the first page.
|
||||||
|
// BDW-GC doesn't have all-interior-pointers on for intraheap edges
|
||||||
|
// or edges originating in static data but by default does allow
|
||||||
|
// them from stack edges; probably we should too.
|
||||||
|
addr &= ~(space->page_size - 1);
|
||||||
|
} else {
|
||||||
|
// Addr not aligned on page boundary? Not a large object.
|
||||||
|
uintptr_t displacement = addr & (space->page_size - 1);
|
||||||
|
if (!gc_is_valid_conservative_ref_displacement(displacement))
|
||||||
|
return gc_ref_null();
|
||||||
|
addr -= displacement;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&space->lock);
|
||||||
|
// ptr might be in fromspace or tospace. Just check the object_pages table, which
|
||||||
|
// contains both, as well as object_pages for free blocks.
|
||||||
|
int found = address_map_contains(&space->object_pages, addr);
|
||||||
|
pthread_mutex_unlock(&space->lock);
|
||||||
|
|
||||||
|
if (found && large_object_space_copy(space, gc_ref(addr)))
|
||||||
|
return gc_ref(addr);
|
||||||
|
|
||||||
|
return gc_ref_null();
|
||||||
|
}
|
||||||
|
|
||||||
static inline int large_object_space_contains(struct large_object_space *space,
|
static inline int large_object_space_contains(struct large_object_space *space,
|
||||||
struct gc_ref ref) {
|
struct gc_ref ref) {
|
||||||
pthread_mutex_lock(&space->lock);
|
pthread_mutex_lock(&space->lock);
|
||||||
|
|
|
@ -18,6 +18,16 @@ static inline int gc_has_conservative_intraheap_edges(void) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
gc_is_valid_conservative_ref_displacement(uintptr_t displacement) {
|
||||||
|
GC_CRASH();
|
||||||
|
}
|
||||||
|
static inline int
|
||||||
|
gc_conservative_ref_might_be_a_heap_object(struct gc_conservative_ref ref,
|
||||||
|
int possibly_interior) {
|
||||||
|
GC_CRASH();
|
||||||
|
}
|
||||||
|
|
||||||
static inline void visit_roots(struct handle *roots,
|
static inline void visit_roots(struct handle *roots,
|
||||||
void (*trace_edge)(struct gc_edge edge,
|
void (*trace_edge)(struct gc_edge edge,
|
||||||
void *trace_data),
|
void *trace_data),
|
||||||
|
@ -26,18 +36,18 @@ static inline void visit_roots(struct handle *roots,
|
||||||
trace_edge(gc_edge(&h->v), trace_data);
|
trace_edge(gc_edge(&h->v), trace_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void gc_trace_precise_mutator_roots(struct gc_mutator_roots *roots,
|
static inline void gc_trace_mutator_roots(struct gc_mutator_roots *roots,
|
||||||
void (*trace_edge)(struct gc_edge edge,
|
void (*trace_edge)(struct gc_edge edge,
|
||||||
void *trace_data),
|
void *trace_data),
|
||||||
void *trace_data) {
|
void *trace_data) {
|
||||||
if (roots)
|
if (roots)
|
||||||
visit_roots(roots->roots, trace_edge, trace_data);
|
visit_roots(roots->roots, trace_edge, trace_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void gc_trace_precise_heap_roots(struct gc_heap_roots *roots,
|
static inline void gc_trace_heap_roots(struct gc_heap_roots *roots,
|
||||||
void (*trace_edge)(struct gc_edge edge,
|
void (*trace_edge)(struct gc_edge edge,
|
||||||
void *trace_data),
|
void *trace_data),
|
||||||
void *trace_data) {
|
void *trace_data) {
|
||||||
if (roots)
|
if (roots)
|
||||||
visit_roots(roots->roots, trace_edge, trace_data);
|
visit_roots(roots->roots, trace_edge, trace_data);
|
||||||
}
|
}
|
||||||
|
|
2
semi.c
2
semi.c
|
@ -161,7 +161,7 @@ static void collect(struct gc_mutator *mut) {
|
||||||
flip(semi);
|
flip(semi);
|
||||||
uintptr_t grey = semi->hp;
|
uintptr_t grey = semi->hp;
|
||||||
if (mut->roots)
|
if (mut->roots)
|
||||||
gc_trace_precise_mutator_roots(mut->roots, visit, heap);
|
gc_trace_mutator_roots(mut->roots, visit, heap);
|
||||||
// fprintf(stderr, "pushed %zd bytes in roots\n", space->hp - grey);
|
// fprintf(stderr, "pushed %zd bytes in roots\n", space->hp - grey);
|
||||||
while(grey < semi->hp)
|
while(grey < semi->hp)
|
||||||
grey = scan(heap, gc_ref(grey));
|
grey = scan(heap, gc_ref(grey));
|
||||||
|
|
|
@ -104,3 +104,9 @@ gc_atomic_forward_address(struct gc_atomic_forward *fwd) {
|
||||||
GC_ASSERT(fwd->state == GC_FORWARDING_STATE_FORWARDED);
|
GC_ASSERT(fwd->state == GC_FORWARDING_STATE_FORWARDED);
|
||||||
return fwd->data;
|
return fwd->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uintptr_t
|
||||||
|
gc_conservative_ref_heap_address(struct gc_conservative_ref ref) {
|
||||||
|
// The specific spaces are responsible for checking alignment.
|
||||||
|
return gc_conservative_ref_value(ref);
|
||||||
|
}
|
||||||
|
|
245
whippet.c
245
whippet.c
|
@ -15,6 +15,7 @@
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "gc-align.h"
|
#include "gc-align.h"
|
||||||
#include "gc-inline.h"
|
#include "gc-inline.h"
|
||||||
|
#include "gc-platform.h"
|
||||||
#include "gc-stack.h"
|
#include "gc-stack.h"
|
||||||
#include "large-object-space.h"
|
#include "large-object-space.h"
|
||||||
#if GC_PARALLEL
|
#if GC_PARALLEL
|
||||||
|
@ -597,15 +598,19 @@ static inline int mark_space_evacuate_or_mark_object(struct mark_space *space,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int mark_space_contains(struct mark_space *space,
|
static inline int mark_space_contains_address(struct mark_space *space,
|
||||||
struct gc_ref ref) {
|
uintptr_t addr) {
|
||||||
uintptr_t addr = gc_ref_value(ref);
|
|
||||||
return addr - space->low_addr < space->extent;
|
return addr - space->low_addr < space->extent;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int large_object_space_mark_object(struct large_object_space *space,
|
static inline int mark_space_contains_conservative_ref(struct mark_space *space,
|
||||||
struct gc_ref ref) {
|
struct gc_conservative_ref ref) {
|
||||||
return large_object_space_copy(space, ref);
|
return mark_space_contains_address(space, gc_conservative_ref_value(ref));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int mark_space_contains(struct mark_space *space,
|
||||||
|
struct gc_ref ref) {
|
||||||
|
return mark_space_contains_address(space, gc_ref_value(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) {
|
||||||
|
@ -625,18 +630,84 @@ static inline int trace_edge(struct gc_heap *heap, struct gc_edge edge) {
|
||||||
GC_CRASH();
|
GC_CRASH();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int trace_ref(struct gc_heap *heap, struct gc_ref ref) {
|
static inline struct gc_ref mark_space_mark_conservative_ref(struct mark_space *space,
|
||||||
if (!gc_ref_is_heap_object(ref))
|
struct gc_conservative_ref ref,
|
||||||
return 0;
|
int possibly_interior) {
|
||||||
if (GC_LIKELY(mark_space_contains(heap_mark_space(heap), ref))) {
|
uintptr_t addr = gc_conservative_ref_value(ref);
|
||||||
GC_ASSERT(!heap_mark_space(heap)->evacuating);
|
|
||||||
return mark_space_mark_object(heap_mark_space(heap), ref);
|
if (possibly_interior) {
|
||||||
|
addr = align_down(addr, GRANULE_SIZE);
|
||||||
|
} else {
|
||||||
|
// Addr not an aligned granule? Not an object.
|
||||||
|
uintptr_t displacement = addr & (GRANULE_SIZE - 1);
|
||||||
|
if (!gc_is_valid_conservative_ref_displacement(displacement))
|
||||||
|
return gc_ref_null();
|
||||||
|
addr -= displacement;
|
||||||
}
|
}
|
||||||
else if (large_object_space_contains(heap_large_object_space(heap), ref))
|
|
||||||
return large_object_space_mark_object(heap_large_object_space(heap),
|
// Addr in meta block? Not an object.
|
||||||
ref);
|
if ((addr & (SLAB_SIZE - 1)) < META_BLOCKS_PER_SLAB * BLOCK_SIZE)
|
||||||
|
return gc_ref_null();
|
||||||
|
|
||||||
|
// Addr in block that has been paged out? Not an object.
|
||||||
|
struct block_summary *summary = block_summary_for_addr(addr);
|
||||||
|
if (block_summary_has_flag(summary, BLOCK_UNAVAILABLE))
|
||||||
|
return gc_ref_null();
|
||||||
|
|
||||||
|
uint8_t *loc = metadata_byte_for_addr(addr);
|
||||||
|
uint8_t byte = atomic_load_explicit(loc, memory_order_relaxed);
|
||||||
|
|
||||||
|
// Already marked object? Nothing to do.
|
||||||
|
if (byte & space->marked_mask)
|
||||||
|
return gc_ref_null();
|
||||||
|
|
||||||
|
// Addr is the not start of an unmarked object? Search backwards if
|
||||||
|
// we have interior pointers, otherwise not an object.
|
||||||
|
uint8_t object_start_mask = space->live_mask | METADATA_BYTE_YOUNG;
|
||||||
|
if (!(byte & object_start_mask)) {
|
||||||
|
if (!possibly_interior)
|
||||||
|
return gc_ref_null();
|
||||||
|
|
||||||
|
uintptr_t block_base = align_down(addr, BLOCK_SIZE);
|
||||||
|
uint8_t *loc_base = metadata_byte_for_addr(block_base);
|
||||||
|
do {
|
||||||
|
// Searched past block? Not an object.
|
||||||
|
if (loc-- == loc_base)
|
||||||
|
return gc_ref_null();
|
||||||
|
|
||||||
|
byte = atomic_load_explicit(loc, memory_order_relaxed);
|
||||||
|
|
||||||
|
// Ran into the end of some other allocation? Not an object, then.
|
||||||
|
if (byte & METADATA_BYTE_END)
|
||||||
|
return gc_ref_null();
|
||||||
|
|
||||||
|
// Continue until we find object start.
|
||||||
|
} while (!(byte & object_start_mask));
|
||||||
|
|
||||||
|
// Found object start, and object is unmarked; adjust addr.
|
||||||
|
addr = block_base + (loc - loc_base) * GRANULE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t mask = METADATA_BYTE_YOUNG | METADATA_BYTE_MARK_0
|
||||||
|
| METADATA_BYTE_MARK_1 | METADATA_BYTE_MARK_2;
|
||||||
|
atomic_store_explicit(loc, (byte & ~mask) | space->marked_mask,
|
||||||
|
memory_order_relaxed);
|
||||||
|
|
||||||
|
return gc_ref(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct gc_ref trace_conservative_ref(struct gc_heap *heap,
|
||||||
|
struct gc_conservative_ref ref,
|
||||||
|
int possibly_interior) {
|
||||||
|
if (!gc_conservative_ref_might_be_a_heap_object(ref, possibly_interior))
|
||||||
|
return gc_ref_null();
|
||||||
|
|
||||||
|
if (GC_LIKELY(mark_space_contains_conservative_ref(heap_mark_space(heap), ref)))
|
||||||
|
return mark_space_mark_conservative_ref(heap_mark_space(heap), ref,
|
||||||
|
possibly_interior);
|
||||||
else
|
else
|
||||||
GC_CRASH();
|
return large_object_space_mark_conservative_ref(heap_large_object_space(heap),
|
||||||
|
ref, possibly_interior);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void trace_one(struct gc_ref ref, void *mark_data) {
|
static inline void trace_one(struct gc_ref ref, void *mark_data) {
|
||||||
|
@ -894,10 +965,24 @@ static void trace_and_enqueue_locally(struct gc_edge edge, void *data) {
|
||||||
mutator_mark_buf_push(&mut->mark_buf, gc_edge_ref(edge));
|
mutator_mark_buf_push(&mut->mark_buf, gc_edge_ref(edge));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void trace_ref_and_enqueue_locally(struct gc_ref ref, void *data) {
|
static inline void do_trace_conservative_ref_and_enqueue_locally(struct gc_conservative_ref ref,
|
||||||
|
void *data,
|
||||||
|
int possibly_interior) {
|
||||||
struct gc_mutator *mut = data;
|
struct gc_mutator *mut = data;
|
||||||
if (trace_ref(mutator_heap(mut), ref))
|
struct gc_ref object = trace_conservative_ref(mutator_heap(mut), ref,
|
||||||
mutator_mark_buf_push(&mut->mark_buf, ref);
|
possibly_interior);
|
||||||
|
if (gc_ref_is_heap_object(object))
|
||||||
|
mutator_mark_buf_push(&mut->mark_buf, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void trace_possibly_interior_conservative_ref_and_enqueue_locally
|
||||||
|
(struct gc_conservative_ref ref, void *data) {
|
||||||
|
return do_trace_conservative_ref_and_enqueue_locally(ref, data, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void trace_conservative_ref_and_enqueue_locally
|
||||||
|
(struct gc_conservative_ref ref, void *data) {
|
||||||
|
return do_trace_conservative_ref_and_enqueue_locally(ref, data, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void trace_and_enqueue_globally(struct gc_edge edge, void *data) {
|
static void trace_and_enqueue_globally(struct gc_edge edge, void *data) {
|
||||||
|
@ -906,40 +991,105 @@ static void trace_and_enqueue_globally(struct gc_edge edge, void *data) {
|
||||||
tracer_enqueue_root(&heap->tracer, gc_edge_ref(edge));
|
tracer_enqueue_root(&heap->tracer, gc_edge_ref(edge));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void trace_ref_and_enqueue_globally(struct gc_ref ref, void *data) {
|
static inline void do_trace_conservative_ref_and_enqueue_globally(struct gc_conservative_ref ref,
|
||||||
|
void *data,
|
||||||
|
int possibly_interior) {
|
||||||
struct gc_heap *heap = data;
|
struct gc_heap *heap = data;
|
||||||
if (trace_ref(heap, ref))
|
struct gc_ref object = trace_conservative_ref(heap, ref, possibly_interior);
|
||||||
tracer_enqueue_root(&heap->tracer, ref);
|
if (gc_ref_is_heap_object(object))
|
||||||
|
tracer_enqueue_root(&heap->tracer, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void trace_possibly_interior_conservative_ref_and_enqueue_globally(struct gc_conservative_ref ref,
|
||||||
|
void *data) {
|
||||||
|
return do_trace_conservative_ref_and_enqueue_globally(ref, data, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void trace_conservative_ref_and_enqueue_globally(struct gc_conservative_ref ref,
|
||||||
|
void *data) {
|
||||||
|
return do_trace_conservative_ref_and_enqueue_globally(ref, data, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct gc_conservative_ref
|
||||||
|
load_conservative_ref(uintptr_t addr) {
|
||||||
|
GC_ASSERT((addr & (sizeof(uintptr_t) - 1)) == 0);
|
||||||
|
uintptr_t val;
|
||||||
|
memcpy(&val, (char*)addr, sizeof(uintptr_t));
|
||||||
|
return gc_conservative_ref(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
trace_conservative_edges(uintptr_t low,
|
||||||
|
uintptr_t high,
|
||||||
|
void (*trace)(struct gc_conservative_ref, void *),
|
||||||
|
void *data) {
|
||||||
|
GC_ASSERT(low == align_down(low, sizeof(uintptr_t)));
|
||||||
|
GC_ASSERT(high == align_down(high, sizeof(uintptr_t)));
|
||||||
|
for (uintptr_t addr = low; addr < high; addr += sizeof(uintptr_t))
|
||||||
|
trace(load_conservative_ref(addr), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mark_and_globally_enqueue_mutator_conservative_roots(uintptr_t low,
|
||||||
|
uintptr_t high,
|
||||||
|
void *data) {
|
||||||
|
trace_conservative_edges(low, high,
|
||||||
|
gc_mutator_conservative_roots_may_be_interior()
|
||||||
|
? trace_possibly_interior_conservative_ref_and_enqueue_globally
|
||||||
|
: trace_conservative_ref_and_enqueue_globally,
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mark_and_globally_enqueue_heap_conservative_roots(uintptr_t low,
|
||||||
|
uintptr_t high,
|
||||||
|
void *data) {
|
||||||
|
trace_conservative_edges(low, high,
|
||||||
|
trace_conservative_ref_and_enqueue_globally,
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mark_and_locally_enqueue_mutator_conservative_roots(uintptr_t low,
|
||||||
|
uintptr_t high,
|
||||||
|
void *data) {
|
||||||
|
trace_conservative_edges(low, high,
|
||||||
|
gc_mutator_conservative_roots_may_be_interior()
|
||||||
|
? trace_possibly_interior_conservative_ref_and_enqueue_locally
|
||||||
|
: trace_conservative_ref_and_enqueue_locally,
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
trace_mutator_conservative_roots(struct gc_mutator *mut,
|
||||||
|
void (*trace_range)(uintptr_t low,
|
||||||
|
uintptr_t high,
|
||||||
|
void *data),
|
||||||
|
void *data) {
|
||||||
|
if (gc_has_mutator_conservative_roots())
|
||||||
|
gc_stack_visit(&mut->stack, trace_range, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the roots of a mutator that is stopping for GC. We can't
|
// Mark the roots of a mutator that is stopping for GC. We can't
|
||||||
// enqueue them directly, so we send them to the controller in a buffer.
|
// enqueue them directly, so we send them to the controller in a buffer.
|
||||||
static void trace_stopping_mutator_roots(struct gc_mutator *mut) {
|
static void trace_stopping_mutator_roots(struct gc_mutator *mut) {
|
||||||
GC_ASSERT(mutator_should_mark_while_stopping(mut));
|
GC_ASSERT(mutator_should_mark_while_stopping(mut));
|
||||||
/*
|
|
||||||
trace_mutator_conservative_roots(mut,
|
trace_mutator_conservative_roots(mut,
|
||||||
mark_and_locally_enqueue_conservative_roots,
|
mark_and_locally_enqueue_mutator_conservative_roots,
|
||||||
mut);
|
mut);
|
||||||
*/
|
gc_trace_mutator_roots(mut->roots, trace_and_enqueue_locally, mut);
|
||||||
gc_trace_precise_mutator_roots(mut->roots, trace_and_enqueue_locally, mut);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void trace_precise_mutator_roots_with_lock(struct gc_mutator *mut) {
|
|
||||||
gc_trace_precise_mutator_roots(mut->roots, trace_and_enqueue_globally,
|
|
||||||
mutator_heap(mut));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void trace_mutator_conservative_roots_with_lock(struct gc_mutator *mut) {
|
static void trace_mutator_conservative_roots_with_lock(struct gc_mutator *mut) {
|
||||||
/*
|
|
||||||
trace_mutator_conservative_roots(mut,
|
trace_mutator_conservative_roots(mut,
|
||||||
mark_and_globally_enqueue_conservative_roots,
|
mark_and_globally_enqueue_mutator_conservative_roots,
|
||||||
mutator_heap(mut));
|
mutator_heap(mut));
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void trace_mutator_roots_with_lock(struct gc_mutator *mut) {
|
static void trace_mutator_roots_with_lock(struct gc_mutator *mut) {
|
||||||
trace_mutator_conservative_roots_with_lock(mut);
|
trace_mutator_conservative_roots_with_lock(mut);
|
||||||
trace_precise_mutator_roots_with_lock(mut);
|
gc_trace_mutator_roots(mut->roots, trace_and_enqueue_globally,
|
||||||
|
mutator_heap(mut));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void trace_mutator_roots_with_lock_before_stop(struct gc_mutator *mut) {
|
static void trace_mutator_roots_with_lock_before_stop(struct gc_mutator *mut) {
|
||||||
|
@ -965,12 +1115,11 @@ static void finish_sweeping_in_block(struct gc_mutator *mut);
|
||||||
|
|
||||||
static void trace_mutator_conservative_roots_after_stop(struct gc_heap *heap) {
|
static void trace_mutator_conservative_roots_after_stop(struct gc_heap *heap) {
|
||||||
int active_mutators_already_marked = heap_should_mark_while_stopping(heap);
|
int active_mutators_already_marked = heap_should_mark_while_stopping(heap);
|
||||||
if (!active_mutators_already_marked) {
|
if (!active_mutators_already_marked)
|
||||||
for (struct gc_mutator *mut = atomic_load(&heap->mutator_trace_list);
|
for (struct gc_mutator *mut = atomic_load(&heap->mutator_trace_list);
|
||||||
mut;
|
mut;
|
||||||
mut = mut->next)
|
mut = mut->next)
|
||||||
trace_mutator_conservative_roots_with_lock(mut);
|
trace_mutator_conservative_roots_with_lock(mut);
|
||||||
}
|
|
||||||
|
|
||||||
for (struct gc_mutator *mut = heap->deactivated_mutators;
|
for (struct gc_mutator *mut = heap->deactivated_mutators;
|
||||||
mut;
|
mut;
|
||||||
|
@ -978,7 +1127,7 @@ static void trace_mutator_conservative_roots_after_stop(struct gc_heap *heap) {
|
||||||
trace_mutator_conservative_roots_with_lock(mut);
|
trace_mutator_conservative_roots_with_lock(mut);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void trace_precise_mutator_roots_after_stop(struct gc_heap *heap) {
|
static void trace_mutator_roots_after_stop(struct gc_heap *heap) {
|
||||||
struct gc_mutator *mut = atomic_load(&heap->mutator_trace_list);
|
struct gc_mutator *mut = atomic_load(&heap->mutator_trace_list);
|
||||||
int active_mutators_already_marked = heap_should_mark_while_stopping(heap);
|
int active_mutators_already_marked = heap_should_mark_while_stopping(heap);
|
||||||
while (mut) {
|
while (mut) {
|
||||||
|
@ -988,7 +1137,7 @@ static void trace_precise_mutator_roots_after_stop(struct gc_heap *heap) {
|
||||||
tracer_enqueue_roots(&heap->tracer, mut->mark_buf.objects,
|
tracer_enqueue_roots(&heap->tracer, mut->mark_buf.objects,
|
||||||
mut->mark_buf.size);
|
mut->mark_buf.size);
|
||||||
else
|
else
|
||||||
trace_precise_mutator_roots_with_lock(mut);
|
trace_mutator_roots_with_lock(mut);
|
||||||
// Also unlink mutator_trace_list chain.
|
// Also unlink mutator_trace_list chain.
|
||||||
struct gc_mutator *next = mut->next;
|
struct gc_mutator *next = mut->next;
|
||||||
mut->next = NULL;
|
mut->next = NULL;
|
||||||
|
@ -998,20 +1147,14 @@ static void trace_precise_mutator_roots_after_stop(struct gc_heap *heap) {
|
||||||
|
|
||||||
for (struct gc_mutator *mut = heap->deactivated_mutators; mut; mut = mut->next) {
|
for (struct gc_mutator *mut = heap->deactivated_mutators; mut; mut = mut->next) {
|
||||||
finish_sweeping_in_block(mut);
|
finish_sweeping_in_block(mut);
|
||||||
trace_precise_mutator_roots_with_lock(mut);
|
trace_mutator_roots_with_lock(mut);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void trace_precise_global_roots(struct gc_heap *heap) {
|
|
||||||
gc_trace_precise_heap_roots(heap->roots, trace_and_enqueue_globally, heap);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void trace_global_conservative_roots(struct gc_heap *heap) {
|
static void trace_global_conservative_roots(struct gc_heap *heap) {
|
||||||
/*
|
|
||||||
if (gc_has_global_conservative_roots())
|
if (gc_has_global_conservative_roots())
|
||||||
gc_platform_visit_global_conservative_roots
|
gc_platform_visit_global_conservative_roots
|
||||||
(mark_and_globally_enqueue_conservative_roots, heap);
|
(mark_and_globally_enqueue_heap_conservative_roots, heap);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t load_eight_aligned_bytes(uint8_t *mark) {
|
static inline uint64_t load_eight_aligned_bytes(uint8_t *mark) {
|
||||||
|
@ -1456,9 +1599,9 @@ static void trace_pinned_roots_after_stop(struct gc_heap *heap) {
|
||||||
trace_conservative_roots_after_stop(heap);
|
trace_conservative_roots_after_stop(heap);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void trace_precise_roots_after_stop(struct gc_heap *heap) {
|
static void trace_roots_after_stop(struct gc_heap *heap) {
|
||||||
trace_precise_mutator_roots_after_stop(heap);
|
trace_mutator_roots_after_stop(heap);
|
||||||
trace_precise_global_roots(heap);
|
gc_trace_heap_roots(heap->roots, trace_and_enqueue_globally, heap);
|
||||||
trace_generational_roots(heap);
|
trace_generational_roots(heap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1494,7 +1637,7 @@ static void collect(struct gc_mutator *mut) {
|
||||||
detect_out_of_memory(heap);
|
detect_out_of_memory(heap);
|
||||||
trace_pinned_roots_after_stop(heap);
|
trace_pinned_roots_after_stop(heap);
|
||||||
prepare_for_evacuation(heap);
|
prepare_for_evacuation(heap);
|
||||||
trace_precise_roots_after_stop(heap);
|
trace_roots_after_stop(heap);
|
||||||
tracer_trace(heap);
|
tracer_trace(heap);
|
||||||
tracer_release(heap);
|
tracer_release(heap);
|
||||||
mark_space_finish_gc(space, gc_kind);
|
mark_space_finish_gc(space, gc_kind);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue