@@ -4,8 +4,7 @@ use super::*;
44use crate :: runtime:: vm:: VMGcRef ;
55
66impl StoreOpaque {
7- /// Attempt to grow the GC heap by `bytes_needed` or, if that fails, perform
8- /// a garbage collection.
7+ /// Perform any growth or GC needed to allocate `bytes_needed` bytes.
98 ///
109 /// Note that even when this function returns it is not guaranteed
1110 /// that a GC allocation of size `bytes_needed` will succeed. Growing the GC
@@ -28,7 +27,7 @@ impl StoreOpaque {
2827 let root = root. map ( |r| scope. gc_roots_mut ( ) . push_lifo_root ( store_id, r) ) ;
2928
3029 scope
31- . grow_or_collect_gc_heap ( limiter, bytes_needed, asyncness)
30+ . collect_and_maybe_grow_gc_heap ( limiter, bytes_needed, asyncness)
3231 . await ;
3332
3433 root. map ( |r| {
@@ -50,16 +49,26 @@ impl StoreOpaque {
5049 }
5150 }
5251
53- async fn grow_or_collect_gc_heap (
52+ /// Helper invoked as part of `gc`, whose purpose is to GC and
53+ /// maybe grow for a pending allocation of a given size.
54+ async fn collect_and_maybe_grow_gc_heap (
5455 & mut self ,
5556 limiter : Option < & mut StoreResourceLimiter < ' _ > > ,
5657 bytes_needed : Option < u64 > ,
5758 asyncness : Asyncness ,
5859 ) {
59- // When explicitly called (e.g., from Store::gc), always collect.
60- // If bytes_needed is specified, also try to grow if needed.
60+ // First, always collect. Then, if bytes_needed is specified,
61+ // also try to grow if that size is greater than GC heap
62+ // capacity minus sum of allocated layout sizes.
6163 self . do_gc ( asyncness) . await ;
62- if let Some ( n) = bytes_needed {
64+ if let Some ( n) = bytes_needed
65+ && n > u64:: try_from ( self . gc_heap_capacity ( ) )
66+ . unwrap ( )
67+ . checked_sub ( self . gc_store . as_ref ( ) . map_or ( 0 , |gc| {
68+ u64:: try_from ( gc. last_post_gc_allocated_bytes . unwrap_or ( 0 ) ) . unwrap ( )
69+ } ) )
70+ . expect ( "allocated bytes cannot be greater than capacity" )
71+ {
6372 let _ = self . grow_gc_heap ( limiter, n) . await ;
6473 }
6574 }
0 commit comments