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

commit cc2a90b4949fa91e7fca814882a83e46a69260f8
Author: Andy Wingo <wi...@igalia.com>
AuthorDate: Mon May 12 13:37:18 2025 +0200

    bdw: Fix detection of objects on free-lists
    
    I am not sure about ephemerons and finalizers, though.
---
 src/bdw.c | 25 ++++++++++++-------------
 1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/src/bdw.c b/src/bdw.c
index a50994d7c..e6b3f4ef5 100644
--- a/src/bdw.c
+++ b/src/bdw.c
@@ -52,7 +52,6 @@
 #define GC_INLINE_FREELIST_COUNT (256U / GC_INLINE_GRANULE_BYTES)
 
 struct gc_heap {
-  struct gc_heap *freelist; // see mark_heap
   struct gc_heap_roots *roots;
   struct gc_mutator *mutators;
   struct gc_event_listener event_listener;
@@ -315,7 +314,7 @@ mark_ephemeron(GC_word *addr, struct GC_ms_entry 
*mark_stack_ptr,
   
   struct gc_ephemeron *ephemeron = (struct gc_ephemeron*) addr;
 
-  // If this ephemeron is on a freelist, its first word will be a
+  // If this ephemeron is on a freelist, its first word will be a possibly-null
   // freelist link and everything else will be NULL.
   if (!gc_ref_value(gc_edge_ref(gc_ephemeron_value_edge(ephemeron)))) {
     bdw_mark_edge(gc_edge(addr), NULL, &state);
@@ -344,7 +343,7 @@ mark_finalizer(GC_word *addr, struct GC_ms_entry 
*mark_stack_ptr,
   
   struct gc_finalizer *finalizer = (struct gc_finalizer*) addr;
 
-  // If this ephemeron is on a freelist, its first word will be a
+  // If this ephemeron is on a freelist, its first word will be a possibly-null
   // freelist link and everything else will be NULL.
   if (!gc_ref_value(gc_finalizer_object(finalizer))) {
     bdw_mark_edge(gc_edge(addr), NULL, &state);
@@ -366,13 +365,10 @@ mark_heap(GC_word *addr, struct GC_ms_entry 
*mark_stack_ptr,
   
   struct gc_heap *heap = (struct gc_heap*) addr;
 
-  // If this heap is on a freelist... well probably we are screwed, BDW
-  // isn't really made to do multiple heaps in a process.  But still, in
-  // this case, the first word is the freelist and the rest are null.
-  if (heap->freelist) {
-    bdw_mark_edge(gc_edge(addr), NULL, &state);
+  // If this heap is not __the_bdw_gc_heap, either it is on a freelist, or the
+  // heap object is still under construction.  In either case, ignore it.
+  if (heap != __the_bdw_gc_heap)
     return state.mark_stack_ptr;
-  }
 
   if (heap->roots)
     gc_trace_heap_roots(heap->roots, bdw_mark_edge, heap, &state);
@@ -397,9 +393,12 @@ mark_mutator(GC_word *addr, struct GC_ms_entry 
*mark_stack_ptr,
   
   struct gc_mutator *mut = (struct gc_mutator*) addr;
 
-  // If this mutator is on a freelist, its first word will be a
-  // freelist link and everything else will be NULL.
-  if (!mut->heap) {
+  // A mutator is valid and initialized if its "heap" member points to
+  // __the_bdw_gc_heap.  Otherwise it could be on a freelist, in which case its
+  // first word will be a possibly-null freelist link, or it could be under
+  // construction, or it could be exited already.  In any case, mark the free
+  // list link and finish.
+  if (mut->heap != __the_bdw_gc_heap) {
     bdw_mark_edge(gc_edge(addr), NULL, &state);
     return state.mark_stack_ptr;
   }
@@ -420,7 +419,6 @@ mark_mutator(GC_word *addr, struct GC_ms_entry 
*mark_stack_ptr,
 static inline struct gc_mutator *add_mutator(struct gc_heap *heap) {
   struct gc_mutator *ret =
     GC_generic_malloc(sizeof(struct gc_mutator), mutator_gc_kind);
-  ret->heap = heap;
   ret->event_listener_data =
     heap->event_listener.mutator_added(heap->event_listener_data);
 
@@ -430,6 +428,7 @@ static inline struct gc_mutator *add_mutator(struct gc_heap 
*heap) {
   if (ret->next)
     ret->next->prev = &ret->next;
   heap->mutators = ret;
+  ret->heap = heap;
   GC_alloc_unlock();
 
   return ret;

Reply via email to