1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use crate::allocator::normal::NormalAllocator;
use crate::allocator::overflow::OverflowAllocator;
use crate::allocator::Allocator;
use crate::block::SweepResult;
use crate::globals::LINE_SIZE;
use crate::heap::Heap;
use crate::internal::block_list::BlockList;
use crate::large_space::PreciseAllocation;
use crate::Config;
use crate::{
    block::Block, block_allocator::BlockAllocator, internal::space_bitmap::SpaceBitmap,
    large_space::LargeObjectSpace,
};

use std::ptr::null_mut;

pub const fn round_up(x: usize, y: usize) -> usize {
    ((x) + (y - 1)) & !(y - 1)
}


/// Global allocator is an storage for:
/// - Immix blocks used for small allocations
/// - Large object space used for large allocations
/// - bitmaps that are used for conservative marking and marking individual block lines
pub struct GlobalAllocator {
    pub(crate) block_allocator: Box<BlockAllocator>,
    pub(crate) large_space: LargeObjectSpace,
    pub(crate) live_bitmap: SpaceBitmap<8>,
    pub(crate) mark_bitmap: SpaceBitmap<8>,
    pub(crate) line_bitmap: SpaceBitmap<LINE_SIZE>,
    pub(crate) normal_allocator: NormalAllocator,
    pub(crate) overflow_allocator: OverflowAllocator,
}

impl GlobalAllocator {
    pub fn new(config: &Config) -> Self {
        let block_allocator = Box::new(BlockAllocator::new(config.heap_size));

        let mut global = Self {
            live_bitmap: SpaceBitmap::create(
                "live-bitmap",
                block_allocator.mmap.aligned(),
                block_allocator.size(),
            ),
            mark_bitmap: SpaceBitmap::create(
                "mark-bitmap",
                block_allocator.mmap.aligned(),
                block_allocator.size(),
            ),
            line_bitmap: SpaceBitmap::create(
                "line-bitmap",
                block_allocator.mmap.aligned(),
                block_allocator.size(),
            ),
            block_allocator,
            normal_allocator: NormalAllocator::new(null_mut(), null_mut()),
            overflow_allocator: OverflowAllocator::new(null_mut(), null_mut()),
            large_space: LargeObjectSpace::new(),
        };
        global.normal_allocator.block_allocator = &mut *global.block_allocator;
        global.overflow_allocator.block_allocator = &mut *global.block_allocator;
        global
    }
    pub fn large_allocation(&mut self, size: usize) -> (*mut u8, usize) {
        let cell = self.large_space.allocate(size);

        (cell.cast(), unsafe {
            (*PreciseAllocation::from_cell(cell)).cell_size()
        })
    }

    pub fn prepare_for_marking(&mut self, eden: bool) {
        self.large_space.prepare_for_marking(eden);
    }
    pub fn begin_marking(&mut self) -> BlockList {
        let mut blocks = BlockList::new();
        self.normal_allocator.get_all_blocks(&mut blocks);
        self.overflow_allocator.get_all_blocks(&mut blocks);
        blocks.for_each(|block| unsafe {
            self.mark_bitmap
                .clear_range(block as _, (*block).end() as _);
            self.line_bitmap.clear_range(block as _, (*block).end());
        });
        for alloc in self.large_space.allocations.iter() {
            unsafe {
                (**alloc).flip();
            }
        }
        blocks
    }

    pub(crate) fn release_memory(&mut self) {}

    pub(crate) fn sweep(&mut self, mut block_list: BlockList) {
        self.large_space.sweep();
        unsafe {
            while !block_list.is_empty() {
                let block = block_list.pop();

                match (*block).sweep::<true>(
                    &self.mark_bitmap,
                    &self.live_bitmap,
                    &self.line_bitmap,
                ) {
                    SweepResult::Empty => {
                        self.block_allocator.return_block(block);
                    }
                    SweepResult::Reuse => {
                        self.normal_allocator.recyclable_blocks.push(block);
                    }
                }
            }
        }
    }
    pub fn acquire_block(&self, heap: *const Heap) -> *mut Block {
        let mut block = null_mut::<Block>();
        if block.is_null() {
            block = self.block_allocator.get_block();
            unsafe {
                (*block).init(heap as _);
            }
        }

        block
    }
}