Update shrooms-vb-core
This commit is contained in:
@@ -1,13 +1,95 @@
|
||||
use std::ffi::c_void;
|
||||
use std::{ffi::c_void, sync::{LazyLock, Mutex}};
|
||||
|
||||
#[derive(Default)]
|
||||
struct Reallocator {
|
||||
allocations: Vec<Allocation>,
|
||||
}
|
||||
|
||||
unsafe impl Send for Reallocator {}
|
||||
|
||||
struct Allocation {
|
||||
ptr: *mut u8,
|
||||
size: usize,
|
||||
}
|
||||
impl Allocation {
|
||||
fn new(size: usize) -> Self {
|
||||
let layout = Self::layout(size);
|
||||
// SAFETY: our layout is not zero, not too big, and properly aligned
|
||||
let ptr = unsafe { std::alloc::alloc_zeroed(layout) };
|
||||
if ptr.is_null() {
|
||||
std::alloc::handle_alloc_error(layout);
|
||||
}
|
||||
Self { ptr, size }
|
||||
}
|
||||
|
||||
fn layout(size: usize) -> std::alloc::Layout {
|
||||
assert!(size != 0);
|
||||
std::alloc::Layout::from_size_align(size, 8).expect("far too large an allocation")
|
||||
}
|
||||
|
||||
fn as_slice(&self) -> &[u8] {
|
||||
// SAFETY: we allocated this ourselves, it's safe
|
||||
unsafe { std::slice::from_raw_parts(self.ptr, self.size) }
|
||||
}
|
||||
|
||||
fn as_mut_slice(&mut self) -> &mut [u8] {
|
||||
// SAFETY: we allocated this ourselves, it's safe
|
||||
unsafe { std::slice::from_raw_parts_mut(self.ptr, self.size) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Allocation {
|
||||
fn drop(&mut self) {
|
||||
// SAFETY: we allocated this ourselves with this layout, and it hasn't been freed
|
||||
unsafe { std::alloc::dealloc(self.ptr, Self::layout(self.size)) };
|
||||
}
|
||||
}
|
||||
|
||||
impl Reallocator {
|
||||
fn realloc(&mut self, ptr: *mut c_void, new_size: usize) -> *mut c_void {
|
||||
if let Some(old_data) = self.load_allocation(ptr) {
|
||||
if new_size == 0 {
|
||||
// free
|
||||
std::ptr::null_mut()
|
||||
} else {
|
||||
// actually reallocate and copy the data over
|
||||
let mut new_data = Allocation::new(new_size);
|
||||
let bytes_to_copy = old_data.size.min(new_size);
|
||||
new_data.as_mut_slice()[..bytes_to_copy].copy_from_slice(&old_data.as_slice()[..bytes_to_copy]);
|
||||
self.store_allocation(new_data)
|
||||
}
|
||||
} else if new_size > 0 {
|
||||
// fresh allocation
|
||||
let allocation = Allocation::new(new_size);
|
||||
self.store_allocation(allocation)
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
fn load_allocation(&mut self, ptr: *mut c_void) -> Option<Allocation> {
|
||||
if ptr.is_null() {
|
||||
return None;
|
||||
}
|
||||
let index = self.allocations.iter().enumerate().find_map(|(i, alloc)| std::ptr::addr_eq(alloc.ptr, ptr).then_some(i))?;
|
||||
let allocation = self.allocations.remove(index);
|
||||
Some(allocation)
|
||||
}
|
||||
|
||||
fn store_allocation(&mut self, allocation: Allocation) -> *mut c_void {
|
||||
let ptr = allocation.ptr;
|
||||
self.allocations.push(allocation);
|
||||
ptr.cast()
|
||||
}
|
||||
}
|
||||
|
||||
static VBU_ALLOC: LazyLock<Mutex<Reallocator>> = LazyLock::new(|| Mutex::new(Reallocator::default()));
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
unsafe fn vbu_realloc_shim(ptr: *mut c_void, new_size: usize) -> *mut c_void {
|
||||
if !ptr.is_null() {
|
||||
// not supporting proper realloc because it needs bookkeeping and it's unnecessary
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
let allocation = vec![0u8; new_size].into_boxed_slice();
|
||||
Box::into_raw(allocation).cast()
|
||||
#[allow(nonstandard_style)]
|
||||
unsafe fn VBU_MEMMGR(ptr: *mut c_void, new_size: usize) -> *mut c_void {
|
||||
let mut allocator = VBU_ALLOC.lock().unwrap();
|
||||
allocator.realloc(ptr, new_size)
|
||||
}
|
||||
|
||||
#[link(name = "vb")]
|
||||
@@ -25,7 +107,7 @@ pub fn rom_from_isx(bytes: &[u8]) -> Option<Vec<u8>> {
|
||||
if raw_rom.is_null() {
|
||||
return None;
|
||||
}
|
||||
// SAFETY: the rom was allocated by vbu_realloc_shim, which created it from a Vec<u8>.
|
||||
let rom = unsafe { Vec::from_raw_parts(raw_rom.cast(), rom_length, rom_length) };
|
||||
Some(rom)
|
||||
let bytes = VBU_ALLOC.lock().unwrap().load_allocation(raw_rom)?;
|
||||
assert_eq!(bytes.size, rom_length);
|
||||
Some(bytes.as_slice().to_vec())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user