use std::hash::Hash;
use std::marker::PhantomData;
use std::{fmt::Debug, ops::Range};
use atomic::Atomic;
use crate::util::constants::{BYTES_IN_ADDRESS, LOG_BYTES_IN_ADDRESS};
use crate::util::{Address, ObjectReference};
pub trait Slot: Copy + Send + Debug + PartialEq + Eq + Hash {
fn load(&self) -> Option<ObjectReference>;
fn store(&self, object: ObjectReference);
fn prefetch_load(&self) {
}
fn prefetch_store(&self) {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct SimpleSlot {
slot_addr: *mut Atomic<Address>,
}
impl SimpleSlot {
pub fn from_address(address: Address) -> Self {
Self {
slot_addr: address.to_mut_ptr(),
}
}
pub fn as_address(&self) -> Address {
Address::from_mut_ptr(self.slot_addr)
}
}
unsafe impl Send for SimpleSlot {}
impl Slot for SimpleSlot {
fn load(&self) -> Option<ObjectReference> {
let addr = unsafe { (*self.slot_addr).load(atomic::Ordering::Relaxed) };
ObjectReference::from_raw_address(addr)
}
fn store(&self, object: ObjectReference) {
unsafe { (*self.slot_addr).store(object.to_raw_address(), atomic::Ordering::Relaxed) }
}
}
impl Slot for Address {
fn load(&self) -> Option<ObjectReference> {
let addr = unsafe { Address::load(*self) };
ObjectReference::from_raw_address(addr)
}
fn store(&self, object: ObjectReference) {
unsafe { Address::store(*self, object) }
}
}
#[test]
fn a_simple_slot_should_have_the_same_size_as_a_pointer() {
assert_eq!(
std::mem::size_of::<SimpleSlot>(),
std::mem::size_of::<*mut libc::c_void>()
);
}
pub trait MemorySlice: Send + Debug + PartialEq + Eq + Clone + Hash {
type SlotType: Slot;
type SlotIterator: Iterator<Item = Self::SlotType>;
fn iter_slots(&self) -> Self::SlotIterator;
fn object(&self) -> Option<ObjectReference>;
fn start(&self) -> Address;
fn bytes(&self) -> usize;
fn copy(src: &Self, tgt: &Self);
}
pub struct AddressRangeIterator {
cursor: Address,
limit: Address,
}
impl Iterator for AddressRangeIterator {
type Item = Address;
fn next(&mut self) -> Option<Self::Item> {
if self.cursor >= self.limit {
None
} else {
let slot = self.cursor;
self.cursor += BYTES_IN_ADDRESS;
Some(slot)
}
}
}
impl MemorySlice for Range<Address> {
type SlotType = Address;
type SlotIterator = AddressRangeIterator;
fn iter_slots(&self) -> Self::SlotIterator {
AddressRangeIterator {
cursor: self.start,
limit: self.end,
}
}
fn object(&self) -> Option<ObjectReference> {
None
}
fn start(&self) -> Address {
self.start
}
fn bytes(&self) -> usize {
self.end - self.start
}
fn copy(src: &Self, tgt: &Self) {
debug_assert_eq!(src.bytes(), tgt.bytes());
debug_assert_eq!(
src.bytes() & ((1 << LOG_BYTES_IN_ADDRESS) - 1),
0,
"bytes are not a multiple of words"
);
unsafe {
let words = tgt.bytes() >> LOG_BYTES_IN_ADDRESS;
let src = src.start().to_ptr::<usize>();
let tgt = tgt.start().to_mut_ptr::<usize>();
std::ptr::copy(src, tgt, words)
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct UnimplementedMemorySlice<SL: Slot = SimpleSlot>(PhantomData<SL>);
pub struct UnimplementedMemorySliceSlotIterator<SL: Slot>(PhantomData<SL>);
impl<SL: Slot> Iterator for UnimplementedMemorySliceSlotIterator<SL> {
type Item = SL;
fn next(&mut self) -> Option<Self::Item> {
unimplemented!()
}
}
impl<SL: Slot> MemorySlice for UnimplementedMemorySlice<SL> {
type SlotType = SL;
type SlotIterator = UnimplementedMemorySliceSlotIterator<SL>;
fn iter_slots(&self) -> Self::SlotIterator {
unimplemented!()
}
fn object(&self) -> Option<ObjectReference> {
unimplemented!()
}
fn start(&self) -> Address {
unimplemented!()
}
fn bytes(&self) -> usize {
unimplemented!()
}
fn copy(_src: &Self, _tgt: &Self) {
unimplemented!()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn address_range_iteration() {
let src: Vec<usize> = (0..32).collect();
let src_slice = Address::from_ptr(&src[0])..Address::from_ptr(&src[0]) + src.len();
for (i, v) in src_slice.iter_slots().enumerate() {
assert_eq!(i, unsafe { v.load::<usize>() })
}
}
#[test]
fn memory_copy_on_address_ranges() {
let src = [1u8; 32];
let mut dst = [0u8; 32];
let src_slice = Address::from_ptr(&src[0])..Address::from_ptr(&src[0]) + src.len();
let dst_slice =
Address::from_mut_ptr(&mut dst[0])..Address::from_mut_ptr(&mut dst[0]) + src.len();
MemorySlice::copy(&src_slice, &dst_slice);
assert_eq!(dst.iter().sum::<u8>(), src.len() as u8);
}
}