use crate::scheduler::GCWork;
use crate::util::linear_scan::Region;
use crate::util::linear_scan::RegionIterator;
use crate::util::metadata::side_metadata::SideMetadataSpec;
use crate::util::Address;
use crate::vm::VMBinding;
use spin::Mutex;
use std::ops::Range;
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialOrd, PartialEq, Eq)]
pub struct Chunk(Address);
impl Region for Chunk {
const LOG_BYTES: usize = crate::util::heap::layout::vm_layout::LOG_BYTES_IN_CHUNK;
fn from_aligned_address(address: Address) -> Self {
debug_assert!(address.is_aligned_to(Self::BYTES));
Self(address)
}
fn start(&self) -> Address {
self.0
}
}
impl Chunk {
pub const ZERO: Self = Self(Address::ZERO);
pub fn iter_region<R: Region>(&self) -> RegionIterator<R> {
debug_assert!(R::LOG_BYTES < Self::LOG_BYTES);
debug_assert!(R::is_aligned(self.start()));
debug_assert!(R::is_aligned(self.end()));
let start = R::from_aligned_address(self.start());
let end = R::from_aligned_address(self.end());
RegionIterator::<R>::new(start, end)
}
}
#[repr(u8)]
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum ChunkState {
Free = 0,
Allocated = 1,
}
pub struct ChunkMap {
chunk_range: Mutex<Range<Chunk>>,
}
impl ChunkMap {
pub const ALLOC_TABLE: SideMetadataSpec =
crate::util::metadata::side_metadata::spec_defs::CHUNK_MARK;
pub fn new() -> Self {
Self {
chunk_range: Mutex::new(Chunk::ZERO..Chunk::ZERO),
}
}
pub fn set(&self, chunk: Chunk, state: ChunkState) {
if self.get(chunk) == state {
return;
}
unsafe { Self::ALLOC_TABLE.store::<u8>(chunk.start(), state as u8) };
if state == ChunkState::Allocated {
debug_assert!(!chunk.start().is_zero());
let mut range = self.chunk_range.lock();
if range.start == Chunk::ZERO {
range.start = chunk;
range.end = chunk.next();
} else if chunk < range.start {
range.start = chunk;
} else if range.end <= chunk {
range.end = chunk.next();
}
}
}
pub fn get(&self, chunk: Chunk) -> ChunkState {
let byte = unsafe { Self::ALLOC_TABLE.load::<u8>(chunk.start()) };
match byte {
0 => ChunkState::Free,
1 => ChunkState::Allocated,
_ => unreachable!(),
}
}
pub fn all_chunks(&self) -> RegionIterator<Chunk> {
let chunk_range = self.chunk_range.lock();
RegionIterator::<Chunk>::new(chunk_range.start, chunk_range.end)
}
pub fn generate_tasks<VM: VMBinding>(
&self,
func: impl Fn(Chunk) -> Box<dyn GCWork<VM>>,
) -> Vec<Box<dyn GCWork<VM>>> {
let mut work_packets: Vec<Box<dyn GCWork<VM>>> = vec![];
for chunk in self
.all_chunks()
.filter(|c| self.get(*c) == ChunkState::Allocated)
{
work_packets.push(func(chunk));
}
work_packets
}
}
impl Default for ChunkMap {
fn default() -> Self {
Self::new()
}
}