use crate::{DefaultGrower, MemoryGrower, PageCount, ERROR_PAGE_COUNT, PAGE_SIZE};
use core::{
alloc::{GlobalAlloc, Layout},
cell::UnsafeCell,
ptr::null_mut,
};
pub struct FailAllocator;
unsafe impl GlobalAlloc for FailAllocator {
unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
null_mut()
}
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
}
#[cfg(target_arch = "wasm32")]
pub struct LeakingPageAllocator;
#[cfg(target_arch = "wasm32")]
unsafe impl GlobalAlloc for LeakingPageAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
debug_assert!(PAGE_SIZE % layout.align() == 0);
let requested_pages = (layout.size() + PAGE_SIZE - 1) / PAGE_SIZE;
let previous_page_count = DefaultGrower.memory_grow(PageCount(requested_pages));
if previous_page_count == ERROR_PAGE_COUNT {
return null_mut();
}
let ptr = previous_page_count.size_in_bytes() as *mut u8;
debug_assert!(ptr.align_offset(layout.align()) == 0);
ptr
}
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
}
pub struct LeakingAllocator<T = DefaultGrower> {
used: UnsafeCell<usize>, size: UnsafeCell<usize>, grower: T,
}
#[cfg(target_arch = "wasm32")]
impl LeakingAllocator<DefaultGrower> {
pub const fn new() -> Self {
LeakingAllocator {
used: UnsafeCell::new(0),
size: UnsafeCell::new(0),
grower: DefaultGrower,
}
}
}
unsafe impl<T: MemoryGrower> GlobalAlloc for LeakingAllocator<T> {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let size: &mut usize = &mut *self.size.get();
let used: &mut usize = &mut *self.used.get();
let alignment = layout.align();
let offset = *used % alignment;
if offset != 0 {
*used += alignment - offset;
}
let requested_size = layout.size();
let new_total = *used + requested_size;
if new_total > *size {
let requested_pages = (requested_size + PAGE_SIZE - 1) / PAGE_SIZE;
let previous_page_count = self.grower.memory_grow(PageCount(requested_pages));
if previous_page_count == ERROR_PAGE_COUNT {
return null_mut();
}
let previous_size = previous_page_count.size_in_bytes();
if previous_size != *size {
*used = previous_size;
}
*size = previous_size + requested_pages * PAGE_SIZE;
}
let start = *used;
*used += requested_size;
start as *mut u8
}
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
}