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