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