Update shrooms-vb-core

This commit is contained in:
2026-10-19 20:06:32 -04:00
parent fe766efcdc
commit 1935d116ca
3 changed files with 95 additions and 13 deletions
+1 -1
View File
@@ -31,7 +31,7 @@ fn main() -> Result<(), Box<dyn Error>> {
.define("VB_DIRECT_FRAME", "on_frame")
.define("VB_DIRECT_READ", "on_read")
.define("VB_DIRECT_WRITE", "on_write")
.define("VBU_REALLOC", "vbu_realloc_shim")
.define("VBU_MEMMGR", "VBU_MEMMGR")
.file(Path::new("shrooms-vb-core/core/vb.c"))
.file(Path::new("shrooms-vb-core/util/isx.c"))
.file(Path::new("shrooms-vb-core/util/vbu.c"))
+93 -11
View File
@@ -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())
}