Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/examples/min-platform/embedding/src/allocator.rs
2450 views
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 alloc::alloc::{GlobalAlloc, Layout};
16
use core::cell::UnsafeCell;
17
use core::ops::{Deref, DerefMut};
18
use core::ptr;
19
use core::sync::atomic::{
20
AtomicBool,
21
Ordering::{Acquire, Release},
22
};
23
use dlmalloc::Dlmalloc;
24
25
#[global_allocator]
26
static MALLOC: MyGlobalDmalloc = MyGlobalDmalloc {
27
dlmalloc: Mutex::new(Dlmalloc::new_with_allocator(MyAllocator)),
28
};
29
30
struct MyGlobalDmalloc {
31
dlmalloc: Mutex<Dlmalloc<MyAllocator>>,
32
}
33
34
struct MyAllocator;
35
36
unsafe impl GlobalAlloc for MyGlobalDmalloc {
37
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
38
unsafe {
39
self.dlmalloc
40
.try_lock()
41
.unwrap()
42
.malloc(layout.size(), layout.align())
43
}
44
}
45
46
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
47
unsafe {
48
self.dlmalloc
49
.try_lock()
50
.unwrap()
51
.calloc(layout.size(), layout.align())
52
}
53
}
54
55
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
56
unsafe {
57
self.dlmalloc
58
.try_lock()
59
.unwrap()
60
.realloc(ptr, layout.size(), layout.align(), new_size)
61
}
62
}
63
64
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
65
unsafe {
66
self.dlmalloc
67
.try_lock()
68
.unwrap()
69
.free(ptr, layout.size(), layout.align())
70
}
71
}
72
}
73
74
#[cfg(not(feature = "wasi"))]
75
const INITIAL_HEAP_SIZE: usize = 64 * 1024;
76
// The wasi component requires a larger heap than the module tests
77
#[cfg(feature = "wasi")]
78
const INITIAL_HEAP_SIZE: usize = 4 * 1024 * 1024;
79
80
static mut INITIAL_HEAP: [u8; INITIAL_HEAP_SIZE] = [0; INITIAL_HEAP_SIZE];
81
static mut INITIAL_HEAP_ALLOCATED: bool = false;
82
83
unsafe impl dlmalloc::Allocator for MyAllocator {
84
fn alloc(&self, _size: usize) -> (*mut u8, usize, u32) {
85
unsafe {
86
if INITIAL_HEAP_ALLOCATED {
87
(ptr::null_mut(), 0, 0)
88
} else {
89
INITIAL_HEAP_ALLOCATED = true;
90
((&raw mut INITIAL_HEAP).cast(), INITIAL_HEAP_SIZE, 0)
91
}
92
}
93
}
94
95
fn remap(&self, _ptr: *mut u8, _old: usize, _new: usize, _can_move: bool) -> *mut u8 {
96
core::ptr::null_mut()
97
}
98
99
fn free_part(&self, _ptr: *mut u8, _old: usize, _new: usize) -> bool {
100
false
101
}
102
103
fn free(&self, _ptr: *mut u8, _size: usize) -> bool {
104
false
105
}
106
107
fn can_release_part(&self, _flags: u32) -> bool {
108
false
109
}
110
111
fn allocates_zeros(&self) -> bool {
112
true
113
}
114
115
fn page_size(&self) -> usize {
116
4096
117
}
118
}
119
120
// Simple mutex which only supports `try_lock` at this time. This would probably
121
// be replaced with a "real" mutex in a "real" embedding.
122
struct Mutex<T> {
123
data: UnsafeCell<T>,
124
locked: AtomicBool,
125
}
126
127
unsafe impl<T: Send> Send for Mutex<T> {}
128
unsafe impl<T: Send> Sync for Mutex<T> {}
129
130
impl<T> Mutex<T> {
131
const fn new(val: T) -> Mutex<T> {
132
Mutex {
133
data: UnsafeCell::new(val),
134
locked: AtomicBool::new(false),
135
}
136
}
137
138
fn try_lock(&self) -> Option<impl DerefMut<Target = T> + '_> {
139
if self.locked.swap(true, Acquire) {
140
None
141
} else {
142
Some(MutexGuard { lock: self })
143
}
144
}
145
}
146
147
struct MutexGuard<'a, T> {
148
lock: &'a Mutex<T>,
149
}
150
151
impl<T> Deref for MutexGuard<'_, T> {
152
type Target = T;
153
154
fn deref(&self) -> &T {
155
unsafe { &*self.lock.data.get() }
156
}
157
}
158
159
impl<T> DerefMut for MutexGuard<'_, T> {
160
fn deref_mut(&mut self) -> &mut T {
161
unsafe { &mut *self.lock.data.get() }
162
}
163
}
164
165
impl<T> Drop for MutexGuard<'_, T> {
166
fn drop(&mut self) {
167
self.lock.locked.store(false, Release);
168
}
169
}
170
171