use core::alloc::Layout;
use core::mem::align_of;
use core::ptr::NonNull;
use crate::gc::RawGcObject;
use crate::memory::RawLuaPage;
use crate::state::{RawCallInfo, RawLuaState, RawMainState};
use crate::value::RawTValue;
pub const VM_ALLOC_ALIGN: usize = {
let mut align = align_of::<usize>();
if align_of::<RawMainState>() > align {
align = align_of::<RawMainState>();
}
if align_of::<RawLuaPage>() > align {
align = align_of::<RawLuaPage>();
}
if align_of::<RawLuaState>() > align {
align = align_of::<RawLuaState>();
}
if align_of::<RawTValue>() > align {
align = align_of::<RawTValue>();
}
if align_of::<RawCallInfo>() > align {
align = align_of::<RawCallInfo>();
}
if align_of::<RawGcObject>() > align {
align = align_of::<RawGcObject>();
}
align
};
#[allow(
clippy::missing_safety_doc,
reason = "allocator methods share the unsafe trait contract above"
)]
pub unsafe trait LuaAllocator {
unsafe fn allocate(&self, layout: Layout) -> Option<NonNull<u8>>;
unsafe fn reallocate(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Option<NonNull<u8>>;
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout);
}
#[derive(Debug, Default, Clone, Copy)]
pub struct SystemLuaAllocator;
unsafe impl LuaAllocator for SystemLuaAllocator {
unsafe fn allocate(&self, layout: Layout) -> Option<NonNull<u8>> {
debug_assert!(layout.size() > 0);
unsafe { NonNull::new(std::alloc::alloc(layout)) }
}
unsafe fn reallocate(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Option<NonNull<u8>> {
debug_assert!(old_layout.size() > 0);
debug_assert!(new_layout.size() > 0);
if old_layout.align() == new_layout.align() {
unsafe {
NonNull::new(std::alloc::realloc(
ptr.as_ptr(),
old_layout,
new_layout.size(),
))
}
} else {
let new_ptr = unsafe { self.allocate(new_layout)? };
unsafe {
core::ptr::copy_nonoverlapping(
ptr.as_ptr(),
new_ptr.as_ptr(),
old_layout.size().min(new_layout.size()),
);
self.deallocate(ptr, old_layout);
}
Some(new_ptr)
}
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
debug_assert!(layout.size() > 0);
unsafe { std::alloc::dealloc(ptr.as_ptr(), layout) };
}
}
pub(crate) enum VmAllocator {
System(SystemLuaAllocator),
Custom(Box<dyn LuaAllocator>),
}
impl VmAllocator {
pub(crate) fn system() -> Self {
Self::System(SystemLuaAllocator)
}
pub(crate) fn custom<A: LuaAllocator + 'static>(allocator: A) -> Self {
Self::Custom(Box::new(allocator))
}
pub(crate) unsafe fn allocate(&self, layout: Layout) -> Option<NonNull<u8>> {
match &self {
Self::System(allocator) => unsafe { allocator.allocate(layout) },
Self::Custom(allocator) => unsafe { allocator.allocate(layout) },
}
}
pub(crate) unsafe fn reallocate(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Option<NonNull<u8>> {
match &self {
Self::System(allocator) => unsafe { allocator.reallocate(ptr, old_layout, new_layout) },
Self::Custom(allocator) => unsafe { allocator.reallocate(ptr, old_layout, new_layout) },
}
}
pub(crate) unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
match &self {
Self::System(allocator) => unsafe { allocator.deallocate(ptr, layout) },
Self::Custom(allocator) => unsafe { allocator.deallocate(ptr, layout) },
}
}
}