1 //! An allocator definition for this embedding. 2 //! 3 //! The Rust standard library and Wasmtime require a memory allocator to be 4 //! configured. For custom embeddings of Wasmtime this might likely already be 5 //! defined elsewhere in the system in which case that should be used. This file 6 //! contains an example implementation using the Rust `dlmalloc` crate using 7 //! memory created by `wasmtime_*` platform symbols. This provides a file that 8 //! manages memory without any extra runtime dependencies, but this is just an 9 //! example. 10 //! 11 //! Allocators in Rust are configured with the `#[global_allocator]` attribute 12 //! and the `GlobalAlloc for T` trait impl. This should be used when hooking 13 //! up to an allocator elsewhere in the system. 14 15 use dlmalloc::Dlmalloc; 16 use std::alloc::{GlobalAlloc, Layout}; 17 use std::ptr; 18 use std::sync::Mutex; 19 20 #[global_allocator] 21 static MALLOC: MyGlobalDmalloc = MyGlobalDmalloc { 22 dlmalloc: Mutex::new(Dlmalloc::new_with_allocator(MyAllocator)), 23 }; 24 25 struct MyGlobalDmalloc { 26 dlmalloc: Mutex<Dlmalloc<MyAllocator>>, 27 } 28 29 unsafe impl Send for MyGlobalDmalloc {} 30 unsafe impl Sync for MyGlobalDmalloc {} 31 32 struct MyAllocator; 33 34 unsafe impl GlobalAlloc for MyGlobalDmalloc { 35 unsafe fn alloc(&self, layout: Layout) -> *mut u8 { 36 self.dlmalloc 37 .lock() 38 .unwrap() 39 .malloc(layout.size(), layout.align()) 40 } 41 42 unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { 43 self.dlmalloc 44 .lock() 45 .unwrap() 46 .calloc(layout.size(), layout.align()) 47 } 48 49 unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { 50 self.dlmalloc 51 .lock() 52 .unwrap() 53 .realloc(ptr, layout.size(), layout.align(), new_size) 54 } 55 56 unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { 57 self.dlmalloc 58 .lock() 59 .unwrap() 60 .free(ptr, layout.size(), layout.align()) 61 } 62 } 63 64 // Hand-copied from `crates/runtime/src/sys/custom/capi.rs`. 65 const PROT_READ: u32 = 1 << 0; 66 const PROT_WRITE: u32 = 1 << 1; 67 extern "C" { 68 fn wasmtime_mmap_new(size: usize, prot_flags: u32, ret: &mut *mut u8) -> i32; 69 fn wasmtime_page_size() -> usize; 70 fn wasmtime_munmap(ptr: *mut u8, size: usize) -> i32; 71 } 72 73 unsafe impl dlmalloc::Allocator for MyAllocator { 74 fn alloc(&self, size: usize) -> (*mut u8, usize, u32) { 75 unsafe { 76 let mut ptr = ptr::null_mut(); 77 let rc = wasmtime_mmap_new(size, PROT_READ | PROT_WRITE, &mut ptr); 78 if rc != 0 { 79 (ptr::null_mut(), 0, 0) 80 } else { 81 (ptr, size, 0) 82 } 83 } 84 } 85 86 fn remap(&self, _ptr: *mut u8, _old: usize, _new: usize, _can_move: bool) -> *mut u8 { 87 std::ptr::null_mut() 88 } 89 90 fn free_part(&self, _ptr: *mut u8, _old: usize, _new: usize) -> bool { 91 false 92 } 93 94 fn free(&self, ptr: *mut u8, size: usize) -> bool { 95 unsafe { 96 wasmtime_munmap(ptr, size); 97 true 98 } 99 } 100 101 fn can_release_part(&self, _flags: u32) -> bool { 102 false 103 } 104 105 fn allocates_zeros(&self) -> bool { 106 true 107 } 108 109 fn page_size(&self) -> usize { 110 unsafe { wasmtime_page_size() } 111 } 112 } 113