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::Lisp2Allocator;
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_LISP2_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 lisp2: [MaybeUninit<Lisp2Allocator<VM>>; MAX_LISP2_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::Lisp2(index) => self.lisp2[index as usize].assume_init_ref(),
56 AllocatorSelector::None => panic!("Allocator mapping is not initialized"),
57 }
58 }
59
60 pub unsafe fn get_typed_allocator<T: Allocator<VM>>(&self, selector: AllocatorSelector) -> &T {
63 self.get_allocator(selector).downcast_ref().unwrap()
64 }
65
66 pub unsafe fn get_allocator_mut(
69 &mut self,
70 selector: AllocatorSelector,
71 ) -> &mut dyn Allocator<VM> {
72 match selector {
73 AllocatorSelector::BumpPointer(index) => {
74 self.bump_pointer[index as usize].assume_init_mut()
75 }
76 AllocatorSelector::LargeObject(index) => {
77 self.large_object[index as usize].assume_init_mut()
78 }
79 AllocatorSelector::Malloc(index) => self.malloc[index as usize].assume_init_mut(),
80 AllocatorSelector::Immix(index) => self.immix[index as usize].assume_init_mut(),
81 AllocatorSelector::FreeList(index) => self.free_list[index as usize].assume_init_mut(),
82 AllocatorSelector::Lisp2(index) => self.lisp2[index as usize].assume_init_mut(),
83 AllocatorSelector::None => panic!("Allocator mapping is not initialized"),
84 }
85 }
86
87 pub unsafe fn get_typed_allocator_mut<T: Allocator<VM>>(
90 &mut self,
91 selector: AllocatorSelector,
92 ) -> &mut T {
93 self.get_allocator_mut(selector).downcast_mut().unwrap()
94 }
95
96 pub fn new(
97 mutator_tls: VMMutatorThread,
98 mmtk: &MMTK<VM>,
99 space_mapping: &[(AllocatorSelector, &'static dyn Space<VM>)],
100 ) -> Self {
101 let mut ret = Allocators {
102 bump_pointer: unsafe { MaybeUninit::uninit().assume_init() },
103 large_object: unsafe { MaybeUninit::uninit().assume_init() },
104 malloc: unsafe { MaybeUninit::uninit().assume_init() },
105 immix: unsafe { MaybeUninit::uninit().assume_init() },
106 free_list: unsafe { MaybeUninit::uninit().assume_init() },
107 lisp2: unsafe { MaybeUninit::uninit().assume_init() },
108 };
109 let context = Arc::new(AllocatorContext::new(mmtk));
110
111 for &(selector, space) in space_mapping.iter() {
112 match selector {
113 AllocatorSelector::BumpPointer(index) => {
114 ret.bump_pointer[index as usize].write(BumpAllocator::new(
115 mutator_tls.0,
116 space,
117 context.clone(),
118 ));
119 }
120 AllocatorSelector::LargeObject(index) => {
121 ret.large_object[index as usize].write(LargeObjectAllocator::new(
122 mutator_tls.0,
123 space.downcast_ref::<LargeObjectSpace<VM>>().unwrap(),
124 context.clone(),
125 ));
126 }
127 AllocatorSelector::Malloc(index) => {
128 ret.malloc[index as usize].write(MallocAllocator::new(
129 mutator_tls.0,
130 space.downcast_ref::<MallocSpace<VM>>().unwrap(),
131 context.clone(),
132 ));
133 }
134 AllocatorSelector::Immix(index) => {
135 ret.immix[index as usize].write(ImmixAllocator::new(
136 mutator_tls.0,
137 Some(space),
138 context.clone(),
139 false,
140 ));
141 }
142 AllocatorSelector::FreeList(index) => {
143 ret.free_list[index as usize].write(FreeListAllocator::new(
144 mutator_tls.0,
145 space.downcast_ref::<MarkSweepSpace<VM>>().unwrap(),
146 context.clone(),
147 ));
148 }
149 AllocatorSelector::Lisp2(index) => {
150 ret.lisp2[index as usize].write(Lisp2Allocator::new(
151 mutator_tls.0,
152 space,
153 context.clone(),
154 ));
155 }
156 AllocatorSelector::None => panic!("Allocator mapping is not initialized"),
157 }
158 }
159
160 ret
161 }
162}
163
164#[repr(C, u8)]
178#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
179pub enum AllocatorSelector {
180 BumpPointer(u8),
182 LargeObject(u8),
184 Malloc(u8),
186 Immix(u8),
188 Lisp2(u8),
190 FreeList(u8),
192 #[default]
194 None,
195}
196
197#[repr(C, u8)]
200#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
201pub enum AllocatorInfo {
202 BumpPointer {
204 bump_pointer_offset: usize,
206 },
207 Unimplemented,
210 #[default]
212 None,
213}
214
215impl AllocatorInfo {
216 pub fn new<VM: VMBinding>(selector: AllocatorSelector) -> AllocatorInfo {
222 let base_offset = Mutator::<VM>::get_allocator_base_offset(selector);
223 match selector {
224 AllocatorSelector::BumpPointer(_) => {
225 let bump_pointer_offset = offset_of!(BumpAllocator<VM>, bump_pointer);
226
227 AllocatorInfo::BumpPointer {
228 bump_pointer_offset: base_offset + bump_pointer_offset,
229 }
230 }
231
232 AllocatorSelector::Immix(_) => {
233 let bump_pointer_offset = offset_of!(ImmixAllocator<VM>, bump_pointer);
234
235 AllocatorInfo::BumpPointer {
236 bump_pointer_offset: base_offset + bump_pointer_offset,
237 }
238 }
239
240 AllocatorSelector::Lisp2(_) => {
241 let bump_offset = base_offset + offset_of!(Lisp2Allocator<VM>, bump_allocator);
242 let bump_pointer_offset = offset_of!(BumpAllocator<VM>, bump_pointer);
243
244 AllocatorInfo::BumpPointer {
245 bump_pointer_offset: bump_offset + bump_pointer_offset,
246 }
247 }
248
249 AllocatorSelector::FreeList(_) => AllocatorInfo::Unimplemented,
250 _ => AllocatorInfo::None,
251 }
252 }
253}