comet/allocator/
normal.rs

1use crate::{
2    block::Block,
3    block_allocator::BlockAllocator,
4    globals::{IMMIX_BLOCK_SIZE, LINE_SIZE},
5    internal::{block_list::BlockList, space_bitmap::SpaceBitmap},
6};
7
8use super::{Allocator, BlockTuple};
9
10/// The `NormalAllocator` is the standard allocator to allocate objects within
11/// the immix space.
12///
13/// Objects smaller than `MEDIUM_OBJECT` bytes are
14pub struct NormalAllocator {
15    /// The global `BlockAllocator` to get new blocks from.
16    pub(crate) block_allocator: *mut BlockAllocator,
17
18    /// The exhausted blocks.
19    unavailable_blocks: BlockList,
20
21    /// The blocks with holes to recycle before requesting new blocks..
22    pub(crate) recyclable_blocks: BlockList,
23
24    /// The current block to allocate from.
25    current_block: Option<BlockTuple>,
26    pub(crate) line_bitmap: *const SpaceBitmap<LINE_SIZE>,
27}
28impl NormalAllocator {
29    /// Create a new `NormalAllocator` backed by the given `BlockAllocator`.
30    pub fn new(
31        block_allocator: *mut BlockAllocator,
32        bitmap: *const SpaceBitmap<LINE_SIZE>,
33    ) -> NormalAllocator {
34        NormalAllocator {
35            block_allocator: block_allocator,
36            unavailable_blocks: BlockList::new(),
37            recyclable_blocks: BlockList::new(),
38            current_block: None,
39            line_bitmap: bitmap,
40        }
41    }
42
43    /// Set the recyclable blocks.
44    pub fn set_recyclable_blocks(&mut self, blocks: BlockList) {
45        self.recyclable_blocks = blocks;
46    }
47}
48
49impl Allocator for NormalAllocator {
50    fn get_all_blocks(&mut self, list: &mut BlockList) {
51        while !self.unavailable_blocks.is_empty() {
52            list.push(self.unavailable_blocks.pop());
53        }
54        while !self.recyclable_blocks.is_empty() {
55            list.push(self.recyclable_blocks.pop());
56        }
57        if let Some(block) = self.current_block.take() {
58            list.push((block).0);
59        }
60    }
61
62    fn take_current_block(&mut self) -> Option<BlockTuple> {
63        self.current_block.take()
64    }
65
66    fn put_current_block(&mut self, block_tuple: BlockTuple) {
67        self.current_block = Some(block_tuple);
68    }
69
70    fn get_new_block(&mut self) -> Option<BlockTuple> {
71        unsafe {
72            let block = (*self.block_allocator).get_block();
73            if block.is_null() {
74                return None;
75            }
76            (*block).set_allocated();
77
78            Some((block, LINE_SIZE as u16, IMMIX_BLOCK_SIZE as u16 - 1))
79        }
80    }
81    fn line_bitmap(&self) -> &SpaceBitmap<LINE_SIZE> {
82        unsafe { &*self.line_bitmap }
83    }
84    fn handle_no_hole(&mut self, size: usize) -> Option<BlockTuple> {
85        if size >= LINE_SIZE {
86            None
87        } else {
88            match self.recyclable_blocks.pop() {
89                x if x.is_null() => None,
90                block => {
91                    match unsafe { (*block).scan_block(&*self.line_bitmap, LINE_SIZE as u16 - 1) } {
92                        None => {
93                            self.handle_full_block(block);
94                            self.handle_no_hole(size)
95                        }
96                        Some((low, high)) => self
97                            .scan_for_hole(size, (block, low, high))
98                            .or_else(|| self.handle_no_hole(size)),
99                    }
100                }
101            }
102        }
103    }
104
105    fn handle_full_block(&mut self, block: *mut Block) {
106        self.unavailable_blocks.push(block);
107    }
108}