1b81bb7a3SAlex Crichton //! An allocator definition for this embedding. 2b81bb7a3SAlex Crichton //! 3b81bb7a3SAlex Crichton //! The Rust standard library and Wasmtime require a memory allocator to be 4b81bb7a3SAlex Crichton //! configured. For custom embeddings of Wasmtime this might likely already be 5b81bb7a3SAlex Crichton //! defined elsewhere in the system in which case that should be used. This file 6b81bb7a3SAlex Crichton //! contains an example implementation using the Rust `dlmalloc` crate using 7b81bb7a3SAlex Crichton //! memory created by `wasmtime_*` platform symbols. This provides a file that 8b81bb7a3SAlex Crichton //! manages memory without any extra runtime dependencies, but this is just an 9b81bb7a3SAlex Crichton //! example. 10b81bb7a3SAlex Crichton //! 11b81bb7a3SAlex Crichton //! Allocators in Rust are configured with the `#[global_allocator]` attribute 12b81bb7a3SAlex Crichton //! and the `GlobalAlloc for T` trait impl. This should be used when hooking 13b81bb7a3SAlex Crichton //! up to an allocator elsewhere in the system. 14b81bb7a3SAlex Crichton 155054d400SAlex Crichton use alloc::alloc::{GlobalAlloc, Layout}; 165054d400SAlex Crichton use core::cell::UnsafeCell; 175054d400SAlex Crichton use core::ops::{Deref, DerefMut}; 185054d400SAlex Crichton use core::ptr; 195054d400SAlex Crichton use core::sync::atomic::{ 205054d400SAlex Crichton AtomicBool, 215054d400SAlex Crichton Ordering::{Acquire, Release}, 225054d400SAlex Crichton }; 23b81bb7a3SAlex Crichton use dlmalloc::Dlmalloc; 24b81bb7a3SAlex Crichton 25b81bb7a3SAlex Crichton #[global_allocator] 26b81bb7a3SAlex Crichton static MALLOC: MyGlobalDmalloc = MyGlobalDmalloc { 27b81bb7a3SAlex Crichton dlmalloc: Mutex::new(Dlmalloc::new_with_allocator(MyAllocator)), 28b81bb7a3SAlex Crichton }; 29b81bb7a3SAlex Crichton 30b81bb7a3SAlex Crichton struct MyGlobalDmalloc { 31b81bb7a3SAlex Crichton dlmalloc: Mutex<Dlmalloc<MyAllocator>>, 32b81bb7a3SAlex Crichton } 33b81bb7a3SAlex Crichton 34b81bb7a3SAlex Crichton struct MyAllocator; 35b81bb7a3SAlex Crichton 36b81bb7a3SAlex Crichton unsafe impl GlobalAlloc for MyGlobalDmalloc { alloc(&self, layout: Layout) -> *mut u837b81bb7a3SAlex Crichton unsafe fn alloc(&self, layout: Layout) -> *mut u8 { 38*073aedabSAlex Crichton unsafe { 39b81bb7a3SAlex Crichton self.dlmalloc 405054d400SAlex Crichton .try_lock() 41b81bb7a3SAlex Crichton .unwrap() 42b81bb7a3SAlex Crichton .malloc(layout.size(), layout.align()) 43b81bb7a3SAlex Crichton } 44*073aedabSAlex Crichton } 45b81bb7a3SAlex Crichton alloc_zeroed(&self, layout: Layout) -> *mut u846b81bb7a3SAlex Crichton unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { 47*073aedabSAlex Crichton unsafe { 48b81bb7a3SAlex Crichton self.dlmalloc 495054d400SAlex Crichton .try_lock() 50b81bb7a3SAlex Crichton .unwrap() 51b81bb7a3SAlex Crichton .calloc(layout.size(), layout.align()) 52b81bb7a3SAlex Crichton } 53*073aedabSAlex Crichton } 54b81bb7a3SAlex Crichton realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u855b81bb7a3SAlex Crichton unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { 56*073aedabSAlex Crichton unsafe { 57b81bb7a3SAlex Crichton self.dlmalloc 585054d400SAlex Crichton .try_lock() 59b81bb7a3SAlex Crichton .unwrap() 60b81bb7a3SAlex Crichton .realloc(ptr, layout.size(), layout.align(), new_size) 61b81bb7a3SAlex Crichton } 62*073aedabSAlex Crichton } 63b81bb7a3SAlex Crichton dealloc(&self, ptr: *mut u8, layout: Layout)64b81bb7a3SAlex Crichton unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { 65*073aedabSAlex Crichton unsafe { 66b81bb7a3SAlex Crichton self.dlmalloc 675054d400SAlex Crichton .try_lock() 68b81bb7a3SAlex Crichton .unwrap() 69b81bb7a3SAlex Crichton .free(ptr, layout.size(), layout.align()) 70b81bb7a3SAlex Crichton } 71b81bb7a3SAlex Crichton } 72*073aedabSAlex Crichton } 73b81bb7a3SAlex Crichton 74b9b0ba49SPat Hickey #[cfg(not(feature = "wasi"))] 75d3132c9dSAlex Crichton const INITIAL_HEAP_SIZE: usize = 64 * 1024; 76b9b0ba49SPat Hickey // The wasi component requires a larger heap than the module tests 77b9b0ba49SPat Hickey #[cfg(feature = "wasi")] 78b9b0ba49SPat Hickey const INITIAL_HEAP_SIZE: usize = 4 * 1024 * 1024; 79b9b0ba49SPat Hickey 80d3132c9dSAlex Crichton static mut INITIAL_HEAP: [u8; INITIAL_HEAP_SIZE] = [0; INITIAL_HEAP_SIZE]; 81d3132c9dSAlex Crichton static mut INITIAL_HEAP_ALLOCATED: bool = false; 82b81bb7a3SAlex Crichton 83b81bb7a3SAlex Crichton unsafe impl dlmalloc::Allocator for MyAllocator { alloc(&self, _size: usize) -> (*mut u8, usize, u32)84d3132c9dSAlex Crichton fn alloc(&self, _size: usize) -> (*mut u8, usize, u32) { 85b81bb7a3SAlex Crichton unsafe { 86d3132c9dSAlex Crichton if INITIAL_HEAP_ALLOCATED { 87b81bb7a3SAlex Crichton (ptr::null_mut(), 0, 0) 88b81bb7a3SAlex Crichton } else { 89d3132c9dSAlex Crichton INITIAL_HEAP_ALLOCATED = true; 9080f44cbbSAlex Crichton ((&raw mut INITIAL_HEAP).cast(), INITIAL_HEAP_SIZE, 0) 91b81bb7a3SAlex Crichton } 92b81bb7a3SAlex Crichton } 93b81bb7a3SAlex Crichton } 94b81bb7a3SAlex Crichton remap(&self, _ptr: *mut u8, _old: usize, _new: usize, _can_move: bool) -> *mut u895b81bb7a3SAlex Crichton fn remap(&self, _ptr: *mut u8, _old: usize, _new: usize, _can_move: bool) -> *mut u8 { 965054d400SAlex Crichton core::ptr::null_mut() 97b81bb7a3SAlex Crichton } 98b81bb7a3SAlex Crichton free_part(&self, _ptr: *mut u8, _old: usize, _new: usize) -> bool99b81bb7a3SAlex Crichton fn free_part(&self, _ptr: *mut u8, _old: usize, _new: usize) -> bool { 100b81bb7a3SAlex Crichton false 101b81bb7a3SAlex Crichton } 102b81bb7a3SAlex Crichton free(&self, _ptr: *mut u8, _size: usize) -> bool103d3132c9dSAlex Crichton fn free(&self, _ptr: *mut u8, _size: usize) -> bool { 104d3132c9dSAlex Crichton false 105b81bb7a3SAlex Crichton } 106b81bb7a3SAlex Crichton can_release_part(&self, _flags: u32) -> bool107b81bb7a3SAlex Crichton fn can_release_part(&self, _flags: u32) -> bool { 108b81bb7a3SAlex Crichton false 109b81bb7a3SAlex Crichton } 110b81bb7a3SAlex Crichton allocates_zeros(&self) -> bool111b81bb7a3SAlex Crichton fn allocates_zeros(&self) -> bool { 112b81bb7a3SAlex Crichton true 113b81bb7a3SAlex Crichton } 114b81bb7a3SAlex Crichton page_size(&self) -> usize115b81bb7a3SAlex Crichton fn page_size(&self) -> usize { 116d3132c9dSAlex Crichton 4096 117b81bb7a3SAlex Crichton } 118b81bb7a3SAlex Crichton } 1195054d400SAlex Crichton 1205054d400SAlex Crichton // Simple mutex which only supports `try_lock` at this time. This would probably 1215054d400SAlex Crichton // be replaced with a "real" mutex in a "real" embedding. 1225054d400SAlex Crichton struct Mutex<T> { 1235054d400SAlex Crichton data: UnsafeCell<T>, 1245054d400SAlex Crichton locked: AtomicBool, 1255054d400SAlex Crichton } 1265054d400SAlex Crichton 1275054d400SAlex Crichton unsafe impl<T: Send> Send for Mutex<T> {} 1285054d400SAlex Crichton unsafe impl<T: Send> Sync for Mutex<T> {} 1295054d400SAlex Crichton 1305054d400SAlex Crichton impl<T> Mutex<T> { new(val: T) -> Mutex<T>1315054d400SAlex Crichton const fn new(val: T) -> Mutex<T> { 1325054d400SAlex Crichton Mutex { 1335054d400SAlex Crichton data: UnsafeCell::new(val), 1345054d400SAlex Crichton locked: AtomicBool::new(false), 1355054d400SAlex Crichton } 1365054d400SAlex Crichton } 1375054d400SAlex Crichton try_lock(&self) -> Option<impl DerefMut<Target = T> + '_>1385054d400SAlex Crichton fn try_lock(&self) -> Option<impl DerefMut<Target = T> + '_> { 1395054d400SAlex Crichton if self.locked.swap(true, Acquire) { 1405054d400SAlex Crichton None 1415054d400SAlex Crichton } else { 1425054d400SAlex Crichton Some(MutexGuard { lock: self }) 1435054d400SAlex Crichton } 1445054d400SAlex Crichton } 1455054d400SAlex Crichton } 1465054d400SAlex Crichton 1475054d400SAlex Crichton struct MutexGuard<'a, T> { 1485054d400SAlex Crichton lock: &'a Mutex<T>, 1495054d400SAlex Crichton } 1505054d400SAlex Crichton 1515054d400SAlex Crichton impl<T> Deref for MutexGuard<'_, T> { 1525054d400SAlex Crichton type Target = T; 1535054d400SAlex Crichton deref(&self) -> &T1545054d400SAlex Crichton fn deref(&self) -> &T { 1555054d400SAlex Crichton unsafe { &*self.lock.data.get() } 1565054d400SAlex Crichton } 1575054d400SAlex Crichton } 1585054d400SAlex Crichton 1595054d400SAlex Crichton impl<T> DerefMut for MutexGuard<'_, T> { deref_mut(&mut self) -> &mut T1605054d400SAlex Crichton fn deref_mut(&mut self) -> &mut T { 1615054d400SAlex Crichton unsafe { &mut *self.lock.data.get() } 1625054d400SAlex Crichton } 1635054d400SAlex Crichton } 1645054d400SAlex Crichton 1655054d400SAlex Crichton impl<T> Drop for MutexGuard<'_, T> { drop(&mut self)1665054d400SAlex Crichton fn drop(&mut self) { 1675054d400SAlex Crichton self.lock.locked.store(false, Release); 1685054d400SAlex Crichton } 1695054d400SAlex Crichton } 170