mmtk/policy/marksweepspace/native_ms/
block_list.rs1use super::{Block, BlockState};
2use crate::util::alloc::allocator;
3use crate::util::linear_scan::Region;
4use crate::vm::VMBinding;
5use std::sync::atomic::AtomicBool;
6use std::sync::atomic::Ordering;
7
8#[repr(C)]
10pub struct BlockList {
11 pub first: Option<Block>,
12 pub last: Option<Block>,
13 pub size: usize,
14 pub lock: AtomicBool,
15}
16
17impl std::fmt::Debug for BlockList {
18 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
19 write!(f, "BlockList {:?}", self.iter().collect::<Vec<Block>>())
20 }
21}
22
23impl BlockList {
24 const fn new(size: usize) -> BlockList {
25 BlockList {
26 first: None,
27 last: None,
28 size,
29 lock: AtomicBool::new(false),
30 }
31 }
32
33 pub fn is_empty(&self) -> bool {
35 self.first.is_none()
36 }
37
38 pub fn remove(&mut self, block: Block) {
40 match (block.load_prev_block(), block.load_next_block()) {
41 (None, None) => {
42 self.first = None;
43 self.last = None;
44 }
45 (None, Some(next)) => {
46 next.clear_prev_block();
47 self.first = Some(next);
48 next.store_block_list(self);
49 }
50 (Some(prev), None) => {
51 prev.clear_next_block();
52 self.last = Some(prev);
53 prev.store_block_list(self);
54 }
55 (Some(prev), Some(next)) => {
56 prev.store_next_block(next);
57 next.store_prev_block(prev);
58 }
59 }
60 }
61
62 pub fn pop(&mut self) -> Option<Block> {
64 if let Some(head) = self.first {
65 if let Some(next) = head.load_next_block() {
66 self.first = Some(next);
67 next.clear_prev_block();
68 next.store_block_list(self);
69 } else {
70 self.first = None;
71 self.last = None;
72 }
73 head.clear_next_block();
74 head.clear_prev_block();
75 Some(head)
76 } else {
77 None
78 }
79 }
80
81 pub fn push(&mut self, block: Block) {
83 if self.is_empty() {
84 block.clear_next_block();
85 block.clear_prev_block();
86 self.first = Some(block);
87 self.last = Some(block);
88 } else {
89 let self_head = self.first.unwrap();
90 block.store_next_block(self_head);
91 self_head.store_prev_block(block);
92 block.clear_prev_block();
93 self.first = Some(block);
94 }
95 block.store_block_list(self);
96 }
97
98 pub fn append(&mut self, other: &mut BlockList) {
100 debug_assert_eq!(self.size, other.size);
101 if !other.is_empty() {
102 debug_assert!(
103 other.first.unwrap().load_prev_block().is_none(),
104 "The other list's head has prev block: prev{} -> head{}",
105 other.first.unwrap().load_prev_block().unwrap().start(),
106 other.first.unwrap().start()
107 );
108 if self.is_empty() {
109 self.first = other.first;
110 self.last = other.last;
111 } else {
112 debug_assert!(
113 self.first.unwrap().load_prev_block().is_none(),
114 "Current list's head has prev block: prev{} -> head{}",
115 self.first.unwrap().load_prev_block().unwrap().start(),
116 self.first.unwrap().start()
117 );
118 let self_tail = self.last.unwrap();
119 let other_head = other.first.unwrap();
120 self_tail.store_next_block(other_head);
121 other_head.store_prev_block(self_tail);
122 self.last = other.last;
123 }
124 let mut cursor = other.first;
125 while let Some(block) = cursor {
126 block.store_block_list(self);
127 cursor = block.load_next_block();
128 }
129 other.reset();
130 }
131 }
132
133 fn reset(&mut self) {
135 self.first = None;
136 self.last = None;
137 }
138
139 pub fn lock(&mut self) {
148 let mut success = false;
149 while !success {
150 success = self
151 .lock
152 .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
153 .is_ok();
154 }
155 }
156
157 pub fn unlock(&mut self) {
159 self.lock.store(false, Ordering::SeqCst);
160 }
161
162 pub fn iter(&self) -> BlockListIterator {
164 BlockListIterator { cursor: self.first }
165 }
166
167 pub fn release_and_sweep_blocks<VM: VMBinding>(&self, space: &super::MarkSweepSpace<VM>) {
169 for block in self.iter() {
170 debug_assert_ne!(block.get_state(), BlockState::Unallocated);
172 if !block.attempt_release(space) {
173 block.sweep::<VM>();
174 }
175 }
176 }
177
178 pub fn release_blocks<VM: VMBinding>(&self, space: &super::MarkSweepSpace<VM>) {
180 for block in self.iter() {
181 debug_assert_ne!(block.get_state(), BlockState::Unallocated);
183 block.attempt_release(space);
184 }
185 }
186}
187
188pub struct BlockListIterator {
189 cursor: Option<Block>,
190}
191
192impl Iterator for BlockListIterator {
193 type Item = Block;
194
195 fn next(&mut self) -> Option<Self::Item> {
196 let ret = self.cursor;
197 if let Some(cur) = self.cursor {
198 self.cursor = cur.load_next_block();
199 }
200 ret
201 }
202}
203
204const MI_INTPTR_SHIFT: usize = crate::util::constants::LOG_BYTES_IN_ADDRESS as usize;
206const MI_INTPTR_SIZE: usize = 1 << MI_INTPTR_SHIFT;
208const MI_INTPTR_BITS: usize = MI_INTPTR_SIZE * 8;
210pub(crate) const MI_BIN_FULL: usize = MAX_BIN + 1;
212pub(crate) const MAX_BIN: usize = 48;
214
215pub(crate) const MI_LARGE_OBJ_SIZE_MAX: usize =
217 crate::util::rust_util::min_of_usize(Block::BYTES, MAX_BIN_SIZE);
218const MI_LARGE_OBJ_WSIZE_MAX: usize = MI_LARGE_OBJ_SIZE_MAX / MI_INTPTR_SIZE;
220pub(crate) const MAX_BIN_SIZE: usize = 8192 * MI_INTPTR_SIZE;
222
223pub type BlockLists = Box<[BlockList; MAX_BIN + 1]>;
227
228pub(crate) fn new_empty_block_lists() -> BlockLists {
230 let ret = Box::new([
231 BlockList::new(MI_INTPTR_SIZE),
232 BlockList::new(MI_INTPTR_SIZE),
233 BlockList::new(2 * MI_INTPTR_SIZE),
234 BlockList::new(3 * MI_INTPTR_SIZE),
235 BlockList::new(4 * MI_INTPTR_SIZE),
236 BlockList::new(5 * MI_INTPTR_SIZE),
237 BlockList::new(6 * MI_INTPTR_SIZE),
238 BlockList::new(7 * MI_INTPTR_SIZE),
239 BlockList::new(8 * MI_INTPTR_SIZE), BlockList::new(10 * MI_INTPTR_SIZE),
241 BlockList::new(12 * MI_INTPTR_SIZE),
242 BlockList::new(14 * MI_INTPTR_SIZE),
243 BlockList::new(16 * MI_INTPTR_SIZE),
244 BlockList::new(20 * MI_INTPTR_SIZE),
245 BlockList::new(24 * MI_INTPTR_SIZE),
246 BlockList::new(28 * MI_INTPTR_SIZE),
247 BlockList::new(32 * MI_INTPTR_SIZE), BlockList::new(40 * MI_INTPTR_SIZE),
249 BlockList::new(48 * MI_INTPTR_SIZE),
250 BlockList::new(56 * MI_INTPTR_SIZE),
251 BlockList::new(64 * MI_INTPTR_SIZE),
252 BlockList::new(80 * MI_INTPTR_SIZE),
253 BlockList::new(96 * MI_INTPTR_SIZE),
254 BlockList::new(112 * MI_INTPTR_SIZE),
255 BlockList::new(128 * MI_INTPTR_SIZE), BlockList::new(160 * MI_INTPTR_SIZE),
257 BlockList::new(192 * MI_INTPTR_SIZE),
258 BlockList::new(224 * MI_INTPTR_SIZE),
259 BlockList::new(256 * MI_INTPTR_SIZE),
260 BlockList::new(320 * MI_INTPTR_SIZE),
261 BlockList::new(384 * MI_INTPTR_SIZE),
262 BlockList::new(448 * MI_INTPTR_SIZE),
263 BlockList::new(512 * MI_INTPTR_SIZE), BlockList::new(640 * MI_INTPTR_SIZE),
265 BlockList::new(768 * MI_INTPTR_SIZE),
266 BlockList::new(896 * MI_INTPTR_SIZE),
267 BlockList::new(1024 * MI_INTPTR_SIZE),
268 BlockList::new(1280 * MI_INTPTR_SIZE),
269 BlockList::new(1536 * MI_INTPTR_SIZE),
270 BlockList::new(1792 * MI_INTPTR_SIZE),
271 BlockList::new(2048 * MI_INTPTR_SIZE), BlockList::new(2560 * MI_INTPTR_SIZE),
273 BlockList::new(3072 * MI_INTPTR_SIZE),
274 BlockList::new(3584 * MI_INTPTR_SIZE),
275 BlockList::new(4096 * MI_INTPTR_SIZE),
276 BlockList::new(5120 * MI_INTPTR_SIZE),
277 BlockList::new(6144 * MI_INTPTR_SIZE),
278 BlockList::new(7168 * MI_INTPTR_SIZE),
279 BlockList::new(8192 * MI_INTPTR_SIZE), ]);
281
282 debug_assert_eq!(
283 ret[MAX_BIN].size, MAX_BIN_SIZE,
284 "MAX_BIN_SIZE = {}, actual max bin size = {}, please update the constants",
285 MAX_BIN_SIZE, ret[MAX_BIN].size
286 );
287
288 ret
289}
290
291#[allow(unused)]
293pub(crate) fn pages_used_by_blocklists(lists: &BlockLists) -> usize {
294 let mut pages = 0;
295 for bin in 1..=MAX_BIN {
296 let list = &lists[bin];
297
298 let mut cursor = list.first;
300 while let Some(block) = cursor {
301 pages += Block::BYTES >> crate::util::constants::LOG_BYTES_IN_PAGE;
302 cursor = block.load_next_block();
303 }
304 }
305
306 pages
307}
308
309fn mi_wsize_from_size(size: usize) -> usize {
313 size.div_ceil(MI_INTPTR_SIZE)
314}
315
316pub fn mi_bin<VM: VMBinding>(size: usize, align: usize) -> usize {
317 let size = allocator::get_maximum_aligned_size::<VM>(size, align);
318 mi_bin_from_size(size)
319}
320
321fn mi_bin_from_size(size: usize) -> usize {
322 let mut wsize: usize = mi_wsize_from_size(size);
324 debug_assert!(wsize <= MI_LARGE_OBJ_WSIZE_MAX);
325 let bin: u8;
326 if wsize <= 1 {
327 bin = 1;
328 } else if wsize <= 8 {
329 bin = wsize as u8;
330 } else {
332 wsize -= 1;
333 let b = (MI_INTPTR_BITS - 1 - usize::leading_zeros(wsize) as usize) as u8; bin = ((b << 2) + ((wsize >> (b - 2)) & 0x03) as u8) - 3;
335 }
336 bin as usize
337}
338
339#[cfg(test)]
340mod tests {
341 use super::*;
342
343 fn get_bin_size_range(bin: usize, bins: &BlockLists) -> Option<(usize, usize)> {
344 if bin == 0 || bin > MAX_BIN {
345 None
346 } else if bin == 1 {
347 Some((0, bins[1].size))
348 } else {
349 Some((bins[bin - 1].size, bins[bin].size))
350 }
351 }
352
353 #[test]
354 fn test_mi_bin() {
355 let block_lists = new_empty_block_lists();
356 for size in 0..=MAX_BIN_SIZE {
357 let bin = mi_bin_from_size(size);
358 let bin_range = get_bin_size_range(bin, &block_lists);
359 assert!(bin_range.is_some(), "Invalid bin {} for size {}", bin, size);
360 assert!(
361 size >= bin_range.unwrap().0 && bin < bin_range.unwrap().1,
362 "Assigning size={} to bin={} ({:?}) incorrect",
363 size,
364 bin,
365 bin_range.unwrap()
366 );
367 }
368 }
369}