#[global_allocator]
pub static GLOBAL: GlobalAllocator = GlobalAllocator;
#[no_mangle]
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
let layout = Layout::from_size_align(size, align);
unsafe {
HEAP
.lock()
.as_mut()
.expect("must first initialise heap before allocating memory")
.allocate(layout)
.unwrap()
.as_ptr()
}
}
#[no_mangle]
pub extern "C" fn __rust_deallocate(pointer: *mut u8, oldSize: usize, align: usize) {
let layout = Layout::from_size_align(oldSize, align);
unsafe {
HEAP
.lock()
.as_mut()
.expect("must first initialise heap before attempting to deallocate memory")
.deallocate(NonNull::new_unchecked(pointer), layout);
}
}
#[no_mangle]
pub extern "C" fn __rust_reallocate(
pointer: *mut u8,
oldSize: usize,
newSize: usize,
align: usize,
) -> *mut u8 {
let newPointer = __rust_allocate(newSize, align);
return if newPointer.is_null() {
newPointer
} else {
unsafe {
ptr::copy(pointer, newPointer, min(newSize, oldSize));
}
__rust_deallocate(pointer, oldSize, align);
newPointer
};
}
#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace(
_pointer: *mut u8,
oldSize: usize,
_size: usize,
_align: usize,
) -> usize {
oldSize
}
#[no_mangle]
pub extern "C" fn __rust_usable_size(size: usize, _align: usize) -> usize {
size
}
pub unsafe fn allocate<T>(allocator: &mut dyn Allocator) -> Option<NonNull<T>> {
allocator.allocate_aligned(Layout::new::<T>()).map(|ptr| ptr.cast::<T>())
}
pub unsafe fn allocate_array<T>(allocator: &mut dyn Allocator, size: usize) -> Option<NonNull<T>> {
allocator
.allocate_aligned(Layout::from_type_array::<T>(size))
.map(|ptr| ptr.cast::<T>())
}
#[derive(Debug)]
pub struct AllocationError;
impl Display for AllocationError {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "An error occurred allocating the requested memory")
}
}
#[derive(Copy, Clone)]
pub struct GlobalAllocator;
pub struct LockedAllocator<A: Allocator>(pub Mutex<A>);
impl<A> LockedAllocator<A>
where
A: Allocator,
{
pub const fn new(allocator: A) -> Self {
return LockedAllocator(Mutex::new(allocator));
}
pub fn lock(&self) -> MutexGuard<A> {
return self.0.lock();
}
}
pub unsafe trait Allocator {
fn allocate(&self, layout: Layout) -> Option<NonNull<u8>>;
unsafe fn deallocate(&self, pointer: *mut u8, layout: Layout);
unsafe fn reallocate(
&self,
pointer: *mut u8,
oldSize: usize,
layout: Layout,
) -> Option<NonNull<u8>>;
unsafe fn allocate_aligned(&self, layout: Layout) -> Option<NonNull<u8>> {
let actualSize = layout.size + layout.align - 1 + size_of::<usize>();
let pointer = match self.allocate(Layout::from_size(actualSize)) {
Some(p) => p.as_ptr() as usize,
None => return None,
};
let alignedPointer = layout.align_up(pointer + size_of::<usize>());
let actualP2P = alignedPointer - size_of::<usize>();
ptr::write_unaligned(actualP2P as *mut usize, pointer);
return Some(NonNull::new_unchecked(alignedPointer as *mut u8));
}
unsafe fn deallocate_aligned(&self, pointer: *mut u8, layout: Layout) {
let alignedPointer = pointer as usize;
let actualP2P = alignedPointer - size_of::<usize>();
let actualPointer = ptr::read_unaligned(actualP2P as *const usize);
self.deallocate(actualPointer as *mut u8, layout);
}
}
unsafe impl<A: Allocator> Allocator for Mutex<A> {
fn allocate(&self, layout: Layout) -> Option<NonNull<u8>> {
return self.lock().allocate(layout);
}
unsafe fn deallocate(&self, pointer: *mut u8, layout: Layout) {
self.lock().deallocate(pointer, layout);
}
unsafe fn reallocate(
&self,
pointer: *mut u8,
oldSize: usize,
layout: Layout,
) -> Option<NonNull<u8>> {
return self.lock().reallocate(pointer, oldSize, layout);
}
}
unsafe impl<A: Allocator> Allocator for LockedAllocator<A> {
fn allocate(&self, layout: Layout) -> Option<NonNull<u8>> {
return self.lock().allocate(layout);
}
unsafe fn deallocate(&self, pointer: *mut u8, layout: Layout) {
return self.lock().deallocate(pointer, layout);
}
unsafe fn reallocate(
&self,
pointer: *mut u8,
oldSize: usize,
layout: Layout,
) -> Option<NonNull<u8>> {
return self.lock().reallocate(pointer, oldSize, layout);
}
}
unsafe impl<A: Allocator> Allocator for &RefCell<A> {
fn allocate(&self, layout: Layout) -> Option<NonNull<u8>> {
return self.borrow_mut().allocate(layout);
}
unsafe fn deallocate(&self, pointer: *mut u8, layout: Layout) {
return self.borrow_mut().deallocate(pointer, layout);
}
unsafe fn reallocate(
&self,
pointer: *mut u8,
oldSize: usize,
layout: Layout,
) -> Option<NonNull<u8>> {
return self.borrow_mut().reallocate(pointer, oldSize, layout);
}
}
unsafe impl Allocator for GlobalAllocator {
fn allocate(&self, layout: Layout) -> Option<NonNull<u8>> {
return Some(NonNull::new(__rust_allocate(layout.size, layout.align)).unwrap());
}
unsafe fn deallocate(&self, pointer: *mut u8, layout: Layout) {
__rust_deallocate(pointer, layout.size, layout.align);
}
unsafe fn reallocate(
&self,
pointer: *mut u8,
oldSize: usize,
layout: Layout,
) -> Option<NonNull<u8>> {
return Some(
NonNull::new(__rust_reallocate(
pointer,
oldSize,
layout.size,
layout.align,
))
.unwrap(),
);
}
}
unsafe impl GlobalAlloc for GlobalAllocator {
unsafe fn alloc(&self, layout: StdLayout) -> *mut u8 {
let layout = Layout::from(layout);
self.allocate(layout)
.map_or(0 as *mut u8, |allocation| allocation.as_ptr())
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: StdLayout) {
let layout = Layout::from(layout);
self.deallocate(ptr, layout);
}
}
pub mod heap;
pub mod layout;
pub mod paging;
pub use self::layout::Layout;
use {
self::heap::HEAP,
std_alloc::alloc::{GlobalAlloc, Layout as StdLayout},
core::{
cell::RefCell,
cmp::min,
fmt::{Display, Formatter},
mem::size_of,
ptr::{self, NonNull},
},
spin::{Mutex, MutexGuard},
};