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

commit 1d157a133df4d802a6070b27199e5b7164df64d6
Author: Andy Wingo <wi...@igalia.com>
AuthorDate: Thu May 22 14:57:34 2025 +0200

    mmc: Add "headroom" for growable heaps that cannot defragment
---
 src/mmc.c        | 26 +++++++++++++++-----------
 src/nofl-space.h | 12 ++++++++++--
 2 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/src/mmc.c b/src/mmc.c
index 4bbfed019..a65219a50 100644
--- a/src/mmc.c
+++ b/src/mmc.c
@@ -575,20 +575,24 @@ compute_progress(struct gc_heap *heap, uintptr_t 
allocation_since_last_gc) {
 }
 
 static void
-grow_heap_for_large_allocation_if_necessary(struct gc_heap *heap,
-                                            enum gc_collection_kind gc_kind,
-                                            int progress)
+grow_heap_if_necessary(struct gc_heap *heap,
+                       enum gc_collection_kind gc_kind,
+                       int progress)
 {
-  if (progress || heap->sizer.policy == GC_HEAP_SIZE_FIXED)
+  if (heap->sizer.policy == GC_HEAP_SIZE_FIXED)
     return;
 
   struct nofl_space *nofl = heap_nofl_space(heap);
-  if (nofl_space_shrink (nofl, 0))
-    return;
+  size_t pending = nofl_space_shrink(nofl, 0);
+
+  size_t needed_headroom =
+    GC_CONSERVATIVE_TRACE
+    ? nofl_active_block_count (nofl) * NOFL_BLOCK_SIZE / 16
+    : 0;
+  size_t headroom = nofl_empty_block_count(nofl) * NOFL_BLOCK_SIZE;
 
-  ssize_t pending = nofl_space_request_release_memory(nofl, 0);
-  GC_ASSERT (pending > 0);
-  resize_heap(heap, heap->size + pending);
+  if (headroom < needed_headroom + pending)
+    resize_heap(heap, heap->size - headroom + needed_headroom + pending);
 }
 
 static int
@@ -893,7 +897,7 @@ collect(struct gc_mutator *mut, enum gc_collection_kind 
requested_kind) {
   DEBUG("--- total live bytes estimate: %zu\n", live_bytes_estimate);
   gc_heap_sizer_on_gc(heap->sizer, heap->size, live_bytes_estimate, pause_ns,
                       resize_heap);
-  grow_heap_for_large_allocation_if_necessary(heap, gc_kind, progress);
+  grow_heap_if_necessary(heap, gc_kind, progress);
   heap->size_at_last_gc = heap->size;
   HEAP_EVENT(heap, restarting_mutators);
   allow_mutators_to_continue(heap);
@@ -992,7 +996,7 @@ allocate_large(struct gc_mutator *mut, size_t size,
   nofl_space_request_release_memory(nofl_space,
                                     npages << lospace->page_size_log2);
 
-  while (!nofl_space_shrink(nofl_space, 0)) {
+  while (nofl_space_shrink(nofl_space, 0)) {
     if (!trigger_collection(mut, GC_COLLECTION_COMPACTING))
       return heap->allocation_failure(heap, size);
   }
diff --git a/src/nofl-space.h b/src/nofl-space.h
index e9d9efb3c..b36694d82 100644
--- a/src/nofl-space.h
+++ b/src/nofl-space.h
@@ -520,6 +520,14 @@ nofl_pop_unavailable_block(struct nofl_space *space,
   return nofl_block_null();
 }
 
+static size_t
+nofl_empty_block_count(struct nofl_space *space) {
+  struct gc_lock lock = nofl_space_lock(space);
+  size_t ret = nofl_block_count(&space->empty.list);
+  gc_lock_release(&lock);
+  return ret;
+}
+
 static void
 nofl_push_empty_block(struct nofl_space *space,
                       struct nofl_block_ref block,
@@ -1807,7 +1815,7 @@ nofl_space_add_slabs(struct nofl_space *space, struct 
nofl_slab *slabs,
     space->slabs[space->nslabs++] = slabs++;
 }
 
-static int
+static size_t
 nofl_space_shrink(struct nofl_space *space, size_t bytes) {
   ssize_t pending = nofl_space_request_release_memory(space, bytes);
   struct gc_lock lock = nofl_space_lock(space);
@@ -1847,7 +1855,7 @@ nofl_space_shrink(struct nofl_space *space, size_t bytes) 
{
 
   // It still may be the case we need to page out more blocks.  Only evacuation
   // can help us then!
-  return pending <= 0;
+  return pending <= 0 ? 0 : pending;
 }
       
 static void

Reply via email to