mmtk/util/heap/layout/
map32.rs1use super::map::CreateFreeListResult;
2use super::map::VMMap;
3use crate::mmtk::SFT_MAP;
4use crate::util::conversions;
5use crate::util::freelist::FreeList;
6use crate::util::heap::layout::heap_parameters::*;
7use crate::util::heap::layout::vm_layout::*;
8use crate::util::heap::space_descriptor::SpaceDescriptor;
9use crate::util::int_array_freelist::IntArrayFreeList;
10use crate::util::rust_util::zeroed_alloc::new_zeroed_vec;
11use crate::util::Address;
12use std::cell::UnsafeCell;
13use std::sync::{Mutex, MutexGuard};
14
15pub struct Map32 {
16 sync: Mutex<()>,
17 inner: UnsafeCell<Map32Inner>,
18}
19
20#[doc(hidden)]
21pub struct Map32Inner {
22 prev_link: Vec<i32>,
23 next_link: Vec<i32>,
24 region_map: IntArrayFreeList,
25 global_page_map: IntArrayFreeList,
26 shared_discontig_fl_count: usize,
27 total_available_discontiguous_chunks: usize,
28 finalized: bool,
29 descriptor_map: Vec<SpaceDescriptor>,
30}
31
32unsafe impl Send for Map32 {}
33unsafe impl Sync for Map32 {}
34
35impl Map32 {
36 pub fn new() -> Self {
37 let max_chunks = vm_layout().max_chunks();
38 Map32 {
39 inner: UnsafeCell::new(Map32Inner {
40 prev_link: vec![-1; max_chunks],
41 next_link: vec![-1; max_chunks],
42 region_map: IntArrayFreeList::new(max_chunks, max_chunks as _, 1),
43 global_page_map: IntArrayFreeList::new(1, 1, MAX_SPACES),
44 shared_discontig_fl_count: 0,
45 total_available_discontiguous_chunks: 0,
46 finalized: false,
47 descriptor_map: new_zeroed_vec(max_chunks),
49 }),
50 sync: Mutex::new(()),
51 }
52 }
53}
54
55impl std::ops::Deref for Map32 {
56 type Target = Map32Inner;
57 fn deref(&self) -> &Self::Target {
58 unsafe { &*self.inner.get() }
59 }
60}
61
62impl VMMap for Map32 {
63 fn insert(&self, start: Address, extent: usize, descriptor: SpaceDescriptor) {
64 let self_mut: &mut Map32Inner = unsafe { self.mut_self() };
67 let mut e = 0;
68 while e < extent {
69 let index = (start + e).chunk_index();
70 assert!(
71 self.descriptor_map[index].is_empty(),
72 "Conflicting virtual address request"
73 );
74 debug!(
75 "Set descriptor {:?} for Chunk {}",
76 descriptor,
77 conversions::chunk_index_to_address(index)
78 );
79 self_mut.descriptor_map[index] = descriptor;
80 e += BYTES_IN_CHUNK;
82 }
83 }
84
85 fn create_freelist(&self, _start: Address) -> CreateFreeListResult {
86 let free_list = Box::new(IntArrayFreeList::from_parent(
87 &self.global_page_map,
88 self.get_discontig_freelist_pr_ordinal() as _,
89 ));
90 CreateFreeListResult {
91 free_list,
92 space_displacement: 0,
93 }
94 }
95
96 fn create_parent_freelist(
97 &self,
98 _start: Address,
99 units: usize,
100 grain: i32,
101 ) -> CreateFreeListResult {
102 let free_list = Box::new(IntArrayFreeList::new(units, grain, 1));
103 CreateFreeListResult {
104 free_list,
105 space_displacement: 0,
106 }
107 }
108
109 unsafe fn allocate_contiguous_chunks(
110 &self,
111 descriptor: SpaceDescriptor,
112 chunks: usize,
113 head: Address,
114 _maybe_freelist: Option<&mut dyn FreeList>,
115 ) -> Address {
116 let (_sync, self_mut) = self.mut_self_with_sync();
117 let chunk = self_mut.region_map.alloc(chunks as _);
118 if chunk == -1 {
119 return Address::zero();
120 }
121 self_mut.total_available_discontiguous_chunks -= chunks;
122 let rtn = conversions::chunk_index_to_address(chunk as _);
123 self.insert(rtn, chunks << LOG_BYTES_IN_CHUNK, descriptor);
124 if head.is_zero() {
125 debug_assert!(self.next_link[chunk as usize] == -1);
126 } else {
127 self_mut.next_link[chunk as usize] = head.chunk_index() as _;
128 self_mut.prev_link[head.chunk_index()] = chunk;
129 }
130 debug_assert!(self.prev_link[chunk as usize] == -1);
131 rtn
132 }
133
134 fn get_next_contiguous_region(&self, start: Address) -> Address {
135 if start.is_zero() {
136 return Address::ZERO;
137 }
138 debug_assert!(start == conversions::chunk_align_down(start));
139 let chunk = start.chunk_index();
140 if self.next_link[chunk] == -1 {
141 unsafe { Address::zero() }
142 } else {
143 let a = self.next_link[chunk];
144 conversions::chunk_index_to_address(a as _)
145 }
146 }
147
148 fn get_contiguous_region_chunks(&self, start: Address) -> usize {
149 debug_assert!(start == conversions::chunk_align_down(start));
150 let chunk = start.chunk_index();
151 self.region_map.size(chunk as i32) as _
152 }
153
154 fn get_contiguous_region_size(&self, start: Address) -> usize {
155 self.get_contiguous_region_chunks(start) << LOG_BYTES_IN_CHUNK
156 }
157
158 fn get_available_discontiguous_chunks(&self) -> usize {
159 self.total_available_discontiguous_chunks
160 }
161
162 fn get_chunk_consumer_count(&self) -> usize {
163 self.shared_discontig_fl_count
164 }
165 #[allow(clippy::while_immutable_condition)]
166 fn free_all_chunks(&self, any_chunk: Address) {
167 debug!("free_all_chunks: {}", any_chunk);
168 let (_sync, self_mut) = self.mut_self_with_sync();
169 debug_assert!(any_chunk == conversions::chunk_align_down(any_chunk));
170 if !any_chunk.is_zero() {
171 let chunk = any_chunk.chunk_index();
172 while self_mut.next_link[chunk] != -1 {
173 let x = self_mut.next_link[chunk];
174 self.free_contiguous_chunks_no_lock(x);
175 }
176 while self_mut.prev_link[chunk] != -1 {
177 let x = self_mut.prev_link[chunk];
178 self.free_contiguous_chunks_no_lock(x);
179 }
180 self.free_contiguous_chunks_no_lock(chunk as _);
181 }
182 }
183
184 unsafe fn free_contiguous_chunks(&self, start: Address) -> usize {
185 debug!("free_contiguous_chunks: {}", start);
186 let (_sync, _) = self.mut_self_with_sync();
187 debug_assert!(start == conversions::chunk_align_down(start));
188 let chunk = start.chunk_index();
189 self.free_contiguous_chunks_no_lock(chunk as _)
190 }
191
192 fn finalize_static_space_map(
193 &self,
194 from: Address,
195 to: Address,
196 on_discontig_start_determined: &mut dyn FnMut(Address),
197 ) {
198 let self_mut: &mut Map32Inner = unsafe { self.mut_self() };
201 let start_address = from;
203 let first_chunk = start_address.chunk_index();
204 let last_chunk = to.chunk_index();
205 let unavail_start_chunk = last_chunk + 1;
206 let trailing_chunks = vm_layout().max_chunks() - unavail_start_chunk;
207 let pages = (1 + last_chunk - first_chunk) * PAGES_IN_CHUNK;
208 self_mut.global_page_map.resize_freelist(pages, pages as _);
211
212 on_discontig_start_determined(start_address);
213
214 self_mut.region_map.alloc(first_chunk as _); for _ in first_chunk..=last_chunk {
226 self_mut.region_map.alloc(1);
227 }
228 let alloced_chunk = self_mut.region_map.alloc(trailing_chunks as _);
229 debug_assert!(
230 alloced_chunk == unavail_start_chunk as i32,
231 "{} != {}",
232 alloced_chunk,
233 unavail_start_chunk
234 );
235 let mut first_page = 0;
237 for chunk_index in first_chunk..=last_chunk {
238 self_mut.total_available_discontiguous_chunks += 1;
239 self_mut.region_map.free(chunk_index as _, false); self_mut.global_page_map.set_uncoalescable(first_page);
241 let alloced_pages = self_mut.global_page_map.alloc(PAGES_IN_CHUNK as _); debug_assert!(alloced_pages == first_page);
243 first_page += PAGES_IN_CHUNK as i32;
244 }
245 self_mut.finalized = true;
246 }
247
248 fn is_finalized(&self) -> bool {
249 self.finalized
250 }
251
252 fn get_descriptor_for_address(&self, address: Address) -> SpaceDescriptor {
253 let index = address.chunk_index();
254 self.descriptor_map
255 .get(index)
256 .copied()
257 .unwrap_or(SpaceDescriptor::UNINITIALIZED)
258 }
259
260 fn min_contiguous_extent(&self) -> usize {
261 BYTES_IN_CHUNK
262 }
263}
264
265impl Map32 {
266 #[allow(clippy::mut_from_ref)]
272 unsafe fn mut_self(&self) -> &mut Map32Inner {
273 &mut *self.inner.get()
274 }
275
276 #[allow(clippy::mut_from_ref)]
279 fn mut_self_with_sync(&self) -> (MutexGuard<'_, ()>, &mut Map32Inner) {
280 let guard = self.sync.lock().unwrap();
281 (guard, unsafe { self.mut_self() })
282 }
283
284 fn free_contiguous_chunks_no_lock(&self, chunk: i32) -> usize {
285 unsafe {
286 let chunks = self.mut_self().region_map.free(chunk, false);
287 self.mut_self().total_available_discontiguous_chunks += chunks as usize;
288 let next = self.next_link[chunk as usize];
289 let prev = self.prev_link[chunk as usize];
290 if next != -1 {
291 self.mut_self().prev_link[next as usize] = prev
292 };
293 if prev != -1 {
294 self.mut_self().next_link[prev as usize] = next
295 };
296 self.mut_self().prev_link[chunk as usize] = -1;
297 self.mut_self().next_link[chunk as usize] = -1;
298 for offset in 0..chunks {
299 let index = (chunk + offset) as usize;
300 let chunk_start = conversions::chunk_index_to_address(index);
301 debug!("Clear descriptor for Chunk {}", chunk_start);
302 self.mut_self().descriptor_map[index] = SpaceDescriptor::UNINITIALIZED;
303 SFT_MAP.clear(chunk_start);
304 }
305 chunks as _
306 }
307 }
308
309 fn get_discontig_freelist_pr_ordinal(&self) -> usize {
310 let self_mut: &mut Map32Inner = unsafe { self.mut_self() };
312 self_mut.shared_discontig_fl_count += 1;
313 self.shared_discontig_fl_count
314 }
315}
316
317impl Default for Map32 {
318 fn default() -> Self {
319 Self::new()
320 }
321}