mmtk/plan/markcompact/
global.rs

1use super::gc_work::MarkCompactGCWorkContext;
2use super::gc_work::{
3    CalculateForwardingAddress, Compact, ForwardingTrace, MarkingTrace, UpdateReferences,
4};
5use crate::plan::global::CommonPlan;
6use crate::plan::global::{BasePlan, CreateGeneralPlanArgs, CreateSpecificPlanArgs};
7use crate::plan::markcompact::mutator::ALLOCATOR_MAPPING;
8use crate::plan::tracing::gc_work::weakref::{
9    VMForwardWeakRefs, VMPostForwarding, VMProcessWeakRefs,
10};
11use crate::plan::AllocationSemantics;
12use crate::plan::Plan;
13use crate::plan::PlanConstraints;
14use crate::policy::markcompactspace::MarkCompactSpace;
15use crate::policy::space::Space;
16use crate::scheduler::gc_work::*;
17use crate::scheduler::*;
18use crate::util::alloc::allocators::AllocatorSelector;
19use crate::util::copy::CopySemantics;
20use crate::util::heap::gc_trigger::SpaceStats;
21use crate::util::heap::VMRequest;
22use crate::util::metadata::side_metadata::SideMetadataContext;
23#[cfg(not(feature = "vo_bit"))]
24use crate::util::metadata::vo_bit::VO_BIT_SIDE_METADATA_SPEC;
25use crate::util::opaque_pointer::*;
26use crate::vm::VMBinding;
27
28use enum_map::EnumMap;
29
30use mmtk_macros::{HasSpaces, PlanTraceObject};
31
32#[derive(HasSpaces, PlanTraceObject)]
33pub struct MarkCompact<VM: VMBinding> {
34    #[space]
35    #[copy_semantics(CopySemantics::DefaultCopy)]
36    pub mc_space: MarkCompactSpace<VM>,
37    #[parent]
38    pub common: CommonPlan<VM>,
39}
40
41/// The plan constraints for the mark compact plan.
42pub const MARKCOMPACT_CONSTRAINTS: PlanConstraints = PlanConstraints {
43    moves_objects: true,
44    needs_forward_after_liveness: true,
45    max_non_los_default_alloc_bytes:
46        crate::plan::plan_constraints::MAX_NON_LOS_ALLOC_BYTES_COPYING_PLAN,
47    ..PlanConstraints::default()
48};
49
50impl<VM: VMBinding> Plan for MarkCompact<VM> {
51    fn constraints(&self) -> &'static PlanConstraints {
52        &MARKCOMPACT_CONSTRAINTS
53    }
54
55    fn base(&self) -> &BasePlan<VM> {
56        &self.common.base
57    }
58
59    fn base_mut(&mut self) -> &mut BasePlan<Self::VM> {
60        &mut self.common.base
61    }
62
63    fn common(&self) -> &CommonPlan<VM> {
64        &self.common
65    }
66
67    fn prepare(&mut self, _tls: VMWorkerThread) {
68        self.common.prepare(_tls, true);
69        self.mc_space.prepare();
70    }
71
72    fn release(&mut self, _tls: VMWorkerThread) {
73        self.common.release(_tls, true);
74        self.mc_space.release();
75    }
76
77    fn end_of_gc(&mut self, tls: VMWorkerThread) {
78        self.common.end_of_gc(tls);
79    }
80
81    fn get_allocator_mapping(&self) -> &'static EnumMap<AllocationSemantics, AllocatorSelector> {
82        &ALLOCATOR_MAPPING
83    }
84
85    fn schedule_collection(&'static self, scheduler: &GCWorkScheduler<VM>) {
86        // TODO: Extract a method similar to `GCWorkScheduler::schedule_common_work`
87        // but for compressing plans.
88
89        // Stop & scan mutators (mutator scanning can happen before STW)
90        scheduler.work_buckets[WorkBucketStage::Unconstrained]
91            .add(StopMutators::<MarkCompactGCWorkContext<VM>>::new());
92
93        // Prepare global/collectors/mutators
94        scheduler.work_buckets[WorkBucketStage::Prepare]
95            .add(Prepare::<MarkCompactGCWorkContext<VM>>::new(self));
96
97        scheduler.work_buckets[WorkBucketStage::CalculateForwarding]
98            .add(CalculateForwardingAddress::<VM>::new(&self.mc_space));
99        // do another trace to update references
100        scheduler.work_buckets[WorkBucketStage::SecondRoots].add(UpdateReferences::<VM>::new(self));
101        scheduler.work_buckets[WorkBucketStage::Compact].add(Compact::<VM>::new(&self.mc_space));
102
103        // Release global/collectors/mutators
104        scheduler.work_buckets[WorkBucketStage::Release]
105            .add(Release::<MarkCompactGCWorkContext<VM>>::new(self));
106
107        // Reference processing
108        if !*self.base().options.no_reference_types {
109            use crate::util::reference_processor::{
110                PhantomRefProcessing, SoftRefProcessing, WeakRefProcessing,
111            };
112            scheduler.work_buckets[WorkBucketStage::SoftRefClosure]
113                .add(SoftRefProcessing::<MarkingTrace<VM>>::new());
114            scheduler.work_buckets[WorkBucketStage::WeakRefClosure]
115                .add(WeakRefProcessing::<VM>::new());
116            scheduler.work_buckets[WorkBucketStage::PhantomRefClosure]
117                .add(PhantomRefProcessing::<VM>::new());
118
119            use crate::util::reference_processor::RefForwarding;
120            scheduler.work_buckets[WorkBucketStage::RefForwarding]
121                .add(RefForwarding::<ForwardingTrace<VM>>::new());
122
123            use crate::util::reference_processor::RefEnqueue;
124            scheduler.work_buckets[WorkBucketStage::Release].add(RefEnqueue::<VM>::new());
125        }
126
127        // Finalization
128        if !*self.base().options.no_finalizer {
129            use crate::util::finalizable_processor::{Finalization, ForwardFinalization};
130            // finalization
131            // treat finalizable objects as roots and perform a closure (marking)
132            // must be done before calculating forwarding pointers
133            scheduler.work_buckets[WorkBucketStage::FinalRefClosure]
134                .add(Finalization::<MarkingTrace<VM>>::new());
135            // update finalizable object references
136            // must be done before compacting
137            scheduler.work_buckets[WorkBucketStage::FinalizableForwarding]
138                .add(ForwardFinalization::<ForwardingTrace<VM>>::new());
139        }
140
141        // VM-specific weak ref processing
142        scheduler.work_buckets[WorkBucketStage::VMRefClosure]
143            .set_sentinel(Box::new(VMProcessWeakRefs::<MarkingTrace<VM>>::new()));
144
145        // VM-specific weak ref forwarding
146        scheduler.work_buckets[WorkBucketStage::VMRefForwarding]
147            .add(VMForwardWeakRefs::<ForwardingTrace<VM>>::new());
148
149        // VM-specific work after forwarding, possible to implement ref enququing.
150        scheduler.work_buckets[WorkBucketStage::Release].add(VMPostForwarding::<VM>::default());
151
152        // Analysis GC work
153        #[cfg(feature = "analysis")]
154        {
155            use crate::util::analysis::GcHookWork;
156            scheduler.work_buckets[WorkBucketStage::Unconstrained].add(GcHookWork);
157        }
158        #[cfg(feature = "sanity")]
159        scheduler.work_buckets[WorkBucketStage::Final]
160            .add(crate::util::sanity::sanity_checker::ScheduleSanityGC::<Self>::new(self));
161    }
162
163    fn collection_required(&self, space_full: bool, _space: Option<SpaceStats<Self::VM>>) -> bool {
164        self.base().collection_required(self, space_full)
165    }
166
167    fn get_used_pages(&self) -> usize {
168        self.mc_space.reserved_pages() + self.common.get_used_pages()
169    }
170
171    fn get_collection_reserved_pages(&self) -> usize {
172        0
173    }
174
175    fn current_gc_may_move_object(&self) -> bool {
176        true
177    }
178}
179
180impl<VM: VMBinding> MarkCompact<VM> {
181    pub fn new(args: CreateGeneralPlanArgs<VM>) -> Self {
182        // if vo_bit is enabled, VO_BIT_SIDE_METADATA_SPEC will be added to
183        // SideMetadataContext by default, so we don't need to add it here.
184        #[cfg(feature = "vo_bit")]
185        let global_side_metadata_specs = SideMetadataContext::new_global_specs(&[]);
186        // if vo_bit is NOT enabled,
187        // we need to add VO_BIT_SIDE_METADATA_SPEC to SideMetadataContext here.
188        #[cfg(not(feature = "vo_bit"))]
189        let global_side_metadata_specs =
190            SideMetadataContext::new_global_specs(&[VO_BIT_SIDE_METADATA_SPEC]);
191
192        let mut plan_args = CreateSpecificPlanArgs {
193            global_args: args,
194            constraints: &MARKCOMPACT_CONSTRAINTS,
195            global_side_metadata_specs,
196        };
197
198        let mc_space = MarkCompactSpace::new(plan_args.get_normal_space_args(
199            "mc",
200            true,
201            false,
202            VMRequest::discontiguous(),
203        ));
204
205        MarkCompact {
206            mc_space,
207            common: CommonPlan::new(plan_args),
208        }
209    }
210}
211
212impl<VM: VMBinding> MarkCompact<VM> {
213    pub fn mc_space(&self) -> &MarkCompactSpace<VM> {
214        &self.mc_space
215    }
216}