From d581440210e461eb74f397580ec8a3a154aee18d Mon Sep 17 00:00:00 2001 From: lifning <> Date: Sat, 27 Nov 2021 01:22:54 -0800 Subject: [PATCH] initial commit --- .gitignore | 2 + Cargo.lock | 16 ++++++ Cargo.toml | 7 +++ src/main.rs | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 169 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3a8cabc --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +.idea diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..b872342 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "shortpointer" +version = "0.1.0" +dependencies = [ + "lazy_static", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..86249af --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "shortpointer" +version = "0.1.0" +edition = "2021" + +[dependencies] +lazy_static = "1" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..099e646 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,144 @@ +use core::alloc::Layout; +use core::marker::PhantomData; +use core::mem::size_of; +use core::ops::{Deref, DerefMut}; + +use std::fmt::Formatter; +use std::mem::size_of_val; +use std::sync::Mutex; + +use lazy_static::lazy_static; + +#[repr(C, align(65536))] +struct Pool { + data: [u8; 65536], + begin: usize, + end: usize, + last_position: usize, +} + +lazy_static! { + static ref POOL: Mutex = Mutex::new(Pool { data: [0; 65536], begin: 0, end: 0, last_position: 0 }); +} + +// halfassed bump allocator just to prove a point. +impl Pool { + fn alloc(&mut self, layout: Layout) -> u16 { + let size = layout.size(); + let align = layout.align(); + + let mut position = self.end + size_of::(); // space for skip marker + let alignmask = align - 1; + if position & alignmask != 0 { + position += ((position ^ alignmask) & alignmask) + 1; + } + let new_end = position + size; + assert!(new_end < self.data.len(), "ShortPointer memory pool exhausted"); + // using most significant bit as whether it's been freed + assert!(position - self.last_position < 32768, "Alignment caused 32KiB limit overrun"); + + let skip_marker = 0x8000_u16.to_ne_bytes(); + self.data[position - 2..position].copy_from_slice(&skip_marker); + self.end = new_end; + if self.begin == 0 { + self.begin = position; + } + self.last_position = position; + position as u16 + } + + fn dealloc(&mut self, sptr: u16) { + let mut position = sptr as usize; + unsafe { + let skip_marker_ptr = self.data.as_mut_ptr().add(position - 2) as *mut u16; + *skip_marker_ptr &= 0x7fff; + // see how much we can free + let mut skip_marker = *skip_marker_ptr; + let update_begin = self.begin == position; + while skip_marker & 0x8000 == 0 { + if skip_marker == 0 { + // last object, we can reclaim memory back to sptr + self.end = sptr as usize; + break; + } else { + position += skip_marker as usize; + } + skip_marker = *(self.data.as_ptr().add(position - 2) as *const u16); + } + if update_begin { + self.begin = position; + } + } + if self.begin == self.end { + // all objects freed, we can reset the entire state + self.begin = 0; + self.end = 0; + self.last_position = 0; + } + } +} + +impl std::fmt::Debug for Pool { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, "Pool {{ data: [_; 65536], begin: {}, end: {}, last_position: {} }}", + self.begin, + self.end, + self.last_position, + ) + } +} + +pub struct ShortPointer(u16, PhantomData); + +impl Drop for ShortPointer { + fn drop(&mut self) { + POOL.lock().unwrap().dealloc(self.0) + } +} + +impl ShortPointer { + fn deref_inner(&self) -> &mut T { + unsafe { + ((((POOL.lock().unwrap().data.as_mut_ptr()) as usize) + (self.0 as usize)) as *mut T).as_mut().unwrap() + } + } + + pub fn new(obj: T) -> Self { + let layout = Layout::for_value(&obj); + let mut sptr = Self(POOL.lock().unwrap().alloc(layout), PhantomData::default()); + let uninitialized = core::mem::replace(sptr.deref_mut(), obj); + core::mem::forget(uninitialized); + sptr + } +} + +impl Deref for ShortPointer { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.deref_inner() + } +} + +impl DerefMut for ShortPointer { + fn deref_mut(&mut self) -> &mut Self::Target { + self.deref_inner() + } +} + +#[allow(unused_must_use)] // dbg! statements +fn main() { + dbg!(POOL.lock().unwrap()); + { + let foo = ShortPointer::new([1, 2, 3, 4, 5]); + dbg!(POOL.lock().unwrap()); + { + let bar = ShortPointer::new(0x900dCafeDa7e5_u64); + dbg!(POOL.lock().unwrap()); + println!("{} | {:?} | {:x}", size_of_val(&foo), *foo, *bar); + } + dbg!(POOL.lock().unwrap()); + } + dbg!(POOL.lock().unwrap()); +}