1use crate::plan::barriers::Barrier;
4use crate::plan::global::Plan;
5use crate::plan::AllocationSemantics;
6use crate::policy::space::Space;
7use crate::util::alloc::allocator::AllocationOptions;
8use crate::util::alloc::allocators::{AllocatorSelector, Allocators};
9use crate::util::alloc::Allocator;
10use crate::util::{Address, ObjectReference};
11use crate::util::{VMMutatorThread, VMWorkerThread};
12use crate::vm::VMBinding;
13use crate::MMTK;
14
15use enum_map::EnumMap;
16
17use super::barriers::NoBarrier;
18
19pub(crate) type SpaceMapping<VM> = Vec<(AllocatorSelector, &'static dyn Space<VM>)>;
20
21pub(crate) fn unreachable_prepare_func<VM: VMBinding>(
25 _mutator: &mut Mutator<VM>,
26 _tls: VMWorkerThread,
27) {
28 unreachable!("`MutatorConfig::prepare_func` must not be called for the current plan.")
29}
30
31#[allow(unused_variables)]
33pub(crate) fn common_prepare_func<VM: VMBinding>(mutator: &mut Mutator<VM>, _tls: VMWorkerThread) {
34 #[cfg(feature = "marksweep_as_nonmoving")]
36 unsafe {
37 mutator.allocator_impl_mut_for_semantic::<crate::util::alloc::FreeListAllocator<VM>>(
38 AllocationSemantics::NonMoving,
39 )
40 }
41 .prepare();
42}
43
44pub(crate) fn unreachable_release_func<VM: VMBinding>(
47 _mutator: &mut Mutator<VM>,
48 _tls: VMWorkerThread,
49) {
50 unreachable!("`MutatorConfig::release_func` must not be called for the current plan.")
51}
52
53#[allow(unused_variables)]
55pub(crate) fn common_release_func<VM: VMBinding>(mutator: &mut Mutator<VM>, _tls: VMWorkerThread) {
56 cfg_if::cfg_if! {
57 if #[cfg(feature = "marksweep_as_nonmoving")] {
58 unsafe { mutator.allocator_impl_mut_for_semantic::<crate::util::alloc::FreeListAllocator<VM>>(
60 AllocationSemantics::NonMoving,
61 )}.release();
62 } else if #[cfg(feature = "immortal_as_nonmoving")] {
63 } else {
65 unsafe { mutator.allocator_impl_mut_for_semantic::<crate::util::alloc::ImmixAllocator<VM>>(
67 AllocationSemantics::NonMoving,
68 )}.reset();
69 }
70 }
71}
72
73#[allow(dead_code)]
75pub(crate) fn no_op_release_func<VM: VMBinding>(_mutator: &mut Mutator<VM>, _tls: VMWorkerThread) {}
76
77#[repr(C)]
80pub struct MutatorConfig<VM: VMBinding> {
81 pub allocator_mapping: &'static EnumMap<AllocationSemantics, AllocatorSelector>,
83 #[allow(clippy::box_collection)]
86 pub space_mapping: Box<SpaceMapping<VM>>,
87 pub prepare_func: &'static (dyn Fn(&mut Mutator<VM>, VMWorkerThread) + Send + Sync),
89 pub release_func: &'static (dyn Fn(&mut Mutator<VM>, VMWorkerThread) + Send + Sync),
91}
92
93impl<VM: VMBinding> std::fmt::Debug for MutatorConfig<VM> {
94 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95 f.write_str("MutatorConfig:\n")?;
96 f.write_str("Semantics mapping:\n")?;
97 for (semantic, selector) in self.allocator_mapping.iter() {
98 let space_name: &str = match self
99 .space_mapping
100 .iter()
101 .find(|(selector_to_find, _)| selector_to_find == selector)
102 {
103 Some((_, space)) => space.name(),
104 None => "!!!missing space here!!!",
105 };
106 f.write_fmt(format_args!(
107 "- {:?} = {:?} ({:?})\n",
108 semantic, selector, space_name
109 ))?;
110 }
111 f.write_str("Space mapping:\n")?;
112 for (selector, space) in self.space_mapping.iter() {
113 f.write_fmt(format_args!("- {:?} = {:?}\n", selector, space.name()))?;
114 }
115 Ok(())
116 }
117}
118
119pub struct MutatorBuilder<VM: VMBinding> {
121 barrier: Box<dyn Barrier<VM>>,
122 mutator_tls: VMMutatorThread,
124 mmtk: &'static MMTK<VM>,
125 config: MutatorConfig<VM>,
126}
127
128impl<VM: VMBinding> MutatorBuilder<VM> {
129 pub fn new(
130 mutator_tls: VMMutatorThread,
131 mmtk: &'static MMTK<VM>,
132 config: MutatorConfig<VM>,
133 ) -> Self {
134 MutatorBuilder {
135 barrier: Box::new(NoBarrier),
136 mutator_tls,
137 mmtk,
138 config,
139 }
140 }
141
142 pub fn barrier(mut self, barrier: Box<dyn Barrier<VM>>) -> Self {
143 self.barrier = barrier;
144 self
145 }
146
147 pub fn build(self) -> Mutator<VM> {
148 Mutator {
149 allocators: Allocators::<VM>::new(
150 self.mutator_tls,
151 self.mmtk,
152 &self.config.space_mapping,
153 ),
154 barrier: self.barrier,
155 mutator_tls: self.mutator_tls,
156 plan: self.mmtk.get_plan(),
157 config: self.config,
158 }
159 }
160}
161
162#[repr(C)]
170pub struct Mutator<VM: VMBinding> {
171 pub(crate) allocators: Allocators<VM>,
172 pub barrier: Box<dyn Barrier<VM>>,
174 pub mutator_tls: VMMutatorThread,
176 pub(crate) plan: &'static dyn Plan<VM = VM>,
177 pub(crate) config: MutatorConfig<VM>,
178}
179
180impl<VM: VMBinding> MutatorContext<VM> for Mutator<VM> {
181 fn prepare(&mut self, tls: VMWorkerThread) {
182 (*self.config.prepare_func)(self, tls)
183 }
184 fn release(&mut self, tls: VMWorkerThread) {
185 (*self.config.release_func)(self, tls)
186 }
187
188 fn alloc(
190 &mut self,
191 size: usize,
192 align: usize,
193 offset: usize,
194 allocator: AllocationSemantics,
195 ) -> Address {
196 let allocator = unsafe {
197 self.allocators
198 .get_allocator_mut(self.config.allocator_mapping[allocator])
199 };
200 debug_assert!(allocator.get_context().get_alloc_options().is_default());
202 allocator.alloc(size, align, offset)
203 }
204
205 fn alloc_with_options(
206 &mut self,
207 size: usize,
208 align: usize,
209 offset: usize,
210 allocator: AllocationSemantics,
211 options: AllocationOptions,
212 ) -> Address {
213 let allocator = unsafe {
214 self.allocators
215 .get_allocator_mut(self.config.allocator_mapping[allocator])
216 };
217 debug_assert!(allocator.get_context().get_alloc_options().is_default());
219 allocator.alloc_with_options(size, align, offset, options)
220 }
221
222 fn alloc_slow(
223 &mut self,
224 size: usize,
225 align: usize,
226 offset: usize,
227 allocator: AllocationSemantics,
228 ) -> Address {
229 let allocator = unsafe {
230 self.allocators
231 .get_allocator_mut(self.config.allocator_mapping[allocator])
232 };
233 debug_assert!(allocator.get_context().get_alloc_options().is_default());
235 allocator.alloc_slow(size, align, offset)
236 }
237
238 fn alloc_slow_with_options(
239 &mut self,
240 size: usize,
241 align: usize,
242 offset: usize,
243 allocator: AllocationSemantics,
244 options: AllocationOptions,
245 ) -> Address {
246 let allocator = unsafe {
247 self.allocators
248 .get_allocator_mut(self.config.allocator_mapping[allocator])
249 };
250 debug_assert!(allocator.get_context().get_alloc_options().is_default());
252 allocator.alloc_slow_with_options(size, align, offset, options)
253 }
254
255 fn post_alloc(&mut self, refer: ObjectReference, bytes: usize, allocator: AllocationSemantics) {
257 unsafe {
258 self.allocators
259 .get_allocator_mut(self.config.allocator_mapping[allocator])
260 }
261 .get_space()
262 .initialize_object_metadata(refer, bytes)
263 }
264
265 fn get_tls(&self) -> VMMutatorThread {
266 self.mutator_tls
267 }
268
269 fn barrier(&mut self) -> &mut dyn Barrier<VM> {
270 &mut *self.barrier
271 }
272}
273
274impl<VM: VMBinding> Mutator<VM> {
275 fn get_all_allocator_selectors(&self) -> Vec<AllocatorSelector> {
277 use itertools::Itertools;
278 self.config
279 .allocator_mapping
280 .iter()
281 .map(|(_, selector)| *selector)
282 .sorted()
283 .dedup()
284 .filter(|selector| *selector != AllocatorSelector::None)
285 .collect()
286 }
287
288 pub fn on_destroy(&mut self) {
290 for selector in self.get_all_allocator_selectors() {
291 unsafe { self.allocators.get_allocator_mut(selector) }.on_mutator_destroy();
292 }
293 }
294
295 pub unsafe fn allocator(&self, selector: AllocatorSelector) -> &dyn Allocator<VM> {
301 self.allocators.get_allocator(selector)
302 }
303
304 pub unsafe fn allocator_mut(&mut self, selector: AllocatorSelector) -> &mut dyn Allocator<VM> {
310 self.allocators.get_allocator_mut(selector)
311 }
312
313 pub unsafe fn allocator_impl<T: Allocator<VM>>(&self, selector: AllocatorSelector) -> &T {
319 self.allocators.get_typed_allocator(selector)
320 }
321
322 pub unsafe fn allocator_impl_mut<T: Allocator<VM>>(
328 &mut self,
329 selector: AllocatorSelector,
330 ) -> &mut T {
331 self.allocators.get_typed_allocator_mut(selector)
332 }
333
334 pub unsafe fn allocator_impl_for_semantic<T: Allocator<VM>>(
339 &self,
340 semantic: AllocationSemantics,
341 ) -> &T {
342 self.allocator_impl::<T>(self.config.allocator_mapping[semantic])
343 }
344
345 pub unsafe fn allocator_impl_mut_for_semantic<T: Allocator<VM>>(
350 &mut self,
351 semantic: AllocationSemantics,
352 ) -> &mut T {
353 self.allocator_impl_mut::<T>(self.config.allocator_mapping[semantic])
354 }
355
356 pub fn get_allocator_base_offset(selector: AllocatorSelector) -> usize {
358 use crate::util::alloc::*;
359 use std::mem::{offset_of, size_of};
360 offset_of!(Mutator<VM>, allocators)
361 + match selector {
362 AllocatorSelector::BumpPointer(index) => {
363 offset_of!(Allocators<VM>, bump_pointer)
364 + size_of::<BumpAllocator<VM>>() * index as usize
365 }
366 AllocatorSelector::FreeList(index) => {
367 offset_of!(Allocators<VM>, free_list)
368 + size_of::<FreeListAllocator<VM>>() * index as usize
369 }
370 AllocatorSelector::Immix(index) => {
371 offset_of!(Allocators<VM>, immix)
372 + size_of::<ImmixAllocator<VM>>() * index as usize
373 }
374 AllocatorSelector::LargeObject(index) => {
375 offset_of!(Allocators<VM>, large_object)
376 + size_of::<LargeObjectAllocator<VM>>() * index as usize
377 }
378 AllocatorSelector::Malloc(index) => {
379 offset_of!(Allocators<VM>, malloc)
380 + size_of::<MallocAllocator<VM>>() * index as usize
381 }
382 AllocatorSelector::MarkCompact(index) => {
383 offset_of!(Allocators<VM>, markcompact)
384 + size_of::<MarkCompactAllocator<VM>>() * index as usize
385 }
386 AllocatorSelector::None => panic!("Expect a valid AllocatorSelector, found None"),
387 }
388 }
389}
390
391pub trait MutatorContext<VM: VMBinding>: Send + 'static {
396 fn prepare(&mut self, tls: VMWorkerThread);
398 fn release(&mut self, tls: VMWorkerThread);
400 fn alloc(
408 &mut self,
409 size: usize,
410 align: usize,
411 offset: usize,
412 allocator: AllocationSemantics,
413 ) -> Address;
414 fn alloc_with_options(
423 &mut self,
424 size: usize,
425 align: usize,
426 offset: usize,
427 allocator: AllocationSemantics,
428 options: AllocationOptions,
429 ) -> Address;
430 fn alloc_slow(
436 &mut self,
437 size: usize,
438 align: usize,
439 offset: usize,
440 allocator: AllocationSemantics,
441 ) -> Address;
442 fn alloc_slow_with_options(
448 &mut self,
449 size: usize,
450 align: usize,
451 offset: usize,
452 allocator: AllocationSemantics,
453 options: AllocationOptions,
454 ) -> Address;
455 fn post_alloc(&mut self, refer: ObjectReference, bytes: usize, allocator: AllocationSemantics);
463 fn flush_remembered_sets(&mut self) {
465 self.barrier().flush();
466 }
467 fn flush(&mut self) {
469 self.flush_remembered_sets();
470 }
471 fn get_tls(&self) -> VMMutatorThread;
474 fn barrier(&mut self) -> &mut dyn Barrier<VM>;
476}
477
478#[allow(dead_code)]
485#[derive(Default)]
486pub(crate) struct ReservedAllocators {
487 pub n_bump_pointer: u8,
488 pub n_large_object: u8,
489 pub n_malloc: u8,
490 pub n_immix: u8,
491 pub n_mark_compact: u8,
492 pub n_free_list: u8,
493}
494
495impl ReservedAllocators {
496 pub const DEFAULT: Self = ReservedAllocators {
497 n_bump_pointer: 0,
498 n_large_object: 0,
499 n_malloc: 0,
500 n_immix: 0,
501 n_mark_compact: 0,
502 n_free_list: 0,
503 };
504 fn validate(&self) {
506 use crate::util::alloc::allocators::*;
507 assert!(
508 self.n_bump_pointer as usize <= MAX_BUMP_ALLOCATORS,
509 "Allocator mapping declared more bump pointer allocators than the max allowed."
510 );
511 assert!(
512 self.n_large_object as usize <= MAX_LARGE_OBJECT_ALLOCATORS,
513 "Allocator mapping declared more large object allocators than the max allowed."
514 );
515 assert!(
516 self.n_malloc as usize <= MAX_MALLOC_ALLOCATORS,
517 "Allocator mapping declared more malloc allocators than the max allowed."
518 );
519 assert!(
520 self.n_immix as usize <= MAX_IMMIX_ALLOCATORS,
521 "Allocator mapping declared more immix allocators than the max allowed."
522 );
523 assert!(
524 self.n_mark_compact as usize <= MAX_MARK_COMPACT_ALLOCATORS,
525 "Allocator mapping declared more mark compact allocators than the max allowed."
526 );
527 assert!(
528 self.n_free_list as usize <= MAX_FREE_LIST_ALLOCATORS,
529 "Allocator mapping declared more free list allocators than the max allowed."
530 );
531 }
532
533 fn add_bump_pointer_allocator(&mut self) -> AllocatorSelector {
536 let selector = AllocatorSelector::BumpPointer(self.n_bump_pointer);
537 self.n_bump_pointer += 1;
538 selector
539 }
540 fn add_large_object_allocator(&mut self) -> AllocatorSelector {
541 let selector = AllocatorSelector::LargeObject(self.n_large_object);
542 self.n_large_object += 1;
543 selector
544 }
545 #[allow(dead_code)]
546 fn add_malloc_allocator(&mut self) -> AllocatorSelector {
547 let selector = AllocatorSelector::Malloc(self.n_malloc);
548 self.n_malloc += 1;
549 selector
550 }
551 #[allow(dead_code)]
552 fn add_immix_allocator(&mut self) -> AllocatorSelector {
553 let selector = AllocatorSelector::Immix(self.n_immix);
554 self.n_immix += 1;
555 selector
556 }
557 #[allow(dead_code)]
558 fn add_mark_compact_allocator(&mut self) -> AllocatorSelector {
559 let selector = AllocatorSelector::MarkCompact(self.n_mark_compact);
560 self.n_mark_compact += 1;
561 selector
562 }
563 #[allow(dead_code)]
564 fn add_free_list_allocator(&mut self) -> AllocatorSelector {
565 let selector = AllocatorSelector::FreeList(self.n_free_list);
566 self.n_free_list += 1;
567 selector
568 }
569}
570
571pub(crate) fn create_allocator_mapping(
577 mut reserved: ReservedAllocators,
578 include_common_plan: bool,
579) -> EnumMap<AllocationSemantics, AllocatorSelector> {
580 let mut map = EnumMap::<AllocationSemantics, AllocatorSelector>::default();
585
586 #[cfg(feature = "code_space")]
589 {
590 map[AllocationSemantics::Code] = reserved.add_bump_pointer_allocator();
591 map[AllocationSemantics::LargeCode] = reserved.add_bump_pointer_allocator();
592 }
593
594 #[cfg(feature = "ro_space")]
595 {
596 map[AllocationSemantics::ReadOnly] = reserved.add_bump_pointer_allocator();
597 }
598
599 if include_common_plan {
602 map[AllocationSemantics::Immortal] = reserved.add_bump_pointer_allocator();
603 map[AllocationSemantics::Los] = reserved.add_large_object_allocator();
604 map[AllocationSemantics::NonMoving] = if cfg!(feature = "marksweep_as_nonmoving") {
605 reserved.add_free_list_allocator()
606 } else if cfg!(feature = "immortal_as_nonmoving") {
607 reserved.add_bump_pointer_allocator()
608 } else {
609 reserved.add_immix_allocator()
610 };
611 }
612
613 reserved.validate();
614 map
615}
616
617pub(crate) fn create_space_mapping<VM: VMBinding>(
624 mut reserved: ReservedAllocators,
625 include_common_plan: bool,
626 plan: &'static dyn Plan<VM = VM>,
627) -> Vec<(AllocatorSelector, &'static dyn Space<VM>)> {
628 let mut vec: Vec<(AllocatorSelector, &'static dyn Space<VM>)> = vec![];
633
634 #[cfg(feature = "code_space")]
637 {
638 vec.push((
639 reserved.add_bump_pointer_allocator(),
640 &plan.base().code_space,
641 ));
642 vec.push((
643 reserved.add_bump_pointer_allocator(),
644 &plan.base().code_lo_space,
645 ));
646 }
647
648 #[cfg(feature = "ro_space")]
649 vec.push((reserved.add_bump_pointer_allocator(), &plan.base().ro_space));
650
651 if include_common_plan {
654 vec.push((
655 reserved.add_bump_pointer_allocator(),
656 plan.common().get_immortal(),
657 ));
658 vec.push((
659 reserved.add_large_object_allocator(),
660 plan.common().get_los(),
661 ));
662 vec.push((
663 if cfg!(feature = "marksweep_as_nonmoving") {
664 reserved.add_free_list_allocator()
665 } else if cfg!(feature = "immortal_as_nonmoving") {
666 reserved.add_bump_pointer_allocator()
667 } else {
668 reserved.add_immix_allocator()
669 },
670 plan.common().get_nonmoving(),
671 ));
672 }
673
674 reserved.validate();
675 vec
676}