mmtk/plan/generational/copying/
global.rs1use 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
46pub 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 (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); }
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 fn get_available_pages(&self) -> usize {
141 (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}