Update shrooms-vb-core
This commit is contained in:
@@ -31,7 +31,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
.define("VB_DIRECT_FRAME", "on_frame")
|
.define("VB_DIRECT_FRAME", "on_frame")
|
||||||
.define("VB_DIRECT_READ", "on_read")
|
.define("VB_DIRECT_READ", "on_read")
|
||||||
.define("VB_DIRECT_WRITE", "on_write")
|
.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/core/vb.c"))
|
||||||
.file(Path::new("shrooms-vb-core/util/isx.c"))
|
.file(Path::new("shrooms-vb-core/util/isx.c"))
|
||||||
.file(Path::new("shrooms-vb-core/util/vbu.c"))
|
.file(Path::new("shrooms-vb-core/util/vbu.c"))
|
||||||
|
|||||||
+1
-1
Submodule shrooms-vb-core updated: 31b7403252...6e9b727b31
@@ -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(no_mangle)]
|
||||||
unsafe fn vbu_realloc_shim(ptr: *mut c_void, new_size: usize) -> *mut c_void {
|
#[allow(nonstandard_style)]
|
||||||
if !ptr.is_null() {
|
unsafe fn VBU_MEMMGR(ptr: *mut c_void, new_size: usize) -> *mut c_void {
|
||||||
// not supporting proper realloc because it needs bookkeeping and it's unnecessary
|
let mut allocator = VBU_ALLOC.lock().unwrap();
|
||||||
return std::ptr::null_mut();
|
allocator.realloc(ptr, new_size)
|
||||||
}
|
|
||||||
let allocation = vec![0u8; new_size].into_boxed_slice();
|
|
||||||
Box::into_raw(allocation).cast()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[link(name = "vb")]
|
#[link(name = "vb")]
|
||||||
@@ -25,7 +107,7 @@ pub fn rom_from_isx(bytes: &[u8]) -> Option<Vec<u8>> {
|
|||||||
if raw_rom.is_null() {
|
if raw_rom.is_null() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
// SAFETY: the rom was allocated by vbu_realloc_shim, which created it from a Vec<u8>.
|
let bytes = VBU_ALLOC.lock().unwrap().load_allocation(raw_rom)?;
|
||||||
let rom = unsafe { Vec::from_raw_parts(raw_rom.cast(), rom_length, rom_length) };
|
assert_eq!(bytes.size, rom_length);
|
||||||
Some(rom)
|
Some(bytes.as_slice().to_vec())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user