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