mmtk/plan/generational/immix/
global.rs1use super::gc_work::GenImmixMatureGCWorkContext;
2use super::gc_work::GenImmixNurseryGCWorkContext;
3use crate::plan::generational::global::CommonGenPlan;
4use crate::plan::generational::global::GenerationalPlan;
5use crate::plan::global::BasePlan;
6use crate::plan::global::CommonPlan;
7use crate::plan::global::CreateGeneralPlanArgs;
8use crate::plan::global::CreateSpecificPlanArgs;
9use crate::plan::AllocationSemantics;
10use crate::plan::Plan;
11use crate::plan::PlanConstraints;
12use crate::policy::gc_work::TraceKind;
13use crate::policy::immix::defrag::StatsForDefrag;
14use crate::policy::immix::ImmixSpace;
15use crate::policy::immix::ImmixSpaceArgs;
16use crate::policy::immix::{TRACE_KIND_DEFRAG, TRACE_KIND_FAST};
17use crate::policy::space::Space;
18use crate::scheduler::GCWorkScheduler;
19use crate::scheduler::GCWorker;
20use crate::util::alloc::allocators::AllocatorSelector;
21use crate::util::copy::*;
22use crate::util::heap::gc_trigger::SpaceStats;
23use crate::util::heap::VMRequest;
24use crate::util::metadata::log_bit::UnlogBitsOperation;
25use crate::util::Address;
26use crate::util::ObjectReference;
27use crate::util::VMWorkerThread;
28use crate::vm::*;
29use crate::ObjectQueue;
30use crate::MMTK;
31
32use enum_map::EnumMap;
33use std::sync::atomic::AtomicBool;
34use std::sync::atomic::Ordering;
35
36use mmtk_macros::{HasSpaces, PlanTraceObject};
37
38#[derive(HasSpaces, PlanTraceObject)]
43pub struct GenImmix<VM: VMBinding> {
44 #[parent]
46 pub gen: CommonGenPlan<VM>,
47 #[post_scan]
49 #[space]
50 #[copy_semantics(CopySemantics::Mature)]
51 pub immix_space: ImmixSpace<VM>,
52 pub last_gc_was_defrag: AtomicBool,
54 pub last_gc_was_full_heap: AtomicBool,
56}
57
58pub const GENIMMIX_CONSTRAINTS: PlanConstraints = PlanConstraints {
60 max_non_los_default_alloc_bytes: crate::util::rust_util::min_of_usize(
67 crate::policy::immix::MAX_IMMIX_OBJECT_SIZE,
68 crate::plan::generational::GEN_CONSTRAINTS.max_non_los_default_alloc_bytes,
69 ),
70 ..crate::plan::generational::GEN_CONSTRAINTS
71};
72
73impl<VM: VMBinding> Plan for GenImmix<VM> {
74 fn constraints(&self) -> &'static PlanConstraints {
75 &GENIMMIX_CONSTRAINTS
76 }
77
78 fn create_copy_config(&'static self) -> CopyConfig<Self::VM> {
79 use enum_map::enum_map;
80 CopyConfig {
81 copy_mapping: enum_map! {
82 CopySemantics::PromoteToMature => CopySelector::ImmixHybrid(0),
83 CopySemantics::Mature => CopySelector::ImmixHybrid(0),
84 _ => CopySelector::Unused,
85 },
86 space_mapping: vec![(CopySelector::ImmixHybrid(0), &self.immix_space)],
87 constraints: &GENIMMIX_CONSTRAINTS,
88 }
89 }
90
91 fn last_collection_was_exhaustive(&self) -> bool {
92 self.last_gc_was_full_heap.load(Ordering::Relaxed)
93 && self
94 .immix_space
95 .is_last_gc_exhaustive(self.last_gc_was_defrag.load(Ordering::Relaxed))
96 }
97
98 fn collection_required(&self, space_full: bool, space: Option<SpaceStats<Self::VM>>) -> bool
99 where
100 Self: Sized,
101 {
102 self.gen.collection_required(self, space_full, space)
103 }
104
105 fn schedule_collection(&'static self, scheduler: &GCWorkScheduler<Self::VM>) {
106 let is_full_heap = self.requires_full_heap_collection();
107 probe!(mmtk, gen_full_heap, is_full_heap);
108
109 if !is_full_heap {
110 info!("Nursery GC");
111 scheduler.schedule_common_work::<GenImmixNurseryGCWorkContext<VM>>(self);
112 } else {
113 info!("Full heap GC");
114 crate::plan::immix::Immix::schedule_immix_full_heap_collection::<
115 GenImmix<VM>,
116 GenImmixMatureGCWorkContext<VM, TRACE_KIND_FAST>,
117 GenImmixMatureGCWorkContext<VM, TRACE_KIND_DEFRAG>,
118 >(self, &self.immix_space, scheduler);
119 }
120 }
121
122 fn get_allocator_mapping(&self) -> &'static EnumMap<AllocationSemantics, AllocatorSelector> {
123 &super::mutator::ALLOCATOR_MAPPING
124 }
125
126 fn prepare(&mut self, tls: VMWorkerThread) {
127 let full_heap = !self.gen.is_current_gc_nursery();
128 self.gen.prepare(tls);
129 if full_heap {
130 self.immix_space.prepare(
131 full_heap,
132 Some(StatsForDefrag::new(self)),
133 UnlogBitsOperation::BulkClear,
135 );
136 } else {
137 }
140 }
141
142 fn release(&mut self, tls: VMWorkerThread) {
143 let full_heap = !self.gen.is_current_gc_nursery();
144 self.gen.release(tls);
145 if full_heap {
146 self.immix_space.release(
147 full_heap,
148 UnlogBitsOperation::NoOp,
150 );
151 } else {
152 }
155
156 self.last_gc_was_full_heap
157 .store(full_heap, Ordering::Relaxed);
158 }
159
160 fn end_of_pause(&mut self, mmtk: &'static MMTK<VM>, tls: VMWorkerThread) {
161 let next_gc_full_heap = CommonGenPlan::should_next_gc_be_full_heap(self);
162 self.gen.end_of_pause(tls, next_gc_full_heap);
163
164 let did_defrag = self.immix_space.end_of_gc();
165 self.last_gc_was_defrag.store(did_defrag, Ordering::Relaxed);
166
167 mmtk.gc_trigger.policy.on_gc_end(mmtk);
168 }
169
170 fn current_gc_may_move_object(&self) -> bool {
171 if self.is_current_gc_nursery() {
172 true
173 } else {
174 self.immix_space.in_defrag()
175 }
176 }
177
178 fn get_collection_reserved_pages(&self) -> usize {
179 self.gen.get_collection_reserved_pages() + self.immix_space.defrag_headroom_pages()
180 }
181
182 fn get_used_pages(&self) -> usize {
183 self.gen.get_used_pages() + self.immix_space.reserved_pages()
184 }
185
186 fn get_available_pages(&self) -> usize {
188 (self
190 .get_total_pages()
191 .saturating_sub(self.get_reserved_pages()))
192 >> 1
193 }
194
195 fn base(&self) -> &BasePlan<VM> {
196 &self.gen.common.base
197 }
198
199 fn base_mut(&mut self) -> &mut BasePlan<Self::VM> {
200 &mut self.gen.common.base
201 }
202
203 fn common(&self) -> &CommonPlan<VM> {
204 &self.gen.common
205 }
206
207 fn generational(&self) -> Option<&dyn GenerationalPlan<VM = VM>> {
208 Some(self)
209 }
210}
211
212impl<VM: VMBinding> GenerationalPlan for GenImmix<VM> {
213 fn is_current_gc_nursery(&self) -> bool {
214 self.gen.is_current_gc_nursery()
215 }
216
217 fn is_object_in_nursery(&self, object: ObjectReference) -> bool {
218 self.gen.nursery.in_space(object)
219 }
220
221 fn is_address_in_nursery(&self, addr: Address) -> bool {
222 self.gen.nursery.address_in_space(addr)
223 }
224
225 fn get_mature_physical_pages_available(&self) -> usize {
226 self.immix_space.available_physical_pages()
227 }
228
229 fn get_mature_reserved_pages(&self) -> usize {
230 self.immix_space.reserved_pages()
231 }
232
233 fn force_full_heap_collection(&self) {
234 self.gen.force_full_heap_collection()
235 }
236
237 fn last_collection_full_heap(&self) -> bool {
238 self.gen.last_collection_full_heap()
239 }
240}
241
242impl<VM: VMBinding> crate::plan::generational::global::GenerationalPlanExt<VM> for GenImmix<VM> {
243 fn trace_object_nursery<Q: ObjectQueue, const KIND: TraceKind>(
244 &self,
245 queue: &mut Q,
246 object: ObjectReference,
247 worker: &mut GCWorker<VM>,
248 ) -> ObjectReference {
249 self.gen
250 .trace_object_nursery::<Q, KIND>(queue, object, worker)
251 }
252}
253
254impl<VM: VMBinding> GenImmix<VM> {
255 pub fn new(args: CreateGeneralPlanArgs<VM>) -> Self {
256 let mut plan_args = CreateSpecificPlanArgs {
257 global_args: args,
258 constraints: &GENIMMIX_CONSTRAINTS,
259 global_side_metadata_specs:
260 crate::plan::generational::new_generational_global_metadata_specs::<VM>(),
261 };
262 let immix_space = ImmixSpace::new(
263 plan_args.get_mature_space_args(
264 "immix_mature",
265 true,
266 false,
267 VMRequest::discontiguous(),
268 ),
269 ImmixSpaceArgs {
270 mixed_age: false,
272 never_move_objects: false,
273 },
274 );
275
276 GenImmix {
277 gen: CommonGenPlan::new(plan_args),
278 immix_space,
279 last_gc_was_defrag: AtomicBool::new(false),
280 last_gc_was_full_heap: AtomicBool::new(false),
281 }
282 }
283
284 fn requires_full_heap_collection(&self) -> bool {
285 self.gen.requires_full_heap_collection(self)
286 }
287}