1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-20 03:30:27 +02:00

Add field-logging write barrier (fast path only)

Add a new kind of write barrier, one which has a bit per field; the
mutator that sets the bit will need to add the field's location (the
edge) to a remembered set.  Here we just have the fast-path
implementation.
This commit is contained in:
Andy Wingo 2024-10-01 10:34:27 +02:00
parent 3955d2ad96
commit 1f4e3bdf37
11 changed files with 89 additions and 22 deletions

View file

@ -49,6 +49,15 @@ static inline size_t gc_write_barrier_card_table_alignment(void) {
static inline size_t gc_write_barrier_card_size(void) {
GC_CRASH();
}
static inline size_t gc_write_barrier_field_table_alignment(void) {
GC_CRASH();
}
static inline size_t gc_write_barrier_field_fields_per_byte(void) {
GC_CRASH();
}
static inline uint8_t gc_write_barrier_field_first_bit_pattern(void) {
GC_CRASH();
}
static inline enum gc_safepoint_mechanism gc_safepoint_mechanism(void) {
return GC_SAFEPOINT_MECHANISM_SIGNAL;

View file

@ -179,13 +179,16 @@ static inline void* gc_allocate(struct gc_mutator *mut, size_t size) {
// FIXME: remove :P
GC_API_ void* gc_allocate_pointerless(struct gc_mutator *mut, size_t bytes);
GC_API_ void gc_write_barrier_extern(struct gc_ref obj, size_t obj_size,
struct gc_edge edge, struct gc_ref new_val) GC_NEVER_INLINE;
GC_API_ void gc_write_barrier_slow(struct gc_mutator *mut, struct gc_ref obj,
size_t obj_size, struct gc_edge edge,
struct gc_ref new_val) GC_NEVER_INLINE;
static inline void gc_write_barrier(struct gc_ref obj, size_t obj_size,
struct gc_edge edge, struct gc_ref new_val) GC_ALWAYS_INLINE;
static inline void gc_write_barrier(struct gc_ref obj, size_t obj_size,
struct gc_edge edge, struct gc_ref new_val) {
static inline void gc_write_barrier(struct gc_mutator *mut, struct gc_ref obj,
size_t obj_size, struct gc_edge edge,
struct gc_ref new_val) GC_ALWAYS_INLINE;
static inline void gc_write_barrier(struct gc_mutator *mut, struct gc_ref obj,
size_t obj_size, struct gc_edge edge,
struct gc_ref new_val) {
switch (gc_write_barrier_kind(obj_size)) {
case GC_WRITE_BARRIER_NONE:
return;
@ -198,8 +201,24 @@ static inline void gc_write_barrier(struct gc_ref obj, size_t obj_size,
atomic_store_explicit((uint8_t*)(base + card), 1, memory_order_relaxed);
return;
}
case GC_WRITE_BARRIER_EXTERN:
gc_write_barrier_extern(obj, obj_size, edge, new_val);
case GC_WRITE_BARRIER_FIELD: {
size_t field_table_alignment = gc_write_barrier_field_table_alignment();
size_t fields_per_byte = gc_write_barrier_field_fields_per_byte();
uint8_t first_bit_pattern = gc_write_barrier_field_first_bit_pattern();
uintptr_t addr = (uintptr_t) gc_edge_loc(edge);
uintptr_t base = addr & ~(field_table_alignment - 1);
uintptr_t field = (addr & (field_table_alignment - 1)) / sizeof(uintptr_t);
uintptr_t log_byte = field / fields_per_byte;
uint8_t log_bit = first_bit_pattern << (field % fields_per_byte);
uint8_t *byte_loc = (uint8_t*)(base + log_byte);
uint8_t byte = atomic_load_explicit(byte_loc, memory_order_relaxed);
if (!(byte & log_bit))
gc_write_barrier_slow(mut, obj, obj_size, edge, new_val);
return;
}
case GC_WRITE_BARRIER_SLOW:
gc_write_barrier_slow(mut, obj, obj_size, edge, new_val);
return;
default:
GC_CRASH();

View file

@ -30,12 +30,16 @@ static inline int gc_allocator_needs_clear(void) GC_ALWAYS_INLINE;
enum gc_write_barrier_kind {
GC_WRITE_BARRIER_NONE,
GC_WRITE_BARRIER_CARD,
GC_WRITE_BARRIER_EXTERN
GC_WRITE_BARRIER_FIELD,
GC_WRITE_BARRIER_SLOW
};
static inline enum gc_write_barrier_kind gc_write_barrier_kind(size_t obj_size) GC_ALWAYS_INLINE;
static inline size_t gc_write_barrier_card_table_alignment(void) GC_ALWAYS_INLINE;
static inline size_t gc_write_barrier_card_size(void) GC_ALWAYS_INLINE;
static inline size_t gc_write_barrier_field_table_alignment(void) GC_ALWAYS_INLINE;
static inline size_t gc_write_barrier_field_fields_per_byte(void) GC_ALWAYS_INLINE;
static inline uint8_t gc_write_barrier_field_first_bit_pattern(void) GC_ALWAYS_INLINE;
enum gc_safepoint_mechanism {
GC_SAFEPOINT_MECHANISM_COOPERATIVE,

View file

@ -44,7 +44,7 @@ static inline enum gc_write_barrier_kind gc_write_barrier_kind(size_t obj_size)
if (GC_GENERATIONAL) {
if (obj_size <= gc_allocator_large_threshold())
return GC_WRITE_BARRIER_CARD;
return GC_WRITE_BARRIER_EXTERN;
return GC_WRITE_BARRIER_SLOW;
}
return GC_WRITE_BARRIER_NONE;
}
@ -56,6 +56,18 @@ static inline size_t gc_write_barrier_card_size(void) {
GC_ASSERT(GC_GENERATIONAL);
return 256;
}
static inline size_t gc_write_barrier_field_table_alignment(void) {
GC_ASSERT(GC_GENERATIONAL);
return 4 * 1024 * 1024;
}
static inline size_t gc_write_barrier_field_fields_per_byte(void) {
GC_ASSERT(GC_GENERATIONAL);
return 2;
}
static inline uint8_t gc_write_barrier_field_first_bit_pattern(void) {
GC_ASSERT(GC_GENERATIONAL);
return 64; // NOFL_METADATA_BYTE_LOGGED_0
}
static inline enum gc_safepoint_mechanism gc_safepoint_mechanism(void) {
return GC_SAFEPOINT_MECHANISM_COOPERATIVE;

View file

@ -52,6 +52,15 @@ static inline size_t gc_write_barrier_card_table_alignment(void) {
static inline size_t gc_write_barrier_card_size(void) {
GC_CRASH();
}
static inline size_t gc_write_barrier_field_table_alignment(void) {
GC_CRASH();
}
static inline size_t gc_write_barrier_field_fields_per_byte(void) {
GC_CRASH();
}
static inline uint8_t gc_write_barrier_field_first_bit_pattern(void) {
GC_CRASH();
}
static inline enum gc_safepoint_mechanism gc_safepoint_mechanism(void) {
return GC_SAFEPOINT_MECHANISM_COOPERATIVE;

View file

@ -51,6 +51,15 @@ static inline size_t gc_write_barrier_card_table_alignment(void) {
static inline size_t gc_write_barrier_card_size(void) {
GC_CRASH();
}
static inline size_t gc_write_barrier_field_table_alignment(void) {
GC_CRASH();
}
static inline size_t gc_write_barrier_field_fields_per_byte(void) {
GC_CRASH();
}
static inline uint8_t gc_write_barrier_field_first_bit_pattern(void) {
GC_CRASH();
}
static inline enum gc_safepoint_mechanism gc_safepoint_mechanism(void) {
return GC_SAFEPOINT_MECHANISM_COOPERATIVE;

View file

@ -144,8 +144,9 @@ static void allocate_garbage(struct thread *t) {
}
}
static void set_field(Node *obj, Node **field, Node *val) {
gc_write_barrier(gc_ref_from_heap_object(obj), sizeof(Node),
static void set_field(struct gc_mutator *mut, Node *obj,
Node **field, Node *val) {
gc_write_barrier(mut, gc_ref_from_heap_object(obj), sizeof(Node),
gc_edge(field),
gc_ref_from_heap_object(val));
*field = val;
@ -166,8 +167,8 @@ static void populate(struct thread *t, int depth, Node *node) {
NodeHandle r = { allocate_node(mut) };
PUSH_HANDLE(t, r);
set_field(HANDLE_REF(self), &HANDLE_REF(self)->left, HANDLE_REF(l));
set_field(HANDLE_REF(self), &HANDLE_REF(self)->right, HANDLE_REF(r));
set_field(mut, HANDLE_REF(self), &HANDLE_REF(self)->left, HANDLE_REF(l));
set_field(mut, HANDLE_REF(self), &HANDLE_REF(self)->right, HANDLE_REF(r));
// i is 0 because the memory is zeroed.
HANDLE_REF(self)->j = depth;

View file

@ -149,8 +149,9 @@ void gc_collect(struct gc_mutator *mut,
}
}
void gc_write_barrier_extern(struct gc_ref obj, size_t obj_size,
struct gc_edge edge, struct gc_ref new_val) {
void gc_write_barrier_slow(struct gc_mutator *mut, struct gc_ref obj,
size_t obj_size, struct gc_edge edge,
struct gc_ref new_val) {
}
int* gc_safepoint_flag_loc(struct gc_mutator *mut) { GC_CRASH(); }

View file

@ -876,8 +876,9 @@ gc_pin_object(struct gc_mutator *mut, struct gc_ref ref) {
}
void
gc_write_barrier_extern(struct gc_ref obj, size_t obj_size,
struct gc_edge edge, struct gc_ref new_val) {
gc_write_barrier_slow(struct gc_mutator *mut, struct gc_ref obj,
size_t obj_size, struct gc_edge edge,
struct gc_ref new_val) {
GC_ASSERT(obj_size > gc_allocator_large_threshold());
gc_object_set_remembered(obj);
}

View file

@ -483,8 +483,9 @@ void gc_pin_object(struct gc_mutator *mut, struct gc_ref ref) {
GC_CRASH();
}
void gc_write_barrier_extern(struct gc_ref obj, size_t obj_size,
struct gc_edge edge, struct gc_ref new_val) {
void gc_write_barrier_slow(struct gc_mutator *mut, struct gc_ref obj,
size_t obj_size, struct gc_edge edge,
struct gc_ref new_val) {
}
int* gc_safepoint_flag_loc(struct gc_mutator *mut) {

View file

@ -453,8 +453,9 @@ void gc_collect(struct gc_mutator *mut,
collect(mut, 0);
}
void gc_write_barrier_extern(struct gc_ref obj, size_t obj_size,
struct gc_edge edge, struct gc_ref new_val) {
void gc_write_barrier_slow(struct gc_mutator *mut, struct gc_ref obj,
size_t obj_size, struct gc_edge edge,
struct gc_ref new_val) {
}
int* gc_safepoint_flag_loc(struct gc_mutator *mut) { GC_CRASH(); }