1use std::mem::MaybeUninit;
2use std::sync::Arc;
3
4use crate::plan::PlanConstraints;
5use crate::policy::copy_context::PolicyCopyContext;
6use crate::policy::copyspace::CopySpace;
7use crate::policy::copyspace::CopySpaceCopyContext;
8use crate::policy::immix::ImmixSpace;
9use crate::policy::immix::{ImmixCopyContext, ImmixHybridCopyContext};
10use crate::policy::space::Space;
11use crate::util::object_forwarding;
12use crate::util::opaque_pointer::VMWorkerThread;
13use crate::util::{Address, ObjectReference};
14use crate::vm::ObjectModel;
15use crate::vm::VMBinding;
16use crate::MMTK;
17
18use enum_map::Enum;
19use enum_map::EnumMap;
20
21use super::alloc::allocator::AllocatorContext;
22
23const MAX_COPYSPACE_COPY_ALLOCATORS: usize = 1;
24const MAX_IMMIX_COPY_ALLOCATORS: usize = 1;
25const MAX_IMMIX_HYBRID_COPY_ALLOCATORS: usize = 1;
26
27type CopySpaceMapping<VM> = Vec<(CopySelector, &'static dyn Space<VM>)>;
28
29pub struct CopyConfig<VM: VMBinding> {
33 pub(crate) copy_mapping: EnumMap<CopySemantics, CopySelector>,
35 pub(crate) space_mapping: CopySpaceMapping<VM>,
37 pub(crate) constraints: &'static PlanConstraints,
40}
41
42impl<VM: VMBinding> Default for CopyConfig<VM> {
43 fn default() -> Self {
44 CopyConfig {
45 copy_mapping: EnumMap::default(),
46 space_mapping: vec![],
47 constraints: &crate::plan::DEFAULT_PLAN_CONSTRAINTS,
48 }
49 }
50}
51
52pub struct GCWorkerCopyContext<VM: VMBinding> {
55 pub copy: [MaybeUninit<CopySpaceCopyContext<VM>>; MAX_COPYSPACE_COPY_ALLOCATORS],
57 pub immix: [MaybeUninit<ImmixCopyContext<VM>>; MAX_IMMIX_COPY_ALLOCATORS],
59 pub immix_hybrid: [MaybeUninit<ImmixHybridCopyContext<VM>>; MAX_IMMIX_HYBRID_COPY_ALLOCATORS],
61 config: CopyConfig<VM>,
63}
64
65impl<VM: VMBinding> GCWorkerCopyContext<VM> {
66 pub fn alloc_copy(
76 &mut self,
77 original: ObjectReference,
78 bytes: usize,
79 align: usize,
80 offset: usize,
81 semantics: CopySemantics,
82 ) -> Address {
83 #[cfg(debug_assertions)]
84 if bytes > self.config.constraints.max_non_los_default_alloc_bytes {
85 warn!(
86 "Attempted to copy an object of {} bytes (> {}) which should be allocated with LOS and not be copied.",
87 bytes, self.config.constraints.max_non_los_default_alloc_bytes
88 );
89 }
90 match self.config.copy_mapping[semantics] {
91 CopySelector::CopySpace(index) => {
92 unsafe { self.copy[index as usize].assume_init_mut() }
93 .alloc_copy(original, bytes, align, offset)
94 }
95 CopySelector::Immix(index) => unsafe { self.immix[index as usize].assume_init_mut() }
96 .alloc_copy(original, bytes, align, offset),
97 CopySelector::ImmixHybrid(index) => {
98 unsafe { self.immix_hybrid[index as usize].assume_init_mut() }
99 .alloc_copy(original, bytes, align, offset)
100 }
101 CopySelector::Unused => unreachable!(),
102 }
103 }
104
105 pub fn post_copy(&mut self, object: ObjectReference, bytes: usize, semantics: CopySemantics) {
112 if VM::VMObjectModel::LOCAL_FORWARDING_BITS_SPEC.is_in_header() {
113 object_forwarding::clear_forwarding_bits::<VM>(object);
115 } else {
116 debug_assert!(!object_forwarding::is_forwarded_or_being_forwarded::<VM>(
118 object
119 ));
120 }
121 match self.config.copy_mapping[semantics] {
123 CopySelector::CopySpace(index) => {
124 unsafe { self.copy[index as usize].assume_init_mut() }.post_copy(object, bytes)
125 }
126 CopySelector::Immix(index) => {
127 unsafe { self.immix[index as usize].assume_init_mut() }.post_copy(object, bytes)
128 }
129 CopySelector::ImmixHybrid(index) => {
130 unsafe { self.immix_hybrid[index as usize].assume_init_mut() }
131 .post_copy(object, bytes)
132 }
133 CopySelector::Unused => unreachable!(),
134 }
135 }
136
137 pub fn prepare(&mut self) {
139 for (_, selector) in self.config.copy_mapping.iter() {
141 match selector {
142 CopySelector::CopySpace(index) => {
143 unsafe { self.copy[*index as usize].assume_init_mut() }.prepare()
144 }
145 CopySelector::Immix(index) => {
146 unsafe { self.immix[*index as usize].assume_init_mut() }.prepare()
147 }
148 CopySelector::ImmixHybrid(index) => {
149 unsafe { self.immix_hybrid[*index as usize].assume_init_mut() }.prepare()
150 }
151 CopySelector::Unused => {}
152 }
153 }
154 }
155
156 pub fn release(&mut self) {
158 for (_, selector) in self.config.copy_mapping.iter() {
160 match selector {
161 CopySelector::CopySpace(index) => {
162 unsafe { self.copy[*index as usize].assume_init_mut() }.release()
163 }
164 CopySelector::Immix(index) => {
165 unsafe { self.immix[*index as usize].assume_init_mut() }.release()
166 }
167 CopySelector::ImmixHybrid(index) => {
168 unsafe { self.immix_hybrid[*index as usize].assume_init_mut() }.release()
169 }
170 CopySelector::Unused => {}
171 }
172 }
173 }
174
175 pub fn new(worker_tls: VMWorkerThread, mmtk: &MMTK<VM>, config: CopyConfig<VM>) -> Self {
182 let mut ret = GCWorkerCopyContext {
183 copy: unsafe { MaybeUninit::uninit().assume_init() },
184 immix: unsafe { MaybeUninit::uninit().assume_init() },
185 immix_hybrid: unsafe { MaybeUninit::uninit().assume_init() },
186 config,
187 };
188 let context = Arc::new(AllocatorContext::new(mmtk));
189
190 for &(selector, space) in ret.config.space_mapping.iter() {
192 match selector {
193 CopySelector::CopySpace(index) => {
194 ret.copy[index as usize].write(CopySpaceCopyContext::new(
195 worker_tls,
196 context.clone(),
197 space.downcast_ref::<CopySpace<VM>>().unwrap(),
198 ));
199 }
200 CopySelector::Immix(index) => {
201 ret.immix[index as usize].write(ImmixCopyContext::new(
202 worker_tls,
203 context.clone(),
204 space.downcast_ref::<ImmixSpace<VM>>().unwrap(),
205 ));
206 }
207 CopySelector::ImmixHybrid(index) => {
208 ret.immix_hybrid[index as usize].write(ImmixHybridCopyContext::new(
209 worker_tls,
210 context.clone(),
211 space.downcast_ref::<ImmixSpace<VM>>().unwrap(),
212 ));
213 }
214 CopySelector::Unused => unreachable!(),
215 }
216 }
217
218 ret
219 }
220
221 pub fn new_non_copy() -> Self {
223 GCWorkerCopyContext {
224 copy: unsafe { MaybeUninit::uninit().assume_init() },
225 immix: unsafe { MaybeUninit::uninit().assume_init() },
226 immix_hybrid: unsafe { MaybeUninit::uninit().assume_init() },
227 config: CopyConfig::default(),
228 }
229 }
230}
231
232#[derive(Clone, Copy, Enum, Debug)]
238pub enum CopySemantics {
239 DefaultCopy,
241 Nursery,
243 PromoteToMature,
245 Mature,
247}
248
249impl CopySemantics {
250 pub fn is_mature(&self) -> bool {
252 matches!(self, CopySemantics::PromoteToMature | CopySemantics::Mature)
253 }
254}
255
256#[repr(C, u8)]
257#[derive(Copy, Clone, Debug, Default)]
258pub(crate) enum CopySelector {
259 CopySpace(u8),
260 Immix(u8),
261 ImmixHybrid(u8),
262 #[default]
263 Unused,
264}