mmtk/plan/immix/
global.rs1use super::gc_work::ImmixGCWorkContext;
2use super::mutator::ALLOCATOR_MAPPING;
3use crate::plan::global::BasePlan;
4use crate::plan::global::CommonPlan;
5use crate::plan::global::CreateGeneralPlanArgs;
6use crate::plan::global::CreateSpecificPlanArgs;
7use crate::plan::AllocationSemantics;
8use crate::plan::Plan;
9use crate::plan::PlanConstraints;
10use crate::policy::immix::ImmixSpaceArgs;
11use crate::policy::immix::{TRACE_KIND_DEFRAG, TRACE_KIND_FAST};
12use crate::policy::space::Space;
13use crate::scheduler::*;
14use crate::util::alloc::allocators::AllocatorSelector;
15use crate::util::copy::*;
16use crate::util::heap::gc_trigger::SpaceStats;
17use crate::util::heap::VMRequest;
18use crate::util::metadata::log_bit::UnlogBitsOperation;
19use crate::util::metadata::side_metadata::SideMetadataContext;
20use crate::vm::VMBinding;
21use crate::MMTK;
22use crate::{policy::immix::ImmixSpace, util::opaque_pointer::VMWorkerThread};
23use std::sync::atomic::AtomicBool;
24
25use atomic::Ordering;
26use enum_map::EnumMap;
27
28use mmtk_macros::{HasSpaces, PlanTraceObject};
29
30#[derive(HasSpaces, PlanTraceObject)]
31pub struct Immix<VM: VMBinding> {
32 #[post_scan]
33 #[space]
34 #[copy_semantics(CopySemantics::DefaultCopy)]
35 pub immix_space: ImmixSpace<VM>,
36 #[parent]
37 pub common: CommonPlan<VM>,
38 last_gc_was_defrag: AtomicBool,
39}
40
41pub const IMMIX_CONSTRAINTS: PlanConstraints = PlanConstraints {
43 moves_objects: !cfg!(feature = "immix_non_moving"),
45 max_non_los_default_alloc_bytes: crate::policy::immix::MAX_IMMIX_OBJECT_SIZE,
47 ..PlanConstraints::default()
48};
49
50impl<VM: VMBinding> Plan for Immix<VM> {
51 fn collection_required(&self, space_full: bool, _space: Option<SpaceStats<Self::VM>>) -> bool {
52 self.base().collection_required(self, space_full)
53 }
54
55 fn last_collection_was_exhaustive(&self) -> bool {
56 self.immix_space
57 .is_last_gc_exhaustive(self.last_gc_was_defrag.load(Ordering::Relaxed))
58 }
59
60 fn constraints(&self) -> &'static PlanConstraints {
61 &IMMIX_CONSTRAINTS
62 }
63
64 fn create_copy_config(&'static self) -> CopyConfig<Self::VM> {
65 use enum_map::enum_map;
66 CopyConfig {
67 copy_mapping: enum_map! {
68 CopySemantics::DefaultCopy => CopySelector::Immix(0),
69 _ => CopySelector::Unused,
70 },
71 space_mapping: vec![(CopySelector::Immix(0), &self.immix_space)],
72 constraints: &IMMIX_CONSTRAINTS,
73 }
74 }
75
76 fn schedule_collection(&'static self, scheduler: &GCWorkScheduler<VM>) {
77 Self::schedule_immix_full_heap_collection::<
78 Immix<VM>,
79 ImmixGCWorkContext<VM, TRACE_KIND_FAST>,
80 ImmixGCWorkContext<VM, TRACE_KIND_DEFRAG>,
81 >(self, &self.immix_space, scheduler)
82 }
83
84 fn get_allocator_mapping(&self) -> &'static EnumMap<AllocationSemantics, AllocatorSelector> {
85 &ALLOCATOR_MAPPING
86 }
87
88 fn prepare(&mut self, tls: VMWorkerThread) {
89 self.prepare_inner(tls, UnlogBitsOperation::NoOp)
90 }
91
92 fn release(&mut self, tls: VMWorkerThread) {
93 self.release_inner(tls, UnlogBitsOperation::NoOp);
94 }
95
96 fn end_of_pause(&mut self, mmtk: &'static MMTK<VM>, tls: VMWorkerThread) {
97 self.last_gc_was_defrag
98 .store(self.immix_space.end_of_gc(), Ordering::Relaxed);
99 self.common.end_of_pause(tls);
100 mmtk.gc_trigger.policy.on_gc_end(mmtk);
101 }
102
103 fn current_gc_may_move_object(&self) -> bool {
104 self.immix_space.in_defrag()
105 }
106
107 fn get_collection_reserved_pages(&self) -> usize {
108 self.immix_space.defrag_headroom_pages()
109 }
110
111 fn get_used_pages(&self) -> usize {
112 self.immix_space.reserved_pages() + self.common.get_used_pages()
113 }
114
115 fn base(&self) -> &BasePlan<VM> {
116 &self.common.base
117 }
118
119 fn base_mut(&mut self) -> &mut BasePlan<Self::VM> {
120 &mut self.common.base
121 }
122
123 fn common(&self) -> &CommonPlan<VM> {
124 &self.common
125 }
126}
127
128impl<VM: VMBinding> Immix<VM> {
129 pub fn new(args: CreateGeneralPlanArgs<VM>) -> Self {
130 let plan_args = CreateSpecificPlanArgs {
131 global_args: args,
132 constraints: &IMMIX_CONSTRAINTS,
133 global_side_metadata_specs: SideMetadataContext::new_global_specs(&[]),
134 };
135 Self::new_with_args(
136 plan_args,
137 ImmixSpaceArgs {
138 mixed_age: false,
139 never_move_objects: false,
140 },
141 )
142 }
143
144 pub fn new_with_args(
145 mut plan_args: CreateSpecificPlanArgs<VM>,
146 space_args: ImmixSpaceArgs,
147 ) -> Self {
148 Immix {
149 immix_space: ImmixSpace::new(
150 if space_args.mixed_age {
151 plan_args.get_mixed_age_space_args(
152 "immix",
153 true,
154 false,
155 VMRequest::discontiguous(),
156 )
157 } else {
158 plan_args.get_normal_space_args(
159 "immix",
160 true,
161 false,
162 VMRequest::discontiguous(),
163 )
164 },
165 space_args,
166 ),
167 common: CommonPlan::new(plan_args),
168 last_gc_was_defrag: AtomicBool::new(false),
169 }
170 }
171
172 pub(crate) fn schedule_immix_full_heap_collection<
175 PlanType: Plan<VM = VM>,
176 FastContext: GCWorkContext<VM = VM, PlanType = PlanType>,
177 DefragContext: GCWorkContext<VM = VM, PlanType = PlanType>,
178 >(
179 plan: &'static DefragContext::PlanType,
180 immix_space: &ImmixSpace<VM>,
181 scheduler: &GCWorkScheduler<VM>,
182 ) {
183 let in_defrag = immix_space.decide_whether_to_defrag(
184 plan.base().global_state.is_emergency_collection(),
185 true,
186 plan.base()
187 .global_state
188 .cur_collection_attempts
189 .load(Ordering::SeqCst),
190 plan.base().global_state.is_user_triggered_collection(),
191 *plan.base().options.full_heap_system_gc,
192 );
193
194 if in_defrag {
195 scheduler.schedule_common_work::<DefragContext>(plan);
196 } else {
197 scheduler.schedule_common_work::<FastContext>(plan);
198 }
199 }
200
201 pub(in crate::plan) fn set_last_gc_was_defrag(&self, defrag: bool, order: Ordering) {
202 self.last_gc_was_defrag.store(defrag, order)
203 }
204
205 pub(in crate::plan) fn prepare_inner(
208 &mut self,
209 tls: VMWorkerThread,
210 unlog_bits_op: UnlogBitsOperation,
211 ) {
212 self.common.prepare(tls, true);
213 self.immix_space.prepare(
214 true,
215 Some(crate::policy::immix::defrag::StatsForDefrag::new(self)),
216 unlog_bits_op,
217 );
218 }
219
220 pub(in crate::plan) fn release_inner(
223 &mut self,
224 tls: VMWorkerThread,
225 unlog_bits_op: UnlogBitsOperation,
226 ) {
227 self.common.release(tls, true);
228 self.immix_space.release(true, unlog_bits_op);
230 }
231}