mmtk/plan/generational/copying/
global.rs

1use super::gc_work::GenCopyGCWorkContext;
2use super::gc_work::GenCopyNurseryGCWorkContext;
3use super::mutator::ALLOCATOR_MAPPING;
4use crate::plan::generational::global::CommonGenPlan;
5use crate::plan::generational::global::GenerationalPlan;
6use crate::plan::generational::global::GenerationalPlanExt;
7use crate::plan::global::BasePlan;
8use crate::plan::global::CommonPlan;
9use crate::plan::global::CreateGeneralPlanArgs;
10use crate::plan::global::CreateSpecificPlanArgs;
11use crate::plan::AllocationSemantics;
12use crate::plan::Plan;
13use crate::plan::PlanConstraints;
14use crate::policy::copyspace::CopySpace;
15use crate::policy::gc_work::TraceKind;
16use crate::policy::space::Space;
17use crate::scheduler::*;
18use crate::util::alloc::allocators::AllocatorSelector;
19use crate::util::copy::*;
20use crate::util::heap::gc_trigger::SpaceStats;
21use crate::util::heap::VMRequest;
22use crate::util::Address;
23use crate::util::ObjectReference;
24use crate::util::VMWorkerThread;
25use crate::vm::*;
26use crate::ObjectQueue;
27use crate::MMTK;
28use enum_map::EnumMap;
29use std::sync::atomic::{AtomicBool, Ordering};
30
31use mmtk_macros::{HasSpaces, PlanTraceObject};
32
33#[derive(HasSpaces, PlanTraceObject)]
34pub struct GenCopy<VM: VMBinding> {
35    #[parent]
36    pub gen: CommonGenPlan<VM>,
37    pub hi: AtomicBool,
38    #[space]
39    #[copy_semantics(CopySemantics::Mature)]
40    pub copyspace0: CopySpace<VM>,
41    #[space]
42    #[copy_semantics(CopySemantics::Mature)]
43    pub copyspace1: CopySpace<VM>,
44}
45
46/// The plan constraints for the generational copying plan.
47pub const GENCOPY_CONSTRAINTS: PlanConstraints = crate::plan::generational::GEN_CONSTRAINTS;
48
49impl<VM: VMBinding> Plan for GenCopy<VM> {
50    fn constraints(&self) -> &'static PlanConstraints {
51        &GENCOPY_CONSTRAINTS
52    }
53
54    fn create_copy_config(&'static self) -> CopyConfig<Self::VM> {
55        use enum_map::enum_map;
56        CopyConfig {
57            copy_mapping: enum_map! {
58                CopySemantics::Mature => CopySelector::CopySpace(0),
59                CopySemantics::PromoteToMature => CopySelector::CopySpace(0),
60                _ => CopySelector::Unused,
61            },
62            space_mapping: vec![
63                // The tospace argument doesn't matter, we will rebind before a GC anyway.
64                (CopySelector::CopySpace(0), self.tospace()),
65            ],
66            constraints: &GENCOPY_CONSTRAINTS,
67        }
68    }
69
70    fn collection_required(&self, space_full: bool, space: Option<SpaceStats<Self::VM>>) -> bool
71    where
72        Self: Sized,
73    {
74        self.gen.collection_required(self, space_full, space)
75    }
76
77    fn schedule_collection(&'static self, scheduler: &GCWorkScheduler<VM>) {
78        let is_full_heap = self.requires_full_heap_collection();
79        if is_full_heap {
80            scheduler.schedule_common_work::<GenCopyGCWorkContext<VM>>(self);
81        } else {
82            scheduler.schedule_common_work::<GenCopyNurseryGCWorkContext<VM>>(self);
83        }
84    }
85
86    fn get_allocator_mapping(&self) -> &'static EnumMap<AllocationSemantics, AllocatorSelector> {
87        &ALLOCATOR_MAPPING
88    }
89
90    fn prepare(&mut self, tls: VMWorkerThread) {
91        let full_heap = !self.gen.is_current_gc_nursery();
92        self.gen.prepare(tls);
93        if full_heap {
94            self.hi
95                .store(!self.hi.load(Ordering::SeqCst), Ordering::SeqCst); // flip the semi-spaces
96        }
97        let hi = self.hi.load(Ordering::SeqCst);
98        self.copyspace0.prepare(hi);
99        self.copyspace1.prepare(!hi);
100
101        self.fromspace_mut()
102            .set_copy_for_sft_trace(Some(CopySemantics::Mature));
103        self.tospace_mut().set_copy_for_sft_trace(None);
104    }
105
106    fn prepare_worker(&self, worker: &mut GCWorker<Self::VM>) {
107        unsafe { worker.get_copy_context_mut().copy[0].assume_init_mut() }.rebind(self.tospace());
108    }
109
110    fn release(&mut self, tls: VMWorkerThread) {
111        let full_heap = !self.gen.is_current_gc_nursery();
112        self.gen.release(tls);
113        if full_heap {
114            if VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC.is_on_side() {
115                self.fromspace().clear_side_log_bits();
116            }
117            self.fromspace().release();
118        }
119    }
120
121    fn end_of_pause(&mut self, mmtk: &'static MMTK<VM>, tls: VMWorkerThread) {
122        let next_gc_full_heap = CommonGenPlan::should_next_gc_be_full_heap(self);
123        self.gen.end_of_pause(tls, next_gc_full_heap);
124        mmtk.gc_trigger.policy.on_gc_end(mmtk);
125    }
126
127    fn get_collection_reserved_pages(&self) -> usize {
128        self.gen.get_collection_reserved_pages() + self.tospace().reserved_pages()
129    }
130
131    fn get_used_pages(&self) -> usize {
132        self.gen.get_used_pages() + self.tospace().reserved_pages()
133    }
134
135    fn current_gc_may_move_object(&self) -> bool {
136        true
137    }
138
139    /// Return the number of pages available for allocation. Assuming all future allocations goes to nursery.
140    fn get_available_pages(&self) -> usize {
141        // super.get_available_pages() / 2 to reserve pages for copying
142        (self
143            .get_total_pages()
144            .saturating_sub(self.get_reserved_pages()))
145            >> 1
146    }
147
148    fn base(&self) -> &BasePlan<VM> {
149        &self.gen.common.base
150    }
151
152    fn base_mut(&mut self) -> &mut BasePlan<Self::VM> {
153        &mut self.gen.common.base
154    }
155
156    fn common(&self) -> &CommonPlan<VM> {
157        &self.gen.common
158    }
159
160    fn generational(&self) -> Option<&dyn GenerationalPlan<VM = Self::VM>> {
161        Some(self)
162    }
163}
164
165impl<VM: VMBinding> GenerationalPlan for GenCopy<VM> {
166    fn is_current_gc_nursery(&self) -> bool {
167        self.gen.is_current_gc_nursery()
168    }
169
170    fn is_object_in_nursery(&self, object: ObjectReference) -> bool {
171        self.gen.nursery.in_space(object)
172    }
173
174    fn is_address_in_nursery(&self, addr: Address) -> bool {
175        self.gen.nursery.address_in_space(addr)
176    }
177
178    fn get_mature_physical_pages_available(&self) -> usize {
179        self.tospace().available_physical_pages()
180    }
181
182    fn get_mature_reserved_pages(&self) -> usize {
183        self.tospace().reserved_pages()
184    }
185
186    fn force_full_heap_collection(&self) {
187        self.gen.force_full_heap_collection()
188    }
189
190    fn last_collection_full_heap(&self) -> bool {
191        self.gen.last_collection_full_heap()
192    }
193}
194
195impl<VM: VMBinding> GenerationalPlanExt<VM> for GenCopy<VM> {
196    fn trace_object_nursery<Q: ObjectQueue, const KIND: TraceKind>(
197        &self,
198        queue: &mut Q,
199        object: ObjectReference,
200        worker: &mut GCWorker<VM>,
201    ) -> ObjectReference {
202        self.gen
203            .trace_object_nursery::<Q, KIND>(queue, object, worker)
204    }
205}
206
207impl<VM: VMBinding> GenCopy<VM> {
208    pub fn new(args: CreateGeneralPlanArgs<VM>) -> Self {
209        let mut plan_args = CreateSpecificPlanArgs {
210            global_args: args,
211            constraints: &GENCOPY_CONSTRAINTS,
212            global_side_metadata_specs:
213                crate::plan::generational::new_generational_global_metadata_specs::<VM>(),
214        };
215
216        let copyspace0 = CopySpace::new(
217            plan_args.get_mature_space_args("copyspace0", true, false, VMRequest::discontiguous()),
218            false,
219        );
220        let copyspace1 = CopySpace::new(
221            plan_args.get_mature_space_args("copyspace1", true, false, VMRequest::discontiguous()),
222            true,
223        );
224
225        GenCopy {
226            gen: CommonGenPlan::new(plan_args),
227            hi: AtomicBool::new(false),
228            copyspace0,
229            copyspace1,
230        }
231    }
232
233    fn requires_full_heap_collection(&self) -> bool {
234        self.gen.requires_full_heap_collection(self)
235    }
236
237    pub fn tospace(&self) -> &CopySpace<VM> {
238        if self.hi.load(Ordering::SeqCst) {
239            &self.copyspace1
240        } else {
241            &self.copyspace0
242        }
243    }
244
245    pub fn tospace_mut(&mut self) -> &mut CopySpace<VM> {
246        if self.hi.load(Ordering::SeqCst) {
247            &mut self.copyspace1
248        } else {
249            &mut self.copyspace0
250        }
251    }
252
253    pub fn fromspace(&self) -> &CopySpace<VM> {
254        if self.hi.load(Ordering::SeqCst) {
255            &self.copyspace0
256        } else {
257            &self.copyspace1
258        }
259    }
260
261    pub fn fromspace_mut(&mut self) -> &mut CopySpace<VM> {
262        if self.hi.load(Ordering::SeqCst) {
263            &mut self.copyspace0
264        } else {
265            &mut self.copyspace1
266        }
267    }
268}