From 62cb89ec751f45d273e8d625a533f698db5fa7ae Mon Sep 17 00:00:00 2001 From: Yi Lin Date: Fri, 8 Aug 2025 01:35:37 +0000 Subject: [PATCH 01/12] Refactor log bits --- src/plan/generational/copying/global.rs | 3 ++ src/plan/generational/global.rs | 3 ++ src/plan/generational/immix/global.rs | 5 ++- src/plan/generational/mod.rs | 2 + src/plan/global.rs | 39 ++++++++++++++++++- src/plan/immix/global.rs | 1 - src/plan/pageprotect/global.rs | 1 + src/plan/plan_constraints.rs | 6 +++ src/plan/sticky/immix/global.rs | 10 +++-- src/policy/copyspace.rs | 20 +++++++--- src/policy/immix/immixspace.rs | 33 ++++++++-------- src/policy/immortalspace.rs | 18 ++++++++- src/policy/largeobjectspace.rs | 26 +++++++++++-- src/policy/marksweepspace/native_ms/global.rs | 24 +++++++----- src/policy/space.rs | 6 +++ src/policy/vmspace.rs | 20 +++++++++- src/util/copy/mod.rs | 2 +- 17 files changed, 172 insertions(+), 47 deletions(-) diff --git a/src/plan/generational/copying/global.rs b/src/plan/generational/copying/global.rs index b23a81c998..b701f8e07d 100644 --- a/src/plan/generational/copying/global.rs +++ b/src/plan/generational/copying/global.rs @@ -110,6 +110,9 @@ impl Plan for GenCopy { let full_heap = !self.gen.is_current_gc_nursery(); self.gen.release(tls); if full_heap { + if VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.is_on_side() { + self.fromspace().clear_side_log_bits(); + } self.fromspace().release(); } } diff --git a/src/plan/generational/global.rs b/src/plan/generational/global.rs index 0404fc93bb..9617bcd1f4 100644 --- a/src/plan/generational/global.rs +++ b/src/plan/generational/global.rs @@ -74,6 +74,9 @@ impl CommonGenPlan { /// Release Gen. This should be called by a single thread in GC release work. pub fn release(&mut self, tls: VMWorkerThread) { let full_heap = !self.is_current_gc_nursery(); + if VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.is_on_side() { + self.nursery.clear_side_log_bits(); + } self.common.release(tls, full_heap); self.nursery.release(); } diff --git a/src/plan/generational/immix/global.rs b/src/plan/generational/immix/global.rs index ff76d5ac55..ba1dc8a9ca 100644 --- a/src/plan/generational/immix/global.rs +++ b/src/plan/generational/immix/global.rs @@ -129,6 +129,9 @@ impl Plan for GenImmix { let full_heap = !self.gen.is_current_gc_nursery(); self.gen.prepare(tls); if full_heap { + if VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.is_on_side() { + self.immix_space.clear_side_log_bits(); + } self.immix_space.prepare( full_heap, Some(crate::policy::immix::defrag::StatsForDefrag::new(self)), @@ -249,8 +252,6 @@ impl GenImmix { let immix_space = ImmixSpace::new( plan_args.get_space_args("immix_mature", true, false, VMRequest::discontiguous()), ImmixSpaceArgs { - // We need to unlog objects at tracing time since we currently clear all log bits during a major GC - unlog_object_when_traced: true, // In GenImmix, young objects are not allocated in ImmixSpace directly. #[cfg(feature = "vo_bit")] mixed_age: false, diff --git a/src/plan/generational/mod.rs b/src/plan/generational/mod.rs index 15b63abb33..7f80fd9400 100644 --- a/src/plan/generational/mod.rs +++ b/src/plan/generational/mod.rs @@ -45,6 +45,8 @@ pub const FULL_NURSERY_GC: bool = false; pub const GEN_CONSTRAINTS: PlanConstraints = PlanConstraints { moves_objects: true, needs_log_bit: ACTIVE_BARRIER.equals(BarrierSelector::ObjectBarrier), + unlog_allocated_object: true, + unlog_traced_object: true, barrier: ACTIVE_BARRIER, // We may trace duplicate edges in sticky immix (or any plan that uses object remembering barrier). See https://github.com/mmtk/mmtk-core/issues/743. may_trace_duplicate_edges: ACTIVE_BARRIER.equals(BarrierSelector::ObjectBarrier), diff --git a/src/plan/global.rs b/src/plan/global.rs index cd087bc20f..16b7b1f8c9 100644 --- a/src/plan/global.rs +++ b/src/plan/global.rs @@ -416,6 +416,8 @@ impl CreateSpecificPlanArgs<'_, VM> { zeroed, permission_exec, vmrequest, + unlog_allocated_object: self.constraints.unlog_allocated_object, + unlog_traced_object: self.constraints.unlog_traced_object, global_side_metadata_specs: self.global_side_metadata_specs.clone(), vm_map: self.global_args.vm_map, mmapper: self.global_args.mmapper, @@ -517,6 +519,28 @@ impl BasePlan { self.vm_space.release(); } + pub fn clear_side_log_bits(&self) { + #[cfg(feature = "code_space")] + self.code_space.clear_side_log_bits(); + #[cfg(feature = "code_space")] + self.code_lo_space.clear_side_log_bits(); + #[cfg(feature = "ro_space")] + self.ro_space.clear_side_log_bits(); + #[cfg(feature = "vm_space")] + self.vm_space.clear_side_log_bits(); + } + + pub fn set_side_log_bits(&self) { + #[cfg(feature = "code_space")] + self.code_space.set_side_log_bits(); + #[cfg(feature = "code_space")] + self.code_lo_space.set_side_log_bits(); + #[cfg(feature = "ro_space")] + self.ro_space.set_side_log_bits(); + #[cfg(feature = "vm_space")] + self.vm_space.set_side_log_bits(); + } + pub fn end_of_gc(&mut self, _tls: VMWorkerThread) { // Do nothing here. None of the spaces needs end_of_gc. } @@ -584,6 +608,7 @@ pub struct CommonPlan { impl CommonPlan { pub fn new(mut args: CreateSpecificPlanArgs) -> CommonPlan { + let needs_log_bit = args.constraints.needs_log_bit; CommonPlan { immortal: ImmortalSpace::new(args.get_space_args( "immortal", @@ -594,6 +619,7 @@ impl CommonPlan { los: LargeObjectSpace::new( args.get_space_args("los", true, false, VMRequest::discontiguous()), false, + needs_log_bit, ), nonmoving: Self::new_nonmoving_space(&mut args), base: BasePlan::new(args), @@ -621,6 +647,18 @@ impl CommonPlan { self.base.release(tls, full_heap) } + pub fn clear_side_log_bits(&self) { + self.immortal.clear_side_log_bits(); + self.los.clear_side_log_bits(); + self.base.clear_side_log_bits(); + } + + pub fn set_side_log_bits(&self) { + self.immortal.set_side_log_bits(); + self.los.set_side_log_bits(); + self.base.set_side_log_bits(); + } + pub fn end_of_gc(&mut self, tls: VMWorkerThread) { self.end_of_gc_nonmoving_space(); self.base.end_of_gc(tls); @@ -648,7 +686,6 @@ impl CommonPlan { NonMovingSpace::new( space_args, crate::policy::immix::ImmixSpaceArgs { - unlog_object_when_traced: false, #[cfg(feature = "vo_bit")] mixed_age: false, never_move_objects: true, diff --git a/src/plan/immix/global.rs b/src/plan/immix/global.rs index d8b5f40935..e488b42681 100644 --- a/src/plan/immix/global.rs +++ b/src/plan/immix/global.rs @@ -138,7 +138,6 @@ impl Immix { Self::new_with_args( plan_args, ImmixSpaceArgs { - unlog_object_when_traced: false, #[cfg(feature = "vo_bit")] mixed_age: false, never_move_objects: false, diff --git a/src/plan/pageprotect/global.rs b/src/plan/pageprotect/global.rs index 5d0d868f95..bd4c5288d4 100644 --- a/src/plan/pageprotect/global.rs +++ b/src/plan/pageprotect/global.rs @@ -110,6 +110,7 @@ impl PageProtect { space: LargeObjectSpace::new( plan_args.get_space_args("pageprotect", true, false, VMRequest::discontiguous()), true, + false, // PageProtect does not use log bit ), common: CommonPlan::new(plan_args), }; diff --git a/src/plan/plan_constraints.rs b/src/plan/plan_constraints.rs index 3110eb7538..f5faf96e3d 100644 --- a/src/plan/plan_constraints.rs +++ b/src/plan/plan_constraints.rs @@ -45,6 +45,10 @@ pub struct PlanConstraints { /// `MutatorConfig::prepare_func`). Those plans can set this to `false` so that the /// `PrepareMutator` work packets will not be created at all. pub needs_prepare_mutator: bool, + /// Should a policy unlog newly allocated objects? + pub unlog_allocated_object: bool, + /// Should a policy unlog traced objects? + pub unlog_traced_object: bool, } impl PlanConstraints { @@ -67,6 +71,8 @@ impl PlanConstraints { barrier: BarrierSelector::NoBarrier, // If we use mark sweep as non moving space, we need to prepare mutator. See [`common_prepare_func`]. needs_prepare_mutator: cfg!(feature = "marksweep_as_nonmoving"), + unlog_allocated_object: false, + unlog_traced_object: false, } } } diff --git a/src/plan/sticky/immix/global.rs b/src/plan/sticky/immix/global.rs index a06dee9816..4690ee05f0 100644 --- a/src/plan/sticky/immix/global.rs +++ b/src/plan/sticky/immix/global.rs @@ -46,6 +46,8 @@ pub const STICKY_IMMIX_CONSTRAINTS: PlanConstraints = PlanConstraints { barrier: crate::plan::BarrierSelector::ObjectBarrier, // We may trace duplicate edges in sticky immix (or any plan that uses object remembering barrier). See https://github.com/mmtk/mmtk-core/issues/743. may_trace_duplicate_edges: true, + unlog_allocated_object: true, + unlog_traced_object: true, ..immix::IMMIX_CONSTRAINTS }; @@ -122,6 +124,10 @@ impl Plan for StickyImmix { self.immix.common.los.prepare(false); } else { self.full_heap_gc_count.lock().unwrap().inc(); + if VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.is_on_side() { + self.immix.common.clear_side_log_bits(); + self.immix.immix_space.clear_side_log_bits(); + } self.immix.prepare(tls); } } @@ -325,10 +331,6 @@ impl StickyImmix { let immix = immix::Immix::new_with_args( plan_args, crate::policy::immix::ImmixSpaceArgs { - // Every object we trace in nursery GC becomes a mature object. - // Every object we trace in full heap GC is a mature object. Thus in both cases, - // they should be unlogged. - unlog_object_when_traced: true, // In StickyImmix, both young and old objects are allocated in the ImmixSpace. #[cfg(feature = "vo_bit")] mixed_age: true, diff --git a/src/policy/copyspace.rs b/src/policy/copyspace.rs index 7067f65d43..90685846a0 100644 --- a/src/policy/copyspace.rs +++ b/src/policy/copyspace.rs @@ -201,12 +201,6 @@ impl CopySpace { side_forwarding_status_table.bzero_metadata(start, size); } - if self.common.needs_log_bit { - if let MetadataSpec::OnSide(side) = *VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC { - side.bzero_metadata(start, size); - } - } - // Clear VO bits because all objects in the space are dead. #[cfg(feature = "vo_bit")] crate::util::metadata::vo_bit::bzero_vo_bit(start, size); @@ -218,6 +212,20 @@ impl CopySpace { self.from_space.store(false, Ordering::SeqCst); } + pub fn clear_side_log_bits(&self) { + let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); + for (start, size) in self.pr.iterate_allocated_regions() { + log_bit.bzero_metadata(start, size); + } + } + + pub fn set_side_log_bits(&self) { + let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); + for (start, size) in self.pr.iterate_allocated_regions() { + log_bit.bset_metadata(start, size); + } + } + fn is_from_space(&self) -> bool { self.from_space.load(Ordering::SeqCst) } diff --git a/src/policy/immix/immixspace.rs b/src/policy/immix/immixspace.rs index a8bcd54fda..306f6ead0b 100644 --- a/src/policy/immix/immixspace.rs +++ b/src/policy/immix/immixspace.rs @@ -60,12 +60,6 @@ pub struct ImmixSpace { /// Some arguments for Immix Space. pub struct ImmixSpaceArgs { - /// Mark an object as unlogged when we trace an object. - /// Normally we set the log bit when we copy an object with [`crate::util::copy::CopySemantics::PromoteToMature`]. - /// In sticky immix, we 'promote' an object to mature when we trace the object - /// (no matter we copy an object or not). So we have to use `PromoteToMature`, and instead - /// just set the log bit in the space when an object is traced. - pub unlog_object_when_traced: bool, /// Whether this ImmixSpace instance contains both young and old objects. /// This affects the updating of valid-object bits. If some lines or blocks of this ImmixSpace /// instance contain young objects, their VO bits need to be updated during this GC. Currently @@ -301,7 +295,7 @@ impl ImmixSpace { args: crate::policy::space::PlanCreateSpaceArgs, mut space_args: ImmixSpaceArgs, ) -> Self { - if space_args.unlog_object_when_traced { + if args.unlog_traced_object { assert!( args.constraints.needs_log_bit, "Invalid args when the plan does not use log bit" @@ -421,14 +415,6 @@ impl ImmixSpace { unimplemented!("cyclic mark bits is not supported at the moment"); } - if self.common.needs_log_bit { - if let MetadataSpec::OnSide(side) = *VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC { - for chunk in self.chunk_map.all_chunks() { - side.bzero_metadata(chunk.start(), Chunk::BYTES); - } - } - } - // Prepare defrag info if self.is_defrag_enabled() { self.defrag.prepare(self, plan_stats.unwrap()); @@ -529,6 +515,21 @@ impl ImmixSpace { did_defrag } + pub fn clear_side_log_bits(&self) { + let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); + for chunk in self.chunk_map.all_chunks() { + log_bit.bzero_metadata(chunk.start(), Chunk::BYTES); + } + } + + #[allow(dead_code)] + pub fn set_side_log_bits(&self) { + let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); + for chunk in self.chunk_map.all_chunks() { + log_bit.bset_metadata(chunk.start(), Chunk::BYTES); + } + } + /// Generate chunk sweep tasks fn generate_sweep_tasks(&self) -> Vec>> { self.defrag.mark_histograms.lock().clear(); @@ -728,7 +729,7 @@ impl ImmixSpace { } fn unlog_object_if_needed(&self, object: ObjectReference) { - if self.space_args.unlog_object_when_traced { + if self.common.unlog_traced_object { // Make sure the side metadata for the line can fit into one byte. For smaller line size, we should // use `mark_as_unlogged` instead to mark the bit. const_assert!( diff --git a/src/policy/immortalspace.rs b/src/policy/immortalspace.rs index c9eedd365f..4c57c4034b 100644 --- a/src/policy/immortalspace.rs +++ b/src/policy/immortalspace.rs @@ -56,7 +56,7 @@ impl SFT for ImmortalSpace { fn initialize_object_metadata(&self, object: ObjectReference, _alloc: bool) { self.mark_state .on_object_metadata_initialization::(object); - if self.common.needs_log_bit { + if self.common.unlog_allocated_object { VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.mark_as_unlogged::(object, Ordering::SeqCst); } #[cfg(feature = "vo_bit")] @@ -173,6 +173,20 @@ impl ImmortalSpace { self.mark_state.on_global_release::(); } + pub fn clear_side_log_bits(&self) { + let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); + for (start, size) in self.pr.iterate_allocated_regions() { + log_bit.bzero_metadata(start, size); + } + } + + pub fn set_side_log_bits(&self) { + let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); + for (start, size) in self.pr.iterate_allocated_regions() { + log_bit.bset_metadata(start, size); + } + } + pub fn trace_object( &self, queue: &mut Q, @@ -186,7 +200,7 @@ impl ImmortalSpace { ); if self.mark_state.test_and_mark::(object) { // Set the unlog bit if required - if self.common.needs_log_bit { + if self.common.unlog_traced_object { VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.store_atomic::( object, 1, diff --git a/src/policy/largeobjectspace.rs b/src/policy/largeobjectspace.rs index abe7976082..3ad03ebd9c 100644 --- a/src/policy/largeobjectspace.rs +++ b/src/policy/largeobjectspace.rs @@ -9,6 +9,7 @@ use crate::util::alloc::allocator::AllocationOptions; use crate::util::constants::BYTES_IN_PAGE; use crate::util::heap::{FreeListPageResource, PageResource}; use crate::util::metadata; +use crate::util::object_enum::ClosureObjectEnumerator; use crate::util::object_enum::ObjectEnumerator; use crate::util::opaque_pointer::*; use crate::util::treadmill::TreadMill; @@ -30,6 +31,7 @@ pub struct LargeObjectSpace { mark_state: u8, in_nursery_gc: bool, treadmill: TreadMill, + clear_log_bit_on_sweep: bool, } impl SFT for LargeObjectSpace { @@ -76,7 +78,7 @@ impl SFT for LargeObjectSpace { ); // If this object is freshly allocated, we do not set it as unlogged - if !alloc && self.common.needs_log_bit { + if !alloc && self.common.unlog_allocated_object { VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.mark_as_unlogged::(object, Ordering::SeqCst); } @@ -216,6 +218,7 @@ impl LargeObjectSpace { pub fn new( args: crate::policy::space::PlanCreateSpaceArgs, protect_memory_on_release: bool, + clear_log_bit_on_sweep: bool, ) -> Self { let is_discontiguous = args.vmrequest.is_discontiguous(); let vm_map = args.vm_map; @@ -240,9 +243,26 @@ impl LargeObjectSpace { mark_state: 0, in_nursery_gc: false, treadmill: TreadMill::new(), + clear_log_bit_on_sweep, } } + pub fn clear_side_log_bits(&self) { + let mut enumator = ClosureObjectEnumerator::<_, VM>::new(|object| { + VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.clear::(object, Ordering::SeqCst); + }); + self.treadmill.enumerate_objects(&mut enumator); + } + + pub fn set_side_log_bits(&self) { + debug_assert!(self.treadmill.is_from_space_empty()); + debug_assert!(self.treadmill.is_nursery_empty()); + let mut enumator = ClosureObjectEnumerator::<_, VM>::new(|object| { + VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.mark_as_unlogged::(object, Ordering::SeqCst); + }); + self.treadmill.enumerate_objects(&mut enumator); + } + pub fn prepare(&mut self, full_heap: bool) { if full_heap { debug_assert!(self.treadmill.is_from_space_empty()); @@ -288,7 +308,7 @@ impl LargeObjectSpace { // We just moved the object out of the logical nursery, mark it as unlogged. // We also unlog mature objects as their unlog bit may have been unset before the // full-heap GC - if self.common.needs_log_bit { + if self.common.unlog_traced_object { VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC .mark_as_unlogged::(object, Ordering::SeqCst); } @@ -308,7 +328,7 @@ impl LargeObjectSpace { #[cfg(feature = "vo_bit")] crate::util::metadata::vo_bit::unset_vo_bit(object); // Clear log bits for dead objects to prevent a new nursery object having the unlog bit set - if self.common.needs_log_bit { + if self.clear_log_bit_on_sweep { VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.clear::(object, Ordering::SeqCst); } self.pr diff --git a/src/policy/marksweepspace/native_ms/global.rs b/src/policy/marksweepspace/native_ms/global.rs index 1dc87cd04c..d7d85a67bd 100644 --- a/src/policy/marksweepspace/native_ms/global.rs +++ b/src/policy/marksweepspace/native_ms/global.rs @@ -406,15 +406,7 @@ impl MarkSweepSpace { self.chunk_map.set_allocated(block.chunk(), true); } - pub fn prepare(&mut self, full_heap: bool) { - if self.common.needs_log_bit && full_heap { - if let MetadataSpec::OnSide(side) = *VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC { - for chunk in self.chunk_map.all_chunks() { - side.bzero_metadata(chunk.start(), Chunk::BYTES); - } - } - } - + pub fn prepare(&mut self, _full_heap: bool) { #[cfg(debug_assertions)] self.abandoned_in_gc.lock().unwrap().assert_empty(); @@ -427,6 +419,20 @@ impl MarkSweepSpace { .bulk_add(work_packets); } + pub fn clear_side_log_bits(&self) { + let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); + for chunk in self.chunk_map.all_chunks() { + log_bit.bzero_metadata(chunk.start(), Chunk::BYTES); + } + } + + pub fn set_side_log_bits(&self) { + let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); + for chunk in self.chunk_map.all_chunks() { + log_bit.bset_metadata(chunk.start(), Chunk::BYTES); + } + } + pub fn release(&mut self) { let num_mutators = VM::VMActivePlan::number_of_mutators(); // all ReleaseMutator work packets plus the ReleaseMarkSweepSpace packet diff --git a/src/policy/space.rs b/src/policy/space.rs index e44874fe5b..2f1a787dfd 100644 --- a/src/policy/space.rs +++ b/src/policy/space.rs @@ -524,6 +524,8 @@ pub struct CommonSpace { /// This field equals to needs_log_bit in the plan constraints. // TODO: This should be a constant for performance. pub needs_log_bit: bool, + pub unlog_allocated_object: bool, + pub unlog_traced_object: bool, /// A lock used during acquire() to make sure only one thread can allocate. pub acquire_lock: Mutex<()>, @@ -548,6 +550,8 @@ pub struct PlanCreateSpaceArgs<'a, VM: VMBinding> { pub name: &'static str, pub zeroed: bool, pub permission_exec: bool, + pub unlog_allocated_object: bool, + pub unlog_traced_object: bool, pub vmrequest: VMRequest, pub global_side_metadata_specs: Vec, pub vm_map: &'static dyn VMMap, @@ -594,6 +598,8 @@ impl CommonSpace { vm_map: args.plan_args.vm_map, mmapper: args.plan_args.mmapper, needs_log_bit: args.plan_args.constraints.needs_log_bit, + unlog_allocated_object: args.plan_args.unlog_allocated_object, + unlog_traced_object: args.plan_args.unlog_traced_object, gc_trigger: args.plan_args.gc_trigger, metadata: SideMetadataContext { global: args.plan_args.global_side_metadata_specs, diff --git a/src/policy/vmspace.rs b/src/policy/vmspace.rs index ab1101aaf5..b08d6a7a21 100644 --- a/src/policy/vmspace.rs +++ b/src/policy/vmspace.rs @@ -61,7 +61,7 @@ impl SFT for VMSpace { fn initialize_object_metadata(&self, object: ObjectReference, _alloc: bool) { self.mark_state .on_object_metadata_initialization::(object); - if self.common.needs_log_bit { + if self.common.unlog_allocated_object { VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.mark_as_unlogged::(object, Ordering::SeqCst); } #[cfg(feature = "vo_bit")] @@ -271,6 +271,22 @@ impl VMSpace { self.mark_state.on_global_release::(); } + pub fn clear_side_log_bits(&self) { + let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); + let external_pages = self.pr.get_external_pages(); + for ep in external_pages.iter() { + log_bit.bzero_metadata(ep.start, ep.end - ep.start); + } + } + + pub fn set_side_log_bits(&self) { + let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); + let external_pages = self.pr.get_external_pages(); + for ep in external_pages.iter() { + log_bit.bset_metadata(ep.start, ep.end - ep.start); + } + } + pub fn trace_object( &self, queue: &mut Q, @@ -287,7 +303,7 @@ impl VMSpace { // Flip the per-object unlogged bits to "unlogged" state for objects inside the // bootimage #[cfg(feature = "set_unlog_bits_vm_space")] - if self.common.needs_log_bit { + if self.common.unlog_traced_object { VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.store_atomic::( object, 1, diff --git a/src/util/copy/mod.rs b/src/util/copy/mod.rs index aaea3b425a..b656cfd03e 100644 --- a/src/util/copy/mod.rs +++ b/src/util/copy/mod.rs @@ -120,7 +120,7 @@ impl GCWorkerCopyContext { )); } // If we are copying objects in mature space, we would need to mark the object as mature. - if semantics.is_mature() && self.config.constraints.needs_log_bit { + if semantics.is_mature() && self.config.constraints.unlog_traced_object { // If the plan uses unlogged bit, we set the unlogged bit (the object is unlogged/mature) VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC .mark_byte_as_unlogged::(object, Ordering::Relaxed); From 9c7695cc90a88ccec63a66584f416759d9e1f901 Mon Sep 17 00:00:00 2001 From: Yi Lin Date: Tue, 12 Aug 2025 00:39:57 +0000 Subject: [PATCH 02/12] Check CI runner --- .github/workflows/binding-tests-openjdk.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/binding-tests-openjdk.yml b/.github/workflows/binding-tests-openjdk.yml index 194d6a3c3c..f3ae5c2bdd 100644 --- a/.github/workflows/binding-tests-openjdk.yml +++ b/.github/workflows/binding-tests-openjdk.yml @@ -45,3 +45,6 @@ jobs: cd mmtk-openjdk export RUST_BACKTRACE=1 ./.github/scripts/${{ inputs.test-script }} + - name: Setup tmate session + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3 From 6149721e29678bbd164b461964c4a5d81d7c57bf Mon Sep 17 00:00:00 2001 From: Yi Lin Date: Wed, 13 Aug 2025 01:47:04 +0000 Subject: [PATCH 03/12] Remove unlog_allocated/traced_object from PlanConstraints. Move them to args for creating spaces. --- src/plan/compressor/global.rs | 2 +- src/plan/generational/copying/global.rs | 4 +- src/plan/generational/global.rs | 2 +- src/plan/generational/immix/global.rs | 8 +- src/plan/generational/mod.rs | 3 +- src/plan/global.rs | 132 +++++++++++++++++++----- src/plan/immix/global.rs | 17 ++- src/plan/markcompact/global.rs | 2 +- src/plan/marksweep/global.rs | 2 +- src/plan/nogc/global.rs | 6 +- src/plan/pageprotect/global.rs | 7 +- src/plan/plan_constraints.rs | 9 +- src/plan/semispace/global.rs | 14 ++- src/plan/sticky/immix/global.rs | 4 +- src/policy/copy_context.rs | 2 +- src/policy/copyspace.rs | 9 +- src/policy/immix/immixspace.rs | 6 +- src/util/copy/mod.rs | 7 -- 18 files changed, 173 insertions(+), 63 deletions(-) diff --git a/src/plan/compressor/global.rs b/src/plan/compressor/global.rs index 882ca51418..62a2a84657 100644 --- a/src/plan/compressor/global.rs +++ b/src/plan/compressor/global.rs @@ -183,7 +183,7 @@ impl Compressor { }; let res = Compressor { - compressor_space: CompressorSpace::new(plan_args.get_space_args( + compressor_space: CompressorSpace::new(plan_args.get_normal_space_args( "compressor_space", true, false, diff --git a/src/plan/generational/copying/global.rs b/src/plan/generational/copying/global.rs index b701f8e07d..66540ffb97 100644 --- a/src/plan/generational/copying/global.rs +++ b/src/plan/generational/copying/global.rs @@ -212,11 +212,11 @@ impl GenCopy { }; let copyspace0 = CopySpace::new( - plan_args.get_space_args("copyspace0", true, false, VMRequest::discontiguous()), + plan_args.get_mature_space_args("copyspace0", true, false, VMRequest::discontiguous()), false, ); let copyspace1 = CopySpace::new( - plan_args.get_space_args("copyspace1", true, false, VMRequest::discontiguous()), + plan_args.get_mature_space_args("copyspace1", true, false, VMRequest::discontiguous()), true, ); diff --git a/src/plan/generational/global.rs b/src/plan/generational/global.rs index 9617bcd1f4..61fe31b836 100644 --- a/src/plan/generational/global.rs +++ b/src/plan/generational/global.rs @@ -41,7 +41,7 @@ pub struct CommonGenPlan { impl CommonGenPlan { pub fn new(mut args: CreateSpecificPlanArgs) -> Self { let nursery = CopySpace::new( - args.get_space_args("nursery", true, false, VMRequest::discontiguous()), + args.get_nursery_space_args("nursery", true, false, VMRequest::discontiguous()), true, ); let full_heap_gc_count = args diff --git a/src/plan/generational/immix/global.rs b/src/plan/generational/immix/global.rs index ba1dc8a9ca..41e7a70768 100644 --- a/src/plan/generational/immix/global.rs +++ b/src/plan/generational/immix/global.rs @@ -250,10 +250,14 @@ impl GenImmix { crate::plan::generational::new_generational_global_metadata_specs::(), }; let immix_space = ImmixSpace::new( - plan_args.get_space_args("immix_mature", true, false, VMRequest::discontiguous()), + plan_args.get_mature_space_args( + "immix_mature", + true, + false, + VMRequest::discontiguous(), + ), ImmixSpaceArgs { // In GenImmix, young objects are not allocated in ImmixSpace directly. - #[cfg(feature = "vo_bit")] mixed_age: false, never_move_objects: false, }, diff --git a/src/plan/generational/mod.rs b/src/plan/generational/mod.rs index 7f80fd9400..dc5c747063 100644 --- a/src/plan/generational/mod.rs +++ b/src/plan/generational/mod.rs @@ -45,8 +45,7 @@ pub const FULL_NURSERY_GC: bool = false; pub const GEN_CONSTRAINTS: PlanConstraints = PlanConstraints { moves_objects: true, needs_log_bit: ACTIVE_BARRIER.equals(BarrierSelector::ObjectBarrier), - unlog_allocated_object: true, - unlog_traced_object: true, + generational: true, barrier: ACTIVE_BARRIER, // We may trace duplicate edges in sticky immix (or any plan that uses object remembering barrier). See https://github.com/mmtk/mmtk-core/issues/743. may_trace_duplicate_edges: ACTIVE_BARRIER.equals(BarrierSelector::ObjectBarrier), diff --git a/src/plan/global.rs b/src/plan/global.rs index 16b7b1f8c9..9f4e1bd8a0 100644 --- a/src/plan/global.rs +++ b/src/plan/global.rs @@ -404,11 +404,13 @@ pub struct CreateSpecificPlanArgs<'a, VM: VMBinding> { impl CreateSpecificPlanArgs<'_, VM> { /// Get a PlanCreateSpaceArgs that can be used to create a space - pub fn get_space_args( + pub fn _get_space_args( &mut self, name: &'static str, zeroed: bool, permission_exec: bool, + unlog_allocated_object: bool, + unlog_traced_object: bool, vmrequest: VMRequest, ) -> PlanCreateSpaceArgs { PlanCreateSpaceArgs { @@ -416,8 +418,8 @@ impl CreateSpecificPlanArgs<'_, VM> { zeroed, permission_exec, vmrequest, - unlog_allocated_object: self.constraints.unlog_allocated_object, - unlog_traced_object: self.constraints.unlog_traced_object, + unlog_allocated_object, + unlog_traced_object, global_side_metadata_specs: self.global_side_metadata_specs.clone(), vm_map: self.global_args.vm_map, mmapper: self.global_args.mmapper, @@ -429,39 +431,121 @@ impl CreateSpecificPlanArgs<'_, VM> { global_state: self.global_args.state.clone(), } } + + // The following are some convenience methods for common presets. + // These are not an exhaustive list -- it is just common presets that are used by most plans. + + /// Get a preset for a nursery space (where young objects are located). + pub fn get_nursery_space_args( + &mut self, + name: &'static str, + zeroed: bool, + permission_exec: bool, + vmrequest: VMRequest, + ) -> PlanCreateSpaceArgs { + // Objects are allocatd as young, and when traced, they stay young. If they are copied out of the nursery space, they will be moved to a mature space, + // and log bits will be set in that case by the mature space. + self._get_space_args(name, zeroed, permission_exec, false, false, vmrequest) + } + + /// Get a preset for a mature space (where mature objects are located). + pub fn get_mature_space_args( + &mut self, + name: &'static str, + zeroed: bool, + permission_exec: bool, + vmrequest: VMRequest, + ) -> PlanCreateSpaceArgs { + // Objects are allocated as mature (pre-tenured), and when traced, they stay mature. + // If an object gets copied into a mature space, the object is also mature, + self._get_space_args(name, zeroed, permission_exec, true, true, vmrequest) + } + + // Get a preset for a mixed age space (where both young and mature objects are located). + pub fn get_mixed_age_space_args( + &mut self, + name: &'static str, + zeroed: bool, + permission_exec: bool, + vmrequest: VMRequest, + ) -> PlanCreateSpaceArgs { + // Objects are allocated as young, and when traced, they become mature objects. + self._get_space_args(name, zeroed, permission_exec, false, true, vmrequest) + } + + /// Get a preset for spaces in a non-generational plan. + pub fn get_normal_space_args( + &mut self, + name: &'static str, + zeroed: bool, + permission_exec: bool, + vmrequest: VMRequest, + ) -> PlanCreateSpaceArgs { + // Non generational plan: we do not use any of the flags about log bits. + self._get_space_args(name, zeroed, permission_exec, false, false, vmrequest) + } + + /// Get a preset for spaces in [`crate::plan::global::CommonPlan`]. + /// Spaces like LOS which may include both young and mature objects should not use this method. + pub fn get_common_space_args( + &mut self, + generational: bool, + name: &'static str, + ) -> PlanCreateSpaceArgs { + self.get_base_space_args( + generational, + name, + false, // Common spaces are not executable. + ) + } + + /// Get a preset for spaces in [`crate::plan::global::BasePlan`]. + pub fn get_base_space_args( + &mut self, + generational: bool, + name: &'static str, + permission_exec: bool, + ) -> PlanCreateSpaceArgs { + if generational { + // In generational plans, common/base spaces behave like a mature space: + // * the objects in these spaces are not traced in a nursery GC + // * the log bits for the objects are maintained exactly the same as a mature space. + // Thus we consider them as mature spaces. + self.get_mature_space_args(name, true, permission_exec, VMRequest::discontiguous()) + } else { + self.get_normal_space_args(name, true, permission_exec, VMRequest::discontiguous()) + } + } } impl BasePlan { #[allow(unused_mut)] // 'args' only needs to be mutable for certain features pub fn new(mut args: CreateSpecificPlanArgs) -> BasePlan { + let _generational = args.constraints.generational; BasePlan { #[cfg(feature = "code_space")] - code_space: ImmortalSpace::new(args.get_space_args( + code_space: ImmortalSpace::new(args.get_base_space_args( + _generational, "code_space", true, - true, - VMRequest::discontiguous(), )), #[cfg(feature = "code_space")] - code_lo_space: ImmortalSpace::new(args.get_space_args( + code_lo_space: ImmortalSpace::new(args.get_base_space_args( + _generational, "code_lo_space", true, - true, - VMRequest::discontiguous(), )), #[cfg(feature = "ro_space")] - ro_space: ImmortalSpace::new(args.get_space_args( + ro_space: ImmortalSpace::new(args.get_base_space_args( + _generational, "ro_space", - true, false, - VMRequest::discontiguous(), )), #[cfg(feature = "vm_space")] - vm_space: VMSpace::new(args.get_space_args( + vm_space: VMSpace::new(args.get_base_space_args( + _generational, "vm_space", - false, false, // it doesn't matter -- we are not mmapping for VM space. - VMRequest::discontiguous(), )), global_state: args.global_args.state.clone(), @@ -609,15 +693,16 @@ pub struct CommonPlan { impl CommonPlan { pub fn new(mut args: CreateSpecificPlanArgs) -> CommonPlan { let needs_log_bit = args.constraints.needs_log_bit; + let generational = args.constraints.generational; CommonPlan { - immortal: ImmortalSpace::new(args.get_space_args( - "immortal", - true, - false, - VMRequest::discontiguous(), - )), + immortal: ImmortalSpace::new(args.get_common_space_args(generational, "immortal")), los: LargeObjectSpace::new( - args.get_space_args("los", true, false, VMRequest::discontiguous()), + // LOS is a bit special, as it is a mixed age space. It has a logical nursery. + if generational { + args.get_mixed_age_space_args("los", true, false, VMRequest::discontiguous()) + } else { + args.get_normal_space_args("los", true, false, VMRequest::discontiguous()) + }, false, needs_log_bit, ), @@ -677,7 +762,7 @@ impl CommonPlan { } fn new_nonmoving_space(args: &mut CreateSpecificPlanArgs) -> NonMovingSpace { - let space_args = args.get_space_args("nonmoving", true, false, VMRequest::discontiguous()); + let space_args = args.get_common_space_args(args.constraints.generational, "nonmoving"); cfg_if::cfg_if! { if #[cfg(any(feature = "immortal_as_nonmoving", feature = "marksweep_as_nonmoving"))] { NonMovingSpace::new(space_args) @@ -686,7 +771,6 @@ impl CommonPlan { NonMovingSpace::new( space_args, crate::policy::immix::ImmixSpaceArgs { - #[cfg(feature = "vo_bit")] mixed_age: false, never_move_objects: true, }, diff --git a/src/plan/immix/global.rs b/src/plan/immix/global.rs index e488b42681..136db58c43 100644 --- a/src/plan/immix/global.rs +++ b/src/plan/immix/global.rs @@ -138,7 +138,6 @@ impl Immix { Self::new_with_args( plan_args, ImmixSpaceArgs { - #[cfg(feature = "vo_bit")] mixed_age: false, never_move_objects: false, }, @@ -151,7 +150,21 @@ impl Immix { ) -> Self { let immix = Immix { immix_space: ImmixSpace::new( - plan_args.get_space_args("immix", true, false, VMRequest::discontiguous()), + if space_args.mixed_age { + plan_args.get_mixed_age_space_args( + "immix", + true, + false, + VMRequest::discontiguous(), + ) + } else { + plan_args.get_normal_space_args( + "immix", + true, + false, + VMRequest::discontiguous(), + ) + }, space_args, ), common: CommonPlan::new(plan_args), diff --git a/src/plan/markcompact/global.rs b/src/plan/markcompact/global.rs index f776840bfd..3be0903117 100644 --- a/src/plan/markcompact/global.rs +++ b/src/plan/markcompact/global.rs @@ -198,7 +198,7 @@ impl MarkCompact { global_side_metadata_specs, }; - let mc_space = MarkCompactSpace::new(plan_args.get_space_args( + let mc_space = MarkCompactSpace::new(plan_args.get_normal_space_args( "mc", true, false, diff --git a/src/plan/marksweep/global.rs b/src/plan/marksweep/global.rs index f6d4b9449b..239c1a5102 100644 --- a/src/plan/marksweep/global.rs +++ b/src/plan/marksweep/global.rs @@ -112,7 +112,7 @@ impl MarkSweep { }; let res = MarkSweep { - ms: MarkSweepSpace::new(plan_args.get_space_args( + ms: MarkSweepSpace::new(plan_args.get_normal_space_args( "ms", true, false, diff --git a/src/plan/nogc/global.rs b/src/plan/nogc/global.rs index d6e6306fef..199b9c6185 100644 --- a/src/plan/nogc/global.rs +++ b/src/plan/nogc/global.rs @@ -99,19 +99,19 @@ impl NoGC { }; let res = NoGC { - nogc_space: NoGCImmortalSpace::new(plan_args.get_space_args( + nogc_space: NoGCImmortalSpace::new(plan_args.get_normal_space_args( "nogc_space", cfg!(not(feature = "nogc_no_zeroing")), false, VMRequest::discontiguous(), )), - immortal: ImmortalSpace::new(plan_args.get_space_args( + immortal: ImmortalSpace::new(plan_args.get_normal_space_args( "immortal", true, false, VMRequest::discontiguous(), )), - los: ImmortalSpace::new(plan_args.get_space_args( + los: ImmortalSpace::new(plan_args.get_normal_space_args( "los", true, false, diff --git a/src/plan/pageprotect/global.rs b/src/plan/pageprotect/global.rs index bd4c5288d4..94a909c9e4 100644 --- a/src/plan/pageprotect/global.rs +++ b/src/plan/pageprotect/global.rs @@ -108,7 +108,12 @@ impl PageProtect { let ret = PageProtect { space: LargeObjectSpace::new( - plan_args.get_space_args("pageprotect", true, false, VMRequest::discontiguous()), + plan_args.get_normal_space_args( + "pageprotect", + true, + false, + VMRequest::discontiguous(), + ), true, false, // PageProtect does not use log bit ), diff --git a/src/plan/plan_constraints.rs b/src/plan/plan_constraints.rs index f5faf96e3d..f86de5e05f 100644 --- a/src/plan/plan_constraints.rs +++ b/src/plan/plan_constraints.rs @@ -45,10 +45,8 @@ pub struct PlanConstraints { /// `MutatorConfig::prepare_func`). Those plans can set this to `false` so that the /// `PrepareMutator` work packets will not be created at all. pub needs_prepare_mutator: bool, - /// Should a policy unlog newly allocated objects? - pub unlog_allocated_object: bool, - /// Should a policy unlog traced objects? - pub unlog_traced_object: bool, + /// Is this plan generational? + pub generational: bool, } impl PlanConstraints { @@ -71,8 +69,7 @@ impl PlanConstraints { barrier: BarrierSelector::NoBarrier, // If we use mark sweep as non moving space, we need to prepare mutator. See [`common_prepare_func`]. needs_prepare_mutator: cfg!(feature = "marksweep_as_nonmoving"), - unlog_allocated_object: false, - unlog_traced_object: false, + generational: false, } } } diff --git a/src/plan/semispace/global.rs b/src/plan/semispace/global.rs index 0205c7a77f..98fed5fe46 100644 --- a/src/plan/semispace/global.rs +++ b/src/plan/semispace/global.rs @@ -146,11 +146,21 @@ impl SemiSpace { let res = SemiSpace { hi: AtomicBool::new(false), copyspace0: CopySpace::new( - plan_args.get_space_args("copyspace0", true, false, VMRequest::discontiguous()), + plan_args.get_normal_space_args( + "copyspace0", + true, + false, + VMRequest::discontiguous(), + ), false, ), copyspace1: CopySpace::new( - plan_args.get_space_args("copyspace1", true, false, VMRequest::discontiguous()), + plan_args.get_normal_space_args( + "copyspace1", + true, + false, + VMRequest::discontiguous(), + ), true, ), common: CommonPlan::new(plan_args), diff --git a/src/plan/sticky/immix/global.rs b/src/plan/sticky/immix/global.rs index 4690ee05f0..f6cb9d4567 100644 --- a/src/plan/sticky/immix/global.rs +++ b/src/plan/sticky/immix/global.rs @@ -46,8 +46,7 @@ pub const STICKY_IMMIX_CONSTRAINTS: PlanConstraints = PlanConstraints { barrier: crate::plan::BarrierSelector::ObjectBarrier, // We may trace duplicate edges in sticky immix (or any plan that uses object remembering barrier). See https://github.com/mmtk/mmtk-core/issues/743. may_trace_duplicate_edges: true, - unlog_allocated_object: true, - unlog_traced_object: true, + generational: true, ..immix::IMMIX_CONSTRAINTS }; @@ -332,7 +331,6 @@ impl StickyImmix { plan_args, crate::policy::immix::ImmixSpaceArgs { // In StickyImmix, both young and old objects are allocated in the ImmixSpace. - #[cfg(feature = "vo_bit")] mixed_age: true, never_move_objects: false, }, diff --git a/src/policy/copy_context.rs b/src/policy/copy_context.rs index 0954834874..d25a524b9e 100644 --- a/src/policy/copy_context.rs +++ b/src/policy/copy_context.rs @@ -22,5 +22,5 @@ pub trait PolicyCopyContext: 'static + Send { align: usize, offset: usize, ) -> Address; - fn post_copy(&mut self, _obj: ObjectReference, _bytes: usize) {} + fn post_copy(&mut self, _obj: ObjectReference, _bytes: usize); } diff --git a/src/policy/copyspace.rs b/src/policy/copyspace.rs index 90685846a0..11e331dffb 100644 --- a/src/policy/copyspace.rs +++ b/src/policy/copyspace.rs @@ -344,6 +344,13 @@ impl PolicyCopyContext for CopySpaceCopyContext { ) -> Address { self.copy_allocator.alloc(bytes, align, offset) } + + fn post_copy(&mut self, obj: ObjectReference, _bytes: usize) { + if self.copy_allocator.get_space().common().unlog_traced_object { + VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC + .mark_byte_as_unlogged::(obj, Ordering::Relaxed); + } + } } impl CopySpaceCopyContext { @@ -356,9 +363,7 @@ impl CopySpaceCopyContext { copy_allocator: BumpAllocator::new(tls.0, tospace, context), } } -} -impl CopySpaceCopyContext { pub fn rebind(&mut self, space: &CopySpace) { self.copy_allocator .rebind(unsafe { &*{ space as *const _ } }); diff --git a/src/policy/immix/immixspace.rs b/src/policy/immix/immixspace.rs index 306f6ead0b..58dc969fac 100644 --- a/src/policy/immix/immixspace.rs +++ b/src/policy/immix/immixspace.rs @@ -65,8 +65,6 @@ pub struct ImmixSpaceArgs { /// instance contain young objects, their VO bits need to be updated during this GC. Currently /// only StickyImmix is affected. GenImmix allocates young objects in a separete CopySpace /// nursery and its VO bits can be cleared in bulk. - // Currently only used when "vo_bit" is enabled. Using #[cfg(...)] to eliminate dead code warning. - #[cfg(feature = "vo_bit")] pub mixed_age: bool, /// Disable copying for this Immix space. pub never_move_objects: bool, @@ -878,6 +876,10 @@ impl ImmixSpace { if !super::MARK_LINE_AT_SCAN_TIME { self.mark_lines(object); } + if self.common.unlog_traced_object { + VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC + .mark_byte_as_unlogged::(object, Ordering::Relaxed); + } } pub(crate) fn prefer_copy_on_nursery_gc(&self) -> bool { diff --git a/src/util/copy/mod.rs b/src/util/copy/mod.rs index b656cfd03e..9b070cc01c 100644 --- a/src/util/copy/mod.rs +++ b/src/util/copy/mod.rs @@ -14,7 +14,6 @@ use crate::util::{Address, ObjectReference}; use crate::vm::ObjectModel; use crate::vm::VMBinding; use crate::MMTK; -use std::sync::atomic::Ordering; use enum_map::Enum; use enum_map::EnumMap; @@ -119,12 +118,6 @@ impl GCWorkerCopyContext { object )); } - // If we are copying objects in mature space, we would need to mark the object as mature. - if semantics.is_mature() && self.config.constraints.unlog_traced_object { - // If the plan uses unlogged bit, we set the unlogged bit (the object is unlogged/mature) - VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC - .mark_byte_as_unlogged::(object, Ordering::Relaxed); - } // Policy specific post copy. match self.config.copy_mapping[semantics] { CopySelector::CopySpace(index) => { From 67db9843b2c18a1a8280d65058d8dd1e10976983 Mon Sep 17 00:00:00 2001 From: Yi Lin Date: Wed, 13 Aug 2025 01:55:11 +0000 Subject: [PATCH 04/12] Fix rayon-core version for MSRV --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index f96df1ec29..5b5c0685bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,7 @@ portable-atomic = "1.4.3" probe = "0.5" regex = "1.7.0" rustversion = "1.0" +rayon-core = "=1.12.1" # We can remove this dependency when we use MSRV 1.80+ spin = "0.9.5" static_assertions = "1.1.0" strum = "0.27.1" From 19a44e47ddd69816dd1598a05651137099e56fef Mon Sep 17 00:00:00 2001 From: Yi Lin Date: Wed, 13 Aug 2025 03:02:50 +0000 Subject: [PATCH 05/12] Fix tutorial code --- docs/userguide/src/tutorial/code/mygc_semispace/global.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/userguide/src/tutorial/code/mygc_semispace/global.rs b/docs/userguide/src/tutorial/code/mygc_semispace/global.rs index 51f9f9361b..aefd86cebe 100644 --- a/docs/userguide/src/tutorial/code/mygc_semispace/global.rs +++ b/docs/userguide/src/tutorial/code/mygc_semispace/global.rs @@ -181,9 +181,9 @@ impl MyGC { let res = MyGC { hi: AtomicBool::new(false), // ANCHOR: copyspace_new - copyspace0: CopySpace::new(plan_args.get_space_args("copyspace0", true, false, VMRequest::discontiguous()), false), + copyspace0: CopySpace::new(plan_args.get_normal_space_args("copyspace0", true, false, VMRequest::discontiguous()), false), // ANCHOR_END: copyspace_new - copyspace1: CopySpace::new(plan_args.get_space_args("copyspace1", true, false, VMRequest::discontiguous()), true), + copyspace1: CopySpace::new(plan_args.get_normal_space_args("copyspace1", true, false, VMRequest::discontiguous()), true), common: CommonPlan::new(plan_args), }; From 54ab35b41fdf8b9975dcb8ceca58498ed0ef74e8 Mon Sep 17 00:00:00 2001 From: Yi Lin Date: Wed, 13 Aug 2025 03:53:28 +0000 Subject: [PATCH 06/12] Revert "Check CI runner" This reverts commit 9c7695cc90a88ccec63a66584f416759d9e1f901. --- .github/workflows/binding-tests-openjdk.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/binding-tests-openjdk.yml b/.github/workflows/binding-tests-openjdk.yml index f3ae5c2bdd..194d6a3c3c 100644 --- a/.github/workflows/binding-tests-openjdk.yml +++ b/.github/workflows/binding-tests-openjdk.yml @@ -45,6 +45,3 @@ jobs: cd mmtk-openjdk export RUST_BACKTRACE=1 ./.github/scripts/${{ inputs.test-script }} - - name: Setup tmate session - if: ${{ failure() }} - uses: mxschmitt/action-tmate@v3 From a1e71be170740cbf78773d45a6c881b8d08b2af5 Mon Sep 17 00:00:00 2001 From: Yi Lin Date: Thu, 14 Aug 2025 00:29:09 +0000 Subject: [PATCH 07/12] Add clear/set_side_log_bits to trait Space --- src/policy/compressor/compressorspace.rs | 8 ++++ src/policy/copyspace.rs | 28 ++++++------- src/policy/immix/immixspace.rs | 39 +++++++++++-------- src/policy/immortalspace.rs | 28 ++++++------- src/policy/largeobjectspace.rs | 32 +++++++-------- src/policy/lockfreeimmortalspace.rs | 8 ++++ src/policy/markcompactspace.rs | 8 ++++ src/policy/marksweepspace/malloc_ms/global.rs | 8 ++++ src/policy/marksweepspace/native_ms/global.rs | 28 ++++++------- src/policy/space.rs | 8 ++++ src/policy/vmspace.rs | 32 +++++++-------- 11 files changed, 137 insertions(+), 90 deletions(-) diff --git a/src/policy/compressor/compressorspace.rs b/src/policy/compressor/compressorspace.rs index 4b7be4fdd1..0a2226c243 100644 --- a/src/policy/compressor/compressorspace.rs +++ b/src/policy/compressor/compressorspace.rs @@ -146,6 +146,14 @@ impl Space for CompressorSpace { fn enumerate_objects(&self, enumerator: &mut dyn ObjectEnumerator) { object_enum::enumerate_blocks_from_monotonic_page_resource(enumerator, &self.pr); } + + fn clear_side_log_bits(&self) { + unimplemented!() + } + + fn set_side_log_bits(&self) { + unimplemented!() + } } impl crate::policy::gc_work::PolicyTraceObject for CompressorSpace { diff --git a/src/policy/copyspace.rs b/src/policy/copyspace.rs index 11e331dffb..e34c799c7e 100644 --- a/src/policy/copyspace.rs +++ b/src/policy/copyspace.rs @@ -143,6 +143,20 @@ impl Space for CopySpace { fn enumerate_objects(&self, enumerator: &mut dyn ObjectEnumerator) { object_enum::enumerate_blocks_from_monotonic_page_resource(enumerator, &self.pr); } + + fn clear_side_log_bits(&self) { + let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); + for (start, size) in self.pr.iterate_allocated_regions() { + log_bit.bzero_metadata(start, size); + } + } + + fn set_side_log_bits(&self) { + let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); + for (start, size) in self.pr.iterate_allocated_regions() { + log_bit.bset_metadata(start, size); + } + } } impl crate::policy::gc_work::PolicyTraceObject for CopySpace { @@ -212,20 +226,6 @@ impl CopySpace { self.from_space.store(false, Ordering::SeqCst); } - pub fn clear_side_log_bits(&self) { - let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); - for (start, size) in self.pr.iterate_allocated_regions() { - log_bit.bzero_metadata(start, size); - } - } - - pub fn set_side_log_bits(&self) { - let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); - for (start, size) in self.pr.iterate_allocated_regions() { - log_bit.bset_metadata(start, size); - } - } - fn is_from_space(&self) -> bool { self.from_space.load(Ordering::SeqCst) } diff --git a/src/policy/immix/immixspace.rs b/src/policy/immix/immixspace.rs index 58dc969fac..6a5c128882 100644 --- a/src/policy/immix/immixspace.rs +++ b/src/policy/immix/immixspace.rs @@ -195,6 +195,20 @@ impl Space for ImmixSpace { fn enumerate_objects(&self, enumerator: &mut dyn ObjectEnumerator) { object_enum::enumerate_blocks_from_chunk_map::(enumerator, &self.chunk_map); } + + fn clear_side_log_bits(&self) { + let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); + for chunk in self.chunk_map.all_chunks() { + log_bit.bzero_metadata(chunk.start(), Chunk::BYTES); + } + } + + fn set_side_log_bits(&self) { + let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); + for chunk in self.chunk_map.all_chunks() { + log_bit.bset_metadata(chunk.start(), Chunk::BYTES); + } + } } impl crate::policy::gc_work::PolicyTraceObject for ImmixSpace { @@ -513,21 +527,6 @@ impl ImmixSpace { did_defrag } - pub fn clear_side_log_bits(&self) { - let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); - for chunk in self.chunk_map.all_chunks() { - log_bit.bzero_metadata(chunk.start(), Chunk::BYTES); - } - } - - #[allow(dead_code)] - pub fn set_side_log_bits(&self) { - let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); - for chunk in self.chunk_map.all_chunks() { - log_bit.bset_metadata(chunk.start(), Chunk::BYTES); - } - } - /// Generate chunk sweep tasks fn generate_sweep_tasks(&self) -> Vec>> { self.defrag.mark_histograms.lock().clear(); @@ -699,6 +698,8 @@ impl ImmixSpace { self.mark_lines(object); } + self.unlog_object_if_needed(object); + object } else { // We are forwarding objects. When the copy allocator allocates the block, it should @@ -709,6 +710,13 @@ impl ImmixSpace { semantics, copy_context, |_new_object| { + // post_copy should have set the unlog bit + // if `unlog_traced_object` is true. + debug_assert!( + !self.common.unlog_traced_object + || VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC + .is_unlogged::(object, Ordering::Relaxed) + ); #[cfg(feature = "vo_bit")] vo_bit::helper::on_object_forwarded::(_new_object); }, @@ -721,7 +729,6 @@ impl ImmixSpace { queue.enqueue(new_object); debug_assert!(new_object.is_live()); - self.unlog_object_if_needed(new_object); new_object } } diff --git a/src/policy/immortalspace.rs b/src/policy/immortalspace.rs index 4c57c4034b..325ddc1c81 100644 --- a/src/policy/immortalspace.rs +++ b/src/policy/immortalspace.rs @@ -115,6 +115,20 @@ impl Space for ImmortalSpace { fn enumerate_objects(&self, enumerator: &mut dyn ObjectEnumerator) { object_enum::enumerate_blocks_from_monotonic_page_resource(enumerator, &self.pr); } + + fn clear_side_log_bits(&self) { + let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); + for (start, size) in self.pr.iterate_allocated_regions() { + log_bit.bzero_metadata(start, size); + } + } + + fn set_side_log_bits(&self) { + let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); + for (start, size) in self.pr.iterate_allocated_regions() { + log_bit.bset_metadata(start, size); + } + } } use crate::scheduler::GCWorker; @@ -173,20 +187,6 @@ impl ImmortalSpace { self.mark_state.on_global_release::(); } - pub fn clear_side_log_bits(&self) { - let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); - for (start, size) in self.pr.iterate_allocated_regions() { - log_bit.bzero_metadata(start, size); - } - } - - pub fn set_side_log_bits(&self) { - let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); - for (start, size) in self.pr.iterate_allocated_regions() { - log_bit.bset_metadata(start, size); - } - } - pub fn trace_object( &self, queue: &mut Q, diff --git a/src/policy/largeobjectspace.rs b/src/policy/largeobjectspace.rs index 3ad03ebd9c..e7d3107e45 100644 --- a/src/policy/largeobjectspace.rs +++ b/src/policy/largeobjectspace.rs @@ -194,6 +194,22 @@ impl Space for LargeObjectSpace { fn enumerate_objects(&self, enumerator: &mut dyn ObjectEnumerator) { self.treadmill.enumerate_objects(enumerator); } + + fn clear_side_log_bits(&self) { + let mut enumator = ClosureObjectEnumerator::<_, VM>::new(|object| { + VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.clear::(object, Ordering::SeqCst); + }); + self.treadmill.enumerate_objects(&mut enumator); + } + + fn set_side_log_bits(&self) { + debug_assert!(self.treadmill.is_from_space_empty()); + debug_assert!(self.treadmill.is_nursery_empty()); + let mut enumator = ClosureObjectEnumerator::<_, VM>::new(|object| { + VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.mark_as_unlogged::(object, Ordering::SeqCst); + }); + self.treadmill.enumerate_objects(&mut enumator); + } } use crate::scheduler::GCWorker; @@ -247,22 +263,6 @@ impl LargeObjectSpace { } } - pub fn clear_side_log_bits(&self) { - let mut enumator = ClosureObjectEnumerator::<_, VM>::new(|object| { - VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.clear::(object, Ordering::SeqCst); - }); - self.treadmill.enumerate_objects(&mut enumator); - } - - pub fn set_side_log_bits(&self) { - debug_assert!(self.treadmill.is_from_space_empty()); - debug_assert!(self.treadmill.is_nursery_empty()); - let mut enumator = ClosureObjectEnumerator::<_, VM>::new(|object| { - VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.mark_as_unlogged::(object, Ordering::SeqCst); - }); - self.treadmill.enumerate_objects(&mut enumator); - } - pub fn prepare(&mut self, full_heap: bool) { if full_heap { debug_assert!(self.treadmill.is_from_space_empty()); diff --git a/src/policy/lockfreeimmortalspace.rs b/src/policy/lockfreeimmortalspace.rs index 76e44c55ee..3a3264b05b 100644 --- a/src/policy/lockfreeimmortalspace.rs +++ b/src/policy/lockfreeimmortalspace.rs @@ -181,6 +181,14 @@ impl Space for LockFreeImmortalSpace { fn enumerate_objects(&self, enumerator: &mut dyn ObjectEnumerator) { enumerator.visit_address_range(self.start, self.start + self.total_bytes); } + + fn clear_side_log_bits(&self) { + unimplemented!() + } + + fn set_side_log_bits(&self) { + unimplemented!() + } } use crate::plan::{ObjectQueue, VectorObjectQueue}; diff --git a/src/policy/markcompactspace.rs b/src/policy/markcompactspace.rs index c709ab499a..d7fa7d8a9c 100644 --- a/src/policy/markcompactspace.rs +++ b/src/policy/markcompactspace.rs @@ -143,6 +143,14 @@ impl Space for MarkCompactSpace { fn enumerate_objects(&self, enumerator: &mut dyn ObjectEnumerator) { object_enum::enumerate_blocks_from_monotonic_page_resource(enumerator, &self.pr); } + + fn clear_side_log_bits(&self) { + unimplemented!() + } + + fn set_side_log_bits(&self) { + unimplemented!() + } } impl crate::policy::gc_work::PolicyTraceObject for MarkCompactSpace { diff --git a/src/policy/marksweepspace/malloc_ms/global.rs b/src/policy/marksweepspace/malloc_ms/global.rs index fd473dd0ee..acf3369554 100644 --- a/src/policy/marksweepspace/malloc_ms/global.rs +++ b/src/policy/marksweepspace/malloc_ms/global.rs @@ -241,6 +241,14 @@ impl Space for MallocSpace { fn enumerate_objects(&self, _enumerator: &mut dyn ObjectEnumerator) { unimplemented!() } + + fn clear_side_log_bits(&self) { + unimplemented!() + } + + fn set_side_log_bits(&self) { + unimplemented!() + } } use crate::scheduler::GCWorker; diff --git a/src/policy/marksweepspace/native_ms/global.rs b/src/policy/marksweepspace/native_ms/global.rs index d7d85a67bd..93697e8b04 100644 --- a/src/policy/marksweepspace/native_ms/global.rs +++ b/src/policy/marksweepspace/native_ms/global.rs @@ -254,6 +254,20 @@ impl Space for MarkSweepSpace { fn enumerate_objects(&self, enumerator: &mut dyn ObjectEnumerator) { object_enum::enumerate_blocks_from_chunk_map::(enumerator, &self.chunk_map); } + + fn clear_side_log_bits(&self) { + let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); + for chunk in self.chunk_map.all_chunks() { + log_bit.bzero_metadata(chunk.start(), Chunk::BYTES); + } + } + + fn set_side_log_bits(&self) { + let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); + for chunk in self.chunk_map.all_chunks() { + log_bit.bset_metadata(chunk.start(), Chunk::BYTES); + } + } } impl crate::policy::gc_work::PolicyTraceObject for MarkSweepSpace { @@ -419,20 +433,6 @@ impl MarkSweepSpace { .bulk_add(work_packets); } - pub fn clear_side_log_bits(&self) { - let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); - for chunk in self.chunk_map.all_chunks() { - log_bit.bzero_metadata(chunk.start(), Chunk::BYTES); - } - } - - pub fn set_side_log_bits(&self) { - let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); - for chunk in self.chunk_map.all_chunks() { - log_bit.bset_metadata(chunk.start(), Chunk::BYTES); - } - } - pub fn release(&mut self) { let num_mutators = VM::VMActivePlan::number_of_mutators(); // all ReleaseMutator work packets plus the ReleaseMarkSweepSpace packet diff --git a/src/policy/space.rs b/src/policy/space.rs index 2f1a787dfd..654bcb22a6 100644 --- a/src/policy/space.rs +++ b/src/policy/space.rs @@ -433,6 +433,14 @@ pub trait Space: 'static + SFT + Sync + Downcast { /// the execution time. For LOS, it will be cheaper to enumerate individual objects than /// scanning VO bits because it is sparse. fn enumerate_objects(&self, enumerator: &mut dyn ObjectEnumerator); + + /// Clear the side log bits for allocated regions in this space. + /// This method is only called if the plan knows the log bits are side metadata. + fn clear_side_log_bits(&self); + + /// Set the side log bits for allocated regions in this space. + /// This method is only called if the plan knows the log bits are side metadata. + fn set_side_log_bits(&self); } /// Print the VM map for a space. diff --git a/src/policy/vmspace.rs b/src/policy/vmspace.rs index b08d6a7a21..9a97aea033 100644 --- a/src/policy/vmspace.rs +++ b/src/policy/vmspace.rs @@ -154,6 +154,22 @@ impl Space for VMSpace { enumerator.visit_address_range(ep.start, ep.end); } } + + fn clear_side_log_bits(&self) { + let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); + let external_pages = self.pr.get_external_pages(); + for ep in external_pages.iter() { + log_bit.bzero_metadata(ep.start, ep.end - ep.start); + } + } + + fn set_side_log_bits(&self) { + let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); + let external_pages = self.pr.get_external_pages(); + for ep in external_pages.iter() { + log_bit.bset_metadata(ep.start, ep.end - ep.start); + } + } } use crate::scheduler::GCWorker; @@ -271,22 +287,6 @@ impl VMSpace { self.mark_state.on_global_release::(); } - pub fn clear_side_log_bits(&self) { - let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); - let external_pages = self.pr.get_external_pages(); - for ep in external_pages.iter() { - log_bit.bzero_metadata(ep.start, ep.end - ep.start); - } - } - - pub fn set_side_log_bits(&self) { - let log_bit = VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.extract_side_spec(); - let external_pages = self.pr.get_external_pages(); - for ep in external_pages.iter() { - log_bit.bset_metadata(ep.start, ep.end - ep.start); - } - } - pub fn trace_object( &self, queue: &mut Q, From fc8e662a79fb26f2296d77c25f61ef3c0da06d95 Mon Sep 17 00:00:00 2001 From: Yi Lin Date: Thu, 14 Aug 2025 00:30:54 +0000 Subject: [PATCH 08/12] Clear side log bits for full heap genimmix --- src/plan/generational/immix/global.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plan/generational/immix/global.rs b/src/plan/generational/immix/global.rs index 41e7a70768..340e5a5887 100644 --- a/src/plan/generational/immix/global.rs +++ b/src/plan/generational/immix/global.rs @@ -130,6 +130,7 @@ impl Plan for GenImmix { self.gen.prepare(tls); if full_heap { if VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.is_on_side() { + self.gen.common.clear_side_log_bits(); self.immix_space.clear_side_log_bits(); } self.immix_space.prepare( From f1d2eb8c5a39bd105ca5e54d8a5f0da824d14fd1 Mon Sep 17 00:00:00 2001 From: Yi Lin Date: Thu, 14 Aug 2025 00:49:53 +0000 Subject: [PATCH 09/12] Don't clear common spaces' log bits for genimmix and stickyimmix --- src/plan/generational/immix/global.rs | 1 - src/plan/sticky/immix/global.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/plan/generational/immix/global.rs b/src/plan/generational/immix/global.rs index 340e5a5887..41e7a70768 100644 --- a/src/plan/generational/immix/global.rs +++ b/src/plan/generational/immix/global.rs @@ -130,7 +130,6 @@ impl Plan for GenImmix { self.gen.prepare(tls); if full_heap { if VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.is_on_side() { - self.gen.common.clear_side_log_bits(); self.immix_space.clear_side_log_bits(); } self.immix_space.prepare( diff --git a/src/plan/sticky/immix/global.rs b/src/plan/sticky/immix/global.rs index f6cb9d4567..7dcd83ad3b 100644 --- a/src/plan/sticky/immix/global.rs +++ b/src/plan/sticky/immix/global.rs @@ -124,7 +124,6 @@ impl Plan for StickyImmix { } else { self.full_heap_gc_count.lock().unwrap().inc(); if VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.is_on_side() { - self.immix.common.clear_side_log_bits(); self.immix.immix_space.clear_side_log_bits(); } self.immix.prepare(tls); From fc6a2aa8d48ff0f159cff8fe815b9cb7846fd8fa Mon Sep 17 00:00:00 2001 From: Yi Lin Date: Thu, 14 Aug 2025 02:05:04 +0000 Subject: [PATCH 10/12] Minor fix on the assertion in immix space --- src/policy/immix/immixspace.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/policy/immix/immixspace.rs b/src/policy/immix/immixspace.rs index 6a5c128882..bc3a585eff 100644 --- a/src/policy/immix/immixspace.rs +++ b/src/policy/immix/immixspace.rs @@ -709,16 +709,16 @@ impl ImmixSpace { object, semantics, copy_context, - |_new_object| { + |new_object| { // post_copy should have set the unlog bit // if `unlog_traced_object` is true. debug_assert!( !self.common.unlog_traced_object || VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC - .is_unlogged::(object, Ordering::Relaxed) + .is_unlogged::(new_object, Ordering::Relaxed) ); #[cfg(feature = "vo_bit")] - vo_bit::helper::on_object_forwarded::(_new_object); + vo_bit::helper::on_object_forwarded::(new_object); }, ) }; From d4ec5409d8fd07c27b2b071f47c78ebd783fab16 Mon Sep 17 00:00:00 2001 From: Yi Lin Date: Thu, 14 Aug 2025 02:07:01 +0000 Subject: [PATCH 11/12] We don't need to clear side log bit for gen nursery --- src/plan/generational/global.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/plan/generational/global.rs b/src/plan/generational/global.rs index 61fe31b836..54e94a6334 100644 --- a/src/plan/generational/global.rs +++ b/src/plan/generational/global.rs @@ -74,9 +74,6 @@ impl CommonGenPlan { /// Release Gen. This should be called by a single thread in GC release work. pub fn release(&mut self, tls: VMWorkerThread) { let full_heap = !self.is_current_gc_nursery(); - if VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.is_on_side() { - self.nursery.clear_side_log_bits(); - } self.common.release(tls, full_heap); self.nursery.release(); } From cabdd668972fb883e05385ce94259e3b01357798 Mon Sep 17 00:00:00 2001 From: Yi Lin Date: Thu, 14 Aug 2025 03:49:42 +0000 Subject: [PATCH 12/12] Fix style check for stable Rust --- src/plan/global.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/plan/global.rs b/src/plan/global.rs index dbdba5958b..481a4063a1 100644 --- a/src/plan/global.rs +++ b/src/plan/global.rs @@ -442,7 +442,7 @@ impl CreateSpecificPlanArgs<'_, VM> { zeroed: bool, permission_exec: bool, vmrequest: VMRequest, - ) -> PlanCreateSpaceArgs { + ) -> PlanCreateSpaceArgs<'_, VM> { // Objects are allocatd as young, and when traced, they stay young. If they are copied out of the nursery space, they will be moved to a mature space, // and log bits will be set in that case by the mature space. self._get_space_args(name, zeroed, permission_exec, false, false, vmrequest) @@ -455,7 +455,7 @@ impl CreateSpecificPlanArgs<'_, VM> { zeroed: bool, permission_exec: bool, vmrequest: VMRequest, - ) -> PlanCreateSpaceArgs { + ) -> PlanCreateSpaceArgs<'_, VM> { // Objects are allocated as mature (pre-tenured), and when traced, they stay mature. // If an object gets copied into a mature space, the object is also mature, self._get_space_args(name, zeroed, permission_exec, true, true, vmrequest) @@ -468,7 +468,7 @@ impl CreateSpecificPlanArgs<'_, VM> { zeroed: bool, permission_exec: bool, vmrequest: VMRequest, - ) -> PlanCreateSpaceArgs { + ) -> PlanCreateSpaceArgs<'_, VM> { // Objects are allocated as young, and when traced, they become mature objects. self._get_space_args(name, zeroed, permission_exec, false, true, vmrequest) } @@ -480,7 +480,7 @@ impl CreateSpecificPlanArgs<'_, VM> { zeroed: bool, permission_exec: bool, vmrequest: VMRequest, - ) -> PlanCreateSpaceArgs { + ) -> PlanCreateSpaceArgs<'_, VM> { // Non generational plan: we do not use any of the flags about log bits. self._get_space_args(name, zeroed, permission_exec, false, false, vmrequest) } @@ -491,7 +491,7 @@ impl CreateSpecificPlanArgs<'_, VM> { &mut self, generational: bool, name: &'static str, - ) -> PlanCreateSpaceArgs { + ) -> PlanCreateSpaceArgs<'_, VM> { self.get_base_space_args( generational, name, @@ -505,7 +505,7 @@ impl CreateSpecificPlanArgs<'_, VM> { generational: bool, name: &'static str, permission_exec: bool, - ) -> PlanCreateSpaceArgs { + ) -> PlanCreateSpaceArgs<'_, VM> { if generational { // In generational plans, common/base spaces behave like a mature space: // * the objects in these spaces are not traced in a nursery GC