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 Edge: Copy + Send + Debug + PartialEq + Eq + Hash {
fn load(&self) -> ObjectReference;
fn store(&self, object: ObjectReference);
#[inline(always)]
fn prefetch_load(&self) {
}
#[inline(always)]
fn prefetch_store(&self) {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct SimpleEdge {
slot_addr: *mut Atomic<ObjectReference>,
}
impl SimpleEdge {
#[inline(always)]
pub fn from_address(address: Address) -> Self {
Self {
slot_addr: address.to_mut_ptr(),
}
}
#[inline(always)]
pub fn as_address(&self) -> Address {
Address::from_mut_ptr(self.slot_addr)
}
}
unsafe impl Send for SimpleEdge {}
impl Edge for SimpleEdge {
#[inline(always)]
fn load(&self) -> ObjectReference {
unsafe { (*self.slot_addr).load(atomic::Ordering::Relaxed) }
}
#[inline(always)]
fn store(&self, object: ObjectReference) {
unsafe { (*self.slot_addr).store(object, atomic::Ordering::Relaxed) }
}
}
impl Edge for Address {
#[inline(always)]
fn load(&self) -> ObjectReference {
unsafe { Address::load(*self) }
}
#[inline(always)]
fn store(&self, object: ObjectReference) {
unsafe { Address::store(*self, object) }
}
}
#[test]
fn a_simple_edge_should_have_the_same_size_as_a_pointer() {
assert_eq!(
std::mem::size_of::<SimpleEdge>(),
std::mem::size_of::<*mut libc::c_void>()
);
}
pub trait MemorySlice: Send + Debug + PartialEq + Eq + Clone + Hash {
type Edge: Edge;
type EdgeIterator: Iterator<Item = Self::Edge>;
fn iter_edges(&self) -> Self::EdgeIterator;
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;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.cursor >= self.limit {
None
} else {
let edge = self.cursor;
self.cursor += BYTES_IN_ADDRESS;
Some(edge)
}
}
}
impl MemorySlice for Range<Address> {
type Edge = Address;
type EdgeIterator = AddressRangeIterator;
#[inline]
fn iter_edges(&self) -> Self::EdgeIterator {
AddressRangeIterator {
cursor: self.start,
limit: self.end,
}
}
#[inline]
fn start(&self) -> Address {
self.start
}
#[inline]
fn bytes(&self) -> usize {
self.end - self.start
}
#[inline]
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<E: Edge = SimpleEdge>(PhantomData<E>);
pub struct UnimplementedMemorySliceEdgeIterator<E: Edge>(PhantomData<E>);
impl<E: Edge> Iterator for UnimplementedMemorySliceEdgeIterator<E> {
type Item = E;
fn next(&mut self) -> Option<Self::Item> {
unimplemented!()
}
}
impl<E: Edge> MemorySlice for UnimplementedMemorySlice<E> {
type Edge = E;
type EdgeIterator = UnimplementedMemorySliceEdgeIterator<E>;
fn iter_edges(&self) -> Self::EdgeIterator {
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_edges().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);
}
}