wingo pushed a commit to branch wip-whippet
in repository guile.

commit 1f4e3bdf3731a48f9758d0cf1f304a77aacf4de0
Author: Andy Wingo <wi...@igalia.com>
AuthorDate: Tue Oct 1 10:34:27 2024 +0200

    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.
---
 api/bdw-attrs.h         |  9 +++++++++
 api/gc-api.h            | 37 ++++++++++++++++++++++++++++---------
 api/gc-attrs.h          |  6 +++++-
 api/mmc-attrs.h         | 14 +++++++++++++-
 api/pcc-attrs.h         |  9 +++++++++
 api/semi-attrs.h        |  9 +++++++++
 benchmarks/mt-gcbench.c |  9 +++++----
 src/bdw.c               |  5 +++--
 src/mmc.c               |  5 +++--
 src/pcc.c               |  5 +++--
 src/semi.c              |  5 +++--
 11 files changed, 90 insertions(+), 23 deletions(-)

diff --git a/api/bdw-attrs.h b/api/bdw-attrs.h
index af1042af3..51b4e72f1 100644
--- a/api/bdw-attrs.h
+++ b/api/bdw-attrs.h
@@ -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;
diff --git a/api/gc-api.h b/api/gc-api.h
index 63921f628..cb1e4e819 100644
--- a/api/gc-api.h
+++ b/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;
-
-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) {
+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_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();
diff --git a/api/gc-attrs.h b/api/gc-attrs.h
index b6acb4302..39faceae2 100644
--- a/api/gc-attrs.h
+++ b/api/gc-attrs.h
@@ -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,
diff --git a/api/mmc-attrs.h b/api/mmc-attrs.h
index e5757f6d1..6da4b2a68 100644
--- a/api/mmc-attrs.h
+++ b/api/mmc-attrs.h
@@ -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;
diff --git a/api/pcc-attrs.h b/api/pcc-attrs.h
index 2f02640ea..5dd38c42f 100644
--- a/api/pcc-attrs.h
+++ b/api/pcc-attrs.h
@@ -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;
diff --git a/api/semi-attrs.h b/api/semi-attrs.h
index bcd8e89e0..94e2dc814 100644
--- a/api/semi-attrs.h
+++ b/api/semi-attrs.h
@@ -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;
diff --git a/benchmarks/mt-gcbench.c b/benchmarks/mt-gcbench.c
index 05ae887d0..7f342fe90 100644
--- a/benchmarks/mt-gcbench.c
+++ b/benchmarks/mt-gcbench.c
@@ -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;
 
diff --git a/src/bdw.c b/src/bdw.c
index df579dde7..d4cbe4c41 100644
--- a/src/bdw.c
+++ b/src/bdw.c
@@ -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(); }
diff --git a/src/mmc.c b/src/mmc.c
index 48d8eae59..63778d669 100644
--- a/src/mmc.c
+++ b/src/mmc.c
@@ -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);
 }
diff --git a/src/pcc.c b/src/pcc.c
index 90194e96a..10d5f8382 100644
--- a/src/pcc.c
+++ b/src/pcc.c
@@ -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) {
diff --git a/src/semi.c b/src/semi.c
index 7958b5898..aab5af233 100644
--- a/src/semi.c
+++ b/src/semi.c
@@ -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(); }

Reply via email to