@@ -160,6 +160,29 @@ define_tunables! {
160160 /// forced and the counter is reset. Only effective when
161161 /// `cfg(gc_zeal)` is enabled.
162162 pub gc_zeal_alloc_counter: Option <NonZeroU32 >,
163+
164+ /// Initial size, in bytes, to be allocated for GC heaps.
165+ ///
166+ /// This is the same as `memory_reservation` but for GC heaps.
167+ pub gc_heap_reservation: u64 ,
168+
169+ /// The size, in bytes, of the guard page region for GC heaps.
170+ ///
171+ /// This is the same as `memory_guard_size` but for GC heaps.
172+ pub gc_heap_guard_size: u64 ,
173+
174+ /// The size, in bytes, to allocate at the end of a relocated GC heap
175+ /// for growth.
176+ ///
177+ /// This is the same as `memory_reservation_for_growth` but for GC
178+ /// heaps.
179+ pub gc_heap_reservation_for_growth: u64 ,
180+
181+ /// Whether or not GC heaps are allowed to be reallocated after initial
182+ /// allocation at runtime.
183+ ///
184+ /// This is the same as `memory_may_move` but for GC heaps.
185+ pub gc_heap_may_move: bool ,
163186 }
164187
165188 pub struct ConfigTunables {
@@ -200,6 +223,7 @@ impl Tunables {
200223 if target. is_pulley ( ) {
201224 ret. signals_based_traps = false ;
202225 ret. memory_guard_size = 0 ;
226+ ret. gc_heap_guard_size = 0 ;
203227 }
204228 Ok ( ret)
205229 }
@@ -239,6 +263,10 @@ impl Tunables {
239263 concurrency_support : true ,
240264 recording : false ,
241265 gc_zeal_alloc_counter : None ,
266+ gc_heap_reservation : 0 ,
267+ gc_heap_guard_size : 0 ,
268+ gc_heap_reservation_for_growth : 0 ,
269+ gc_heap_may_move : true ,
242270 }
243271 }
244272
@@ -253,6 +281,12 @@ impl Tunables {
253281 memory_reservation_for_growth : 1 << 20 , // 1MB
254282 signals_based_traps : true ,
255283
284+ // GC heaps on 32-bit: conservative defaults similar to linear
285+ // memories.
286+ gc_heap_reservation : 10 * ( 1 << 20 ) ,
287+ gc_heap_guard_size : 0x1_0000 ,
288+ gc_heap_reservation_for_growth : 1 << 20 , // 1MB
289+
256290 ..Tunables :: default_miri ( )
257291 }
258292 }
@@ -278,6 +312,12 @@ impl Tunables {
278312 // to avoid memory movement.
279313 memory_reservation_for_growth : 2 << 30 , // 2GB
280314
315+ // GC heaps on 64-bit: use 4GiB reservation and 32MiB guard pages
316+ // to enable bounds check elision, matching linear memory defaults.
317+ gc_heap_reservation : 1 << 32 ,
318+ gc_heap_guard_size : 32 << 20 ,
319+ gc_heap_reservation_for_growth : 2 << 30 , // 2GB
320+
281321 signals_based_traps : true ,
282322 ..Tunables :: default_miri ( )
283323 }
@@ -298,6 +338,73 @@ impl Tunables {
298338 }
299339}
300340
341+ /// Whether a heap is backing a linear memory or a GC heap.
342+ ///
343+ /// This is used by [`MemoryTunables`] to select between the memory tunables and
344+ /// the GC heap tunables.
345+ #[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash ) ]
346+ pub enum MemoryKind {
347+ /// A WebAssembly linear memory.
348+ LinearMemory ,
349+ /// A GC heap for garbage-collected objects.
350+ GcHeap ,
351+ }
352+
353+ /// A view into a [`Tunables`] that selects the appropriate linear-memory or
354+ /// GC-heap flavor of each tunable based on a [`MemoryKind`].
355+ pub struct MemoryTunables < ' a > {
356+ tunables : & ' a Tunables ,
357+ kind : MemoryKind ,
358+ }
359+
360+ impl < ' a > MemoryTunables < ' a > {
361+ /// Create a new `MemoryTunables` view.
362+ pub fn new ( tunables : & ' a Tunables , kind : MemoryKind ) -> Self {
363+ Self { tunables, kind }
364+ }
365+
366+ /// The virtual memory reservation for this kind of memory.
367+ pub fn reservation ( & self ) -> u64 {
368+ match self . kind {
369+ MemoryKind :: LinearMemory => self . tunables . memory_reservation ,
370+ MemoryKind :: GcHeap => self . tunables . gc_heap_reservation ,
371+ }
372+ }
373+
374+ /// The size of the guard page region for this kind of memory.
375+ pub fn guard_size ( & self ) -> u64 {
376+ match self . kind {
377+ MemoryKind :: LinearMemory => self . tunables . memory_guard_size ,
378+ MemoryKind :: GcHeap => self . tunables . gc_heap_guard_size ,
379+ }
380+ }
381+
382+ /// Extra virtual memory to reserve beyond the initially mapped pages for
383+ /// this kind of memory.
384+ pub fn reservation_for_growth ( & self ) -> u64 {
385+ match self . kind {
386+ MemoryKind :: LinearMemory => self . tunables . memory_reservation_for_growth ,
387+ MemoryKind :: GcHeap => self . tunables . gc_heap_reservation_for_growth ,
388+ }
389+ }
390+
391+ /// Whether this kind of memory's base pointer may be relocated at runtime.
392+ pub fn may_move ( & self ) -> bool {
393+ match self . kind {
394+ MemoryKind :: LinearMemory => self . tunables . memory_may_move ,
395+ MemoryKind :: GcHeap => self . tunables . gc_heap_may_move ,
396+ }
397+ }
398+
399+ /// Get the underlying tunables.
400+ ///
401+ /// This is ONLY for accessing tunable fields that DO NOT come in a
402+ /// linear-memory flavor and a GC-heap flavor.
403+ pub fn tunables ( & self ) -> & ' a Tunables {
404+ self . tunables
405+ }
406+ }
407+
301408/// The garbage collector implementation to use.
302409#[ derive( Clone , Copy , Hash , Serialize , Deserialize , Debug , PartialEq , Eq ) ]
303410pub enum Collector {
0 commit comments