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:
parent
3955d2ad96
commit
1f4e3bdf37
11 changed files with 89 additions and 22 deletions
|
@ -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;
|
||||
|
|
35
api/gc-api.h
35
api/gc-api.h
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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(); }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue