1use std::mem::{offset_of, MaybeUninit};
2use std::sync::Arc;
3
4use crate::policy::largeobjectspace::LargeObjectSpace;
5use crate::policy::marksweepspace::malloc_ms::MallocSpace;
6use crate::policy::marksweepspace::native_ms::MarkSweepSpace;
7use crate::policy::space::Space;
8use crate::util::alloc::LargeObjectAllocator;
9use crate::util::alloc::MallocAllocator;
10use crate::util::alloc::{Allocator, BumpAllocator, ImmixAllocator};
11use crate::util::VMMutatorThread;
12use crate::vm::VMBinding;
13use crate::Mutator;
14use crate::MMTK;
15
16use super::allocator::AllocatorContext;
17use super::FreeListAllocator;
18use super::MarkCompactAllocator;
19
20pub(crate) const MAX_BUMP_ALLOCATORS: usize = 6;
21pub(crate) const MAX_LARGE_OBJECT_ALLOCATORS: usize = 2;
22pub(crate) const MAX_MALLOC_ALLOCATORS: usize = 1;
23pub(crate) const MAX_IMMIX_ALLOCATORS: usize = 2;
24pub(crate) const MAX_FREE_LIST_ALLOCATORS: usize = 2;
25pub(crate) const MAX_MARK_COMPACT_ALLOCATORS: usize = 1;
26
27#[repr(C)]
32pub struct Allocators<VM: VMBinding> {
33 pub bump_pointer: [MaybeUninit<BumpAllocator<VM>>; MAX_BUMP_ALLOCATORS],
34 pub large_object: [MaybeUninit<LargeObjectAllocator<VM>>; MAX_LARGE_OBJECT_ALLOCATORS],
35 pub malloc: [MaybeUninit<MallocAllocator<VM>>; MAX_MALLOC_ALLOCATORS],
36 pub immix: [MaybeUninit<ImmixAllocator<VM>>; MAX_IMMIX_ALLOCATORS],
37 pub free_list: [MaybeUninit<FreeListAllocator<VM>>; MAX_FREE_LIST_ALLOCATORS],
38 pub markcompact: [MaybeUninit<MarkCompactAllocator<VM>>; MAX_MARK_COMPACT_ALLOCATORS],
39}
40
41impl<VM: VMBinding> Allocators<VM> {
42 pub unsafe fn get_allocator(&self, selector: AllocatorSelector) -> &dyn Allocator<VM> {
45 match selector {
46 AllocatorSelector::BumpPointer(index) => {
47 self.bump_pointer[index as usize].assume_init_ref()
48 }
49 AllocatorSelector::LargeObject(index) => {
50 self.large_object[index as usize].assume_init_ref()
51 }
52 AllocatorSelector::Malloc(index) => self.malloc[index as usize].assume_init_ref(),
53 AllocatorSelector::Immix(index) => self.immix[index as usize].assume_init_ref(),
54 AllocatorSelector::FreeList(index) => self.free_list[index as usize].assume_init_ref(),
55 AllocatorSelector::MarkCompact(index) => {
56 self.markcompact[index as usize].assume_init_ref()
57 }
58 AllocatorSelector::None => panic!("Allocator mapping is not initialized"),
59 }
60 }
61
62 pub unsafe fn get_typed_allocator<T: Allocator<VM>>(&self, selector: AllocatorSelector) -> &T {
65 self.get_allocator(selector).downcast_ref().unwrap()
66 }
67
68 pub unsafe fn get_allocator_mut(
71 &mut self,
72 selector: AllocatorSelector,
73 ) -> &mut dyn Allocator<VM> {
74 match selector {
75 AllocatorSelector::BumpPointer(index) => {
76 self.bump_pointer[index as usize].assume_init_mut()
77 }
78 AllocatorSelector::LargeObject(index) => {
79 self.large_object[index as usize].assume_init_mut()
80 }
81 AllocatorSelector::Malloc(index) => self.malloc[index as usize].assume_init_mut(),
82 AllocatorSelector::Immix(index) => self.immix[index as usize].assume_init_mut(),
83 AllocatorSelector::FreeList(index) => self.free_list[index as usize].assume_init_mut(),
84 AllocatorSelector::MarkCompact(index) => {
85 self.markcompact[index as usize].assume_init_mut()
86 }
87 AllocatorSelector::None => panic!("Allocator mapping is not initialized"),
88 }
89 }
90
91 pub unsafe fn get_typed_allocator_mut<T: Allocator<VM>>(
94 &mut self,
95 selector: AllocatorSelector,
96 ) -> &mut T {
97 self.get_allocator_mut(selector).downcast_mut().unwrap()
98 }
99
100 pub fn new(
101 mutator_tls: VMMutatorThread,
102 mmtk: &MMTK<VM>,
103 space_mapping: &[(AllocatorSelector, &'static dyn Space<VM>)],
104 ) -> Self {
105 let mut ret = Allocators {
106 bump_pointer: unsafe { MaybeUninit::uninit().assume_init() },
107 large_object: unsafe { MaybeUninit::uninit().assume_init() },
108 malloc: unsafe { MaybeUninit::uninit().assume_init() },
109 immix: unsafe { MaybeUninit::uninit().assume_init() },
110 free_list: unsafe { MaybeUninit::uninit().assume_init() },
111 markcompact: unsafe { MaybeUninit::uninit().assume_init() },
112 };
113 let context = Arc::new(AllocatorContext::new(mmtk));
114
115 for &(selector, space) in space_mapping.iter() {
116 match selector {
117 AllocatorSelector::BumpPointer(index) => {
118 ret.bump_pointer[index as usize].write(BumpAllocator::new(
119 mutator_tls.0,
120 space,
121 context.clone(),
122 ));
123 }
124 AllocatorSelector::LargeObject(index) => {
125 ret.large_object[index as usize].write(LargeObjectAllocator::new(
126 mutator_tls.0,
127 space.downcast_ref::<LargeObjectSpace<VM>>().unwrap(),
128 context.clone(),
129 ));
130 }
131 AllocatorSelector::Malloc(index) => {
132 ret.malloc[index as usize].write(MallocAllocator::new(
133 mutator_tls.0,
134 space.downcast_ref::<MallocSpace<VM>>().unwrap(),
135 context.clone(),
136 ));
137 }
138 AllocatorSelector::Immix(index) => {
139 ret.immix[index as usize].write(ImmixAllocator::new(
140 mutator_tls.0,
141 Some(space),
142 context.clone(),
143 false,
144 ));
145 }
146 AllocatorSelector::FreeList(index) => {
147 ret.free_list[index as usize].write(FreeListAllocator::new(
148 mutator_tls.0,
149 space.downcast_ref::<MarkSweepSpace<VM>>().unwrap(),
150 context.clone(),
151 ));
152 }
153 AllocatorSelector::MarkCompact(index) => {
154 ret.markcompact[index as usize].write(MarkCompactAllocator::new(
155 mutator_tls.0,
156 space,
157 context.clone(),
158 ));
159 }
160 AllocatorSelector::None => panic!("Allocator mapping is not initialized"),
161 }
162 }
163
164 ret
165 }
166}
167
168#[repr(C, u8)]
182#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
183pub enum AllocatorSelector {
184 BumpPointer(u8),
186 LargeObject(u8),
188 Malloc(u8),
190 Immix(u8),
192 MarkCompact(u8),
194 FreeList(u8),
196 #[default]
198 None,
199}
200
201#[repr(C, u8)]
204#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
205pub enum AllocatorInfo {
206 BumpPointer {
208 bump_pointer_offset: usize,
210 },
211 Unimplemented,
214 #[default]
216 None,
217}
218
219impl AllocatorInfo {
220 pub fn new<VM: VMBinding>(selector: AllocatorSelector) -> AllocatorInfo {
226 let base_offset = Mutator::<VM>::get_allocator_base_offset(selector);
227 match selector {
228 AllocatorSelector::BumpPointer(_) => {
229 let bump_pointer_offset = offset_of!(BumpAllocator<VM>, bump_pointer);
230
231 AllocatorInfo::BumpPointer {
232 bump_pointer_offset: base_offset + bump_pointer_offset,
233 }
234 }
235
236 AllocatorSelector::Immix(_) => {
237 let bump_pointer_offset = offset_of!(ImmixAllocator<VM>, bump_pointer);
238
239 AllocatorInfo::BumpPointer {
240 bump_pointer_offset: base_offset + bump_pointer_offset,
241 }
242 }
243
244 AllocatorSelector::MarkCompact(_) => {
245 let bump_offset =
246 base_offset + offset_of!(MarkCompactAllocator<VM>, bump_allocator);
247 let bump_pointer_offset = offset_of!(BumpAllocator<VM>, bump_pointer);
248
249 AllocatorInfo::BumpPointer {
250 bump_pointer_offset: bump_offset + bump_pointer_offset,
251 }
252 }
253
254 AllocatorSelector::FreeList(_) => AllocatorInfo::Unimplemented,
255 _ => AllocatorInfo::None,
256 }
257 }
258}