wasmer_runtime_core_fl/memory/
mod.rs1use crate::{
4 error::{CreationError, GrowError},
5 export::Export,
6 import::IsExport,
7 memory::dynamic::DYNAMIC_GUARD_SIZE,
8 memory::static_::{SAFE_STATIC_GUARD_SIZE, SAFE_STATIC_HEAP_SIZE},
9 types::{MemoryDescriptor, ValueType},
10 units::Pages,
11 vm,
12};
13use std::{cell::Cell, fmt, mem, sync::Arc};
14
15use std::sync::Mutex as StdMutex;
16
17pub use self::dynamic::DynamicMemory;
18pub use self::static_::StaticMemory;
19pub use self::view::{Atomically, MemoryView};
20
21use parking_lot::Mutex;
22
23mod dynamic;
24pub mod ptr;
25mod static_;
26mod view;
27
28#[derive(Clone)]
29enum MemoryVariant {
30 Unshared(UnsharedMemory),
31 Shared(SharedMemory),
32}
33
34#[derive(Clone)]
38pub struct Memory {
39 desc: MemoryDescriptor,
40 variant: MemoryVariant,
41}
42
43impl Memory {
44 pub fn new(desc: MemoryDescriptor) -> Result<Self, CreationError> {
63 if let Some(max) = desc.maximum {
64 if max < desc.minimum {
65 return Err(CreationError::InvalidDescriptor(
66 "Max number of memory pages is less than the minimum number of pages"
67 .to_string(),
68 ));
69 }
70 }
71
72 if desc.shared && desc.maximum.is_none() {
73 return Err(CreationError::InvalidDescriptor(
74 "Max number of pages is required for shared memory".to_string(),
75 ));
76 }
77
78 let variant = if !desc.shared {
79 MemoryVariant::Unshared(UnsharedMemory::new(desc)?)
80 } else {
81 MemoryVariant::Shared(SharedMemory::new(desc)?)
82 };
83
84 Ok(Memory { desc, variant })
85 }
86
87 pub fn descriptor(&self) -> MemoryDescriptor {
92 self.desc
93 }
94
95 pub fn grow(&self, delta: Pages) -> Result<Pages, GrowError> {
97 match &self.variant {
98 MemoryVariant::Unshared(unshared_mem) => unshared_mem.grow(delta),
99 MemoryVariant::Shared(shared_mem) => shared_mem.grow(delta),
100 }
101 }
102
103 pub fn size(&self) -> Pages {
105 match &self.variant {
106 MemoryVariant::Unshared(unshared_mem) => unshared_mem.size(),
107 MemoryVariant::Shared(shared_mem) => shared_mem.size(),
108 }
109 }
110
111 pub fn view<T: ValueType>(&self) -> MemoryView<T> {
145 let vm::LocalMemory { base, .. } = unsafe { *self.vm_local_memory() };
146
147 let length = self.size().bytes().0 / mem::size_of::<T>();
148
149 unsafe { MemoryView::new(base as _, length as u32) }
150 }
151
152 pub fn vm_local_memory(&self) -> *mut vm::LocalMemory {
154 match &self.variant {
155 MemoryVariant::Unshared(unshared_mem) => unshared_mem.vm_local_memory(),
156 MemoryVariant::Shared(shared_mem) => shared_mem.vm_local_memory(),
157 }
158 }
159}
160
161impl IsExport for Memory {
162 fn to_export(&self) -> Export {
163 Export::Memory(self.clone())
164 }
165}
166
167impl fmt::Debug for Memory {
168 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
169 f.debug_struct("Memory")
170 .field("desc", &self.desc)
171 .field("size", &self.size())
172 .finish()
173 }
174}
175
176#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
178pub enum MemoryType {
179 Dynamic,
181 Static,
183 SharedStatic,
185}
186
187impl MemoryType {
188 #[doc(hidden)]
189 pub fn guard_size(self) -> u64 {
190 match self {
191 MemoryType::Dynamic => DYNAMIC_GUARD_SIZE as u64,
192 MemoryType::Static | MemoryType::SharedStatic => SAFE_STATIC_GUARD_SIZE as u64,
193 }
194 }
195
196 #[doc(hidden)]
197 pub fn bounds(self) -> Option<u64> {
198 match self {
199 MemoryType::Dynamic => None,
200 MemoryType::Static | MemoryType::SharedStatic => Some(SAFE_STATIC_HEAP_SIZE as u64),
201 }
202 }
203}
204
205enum UnsharedMemoryStorage {
206 Dynamic(Box<DynamicMemory>),
207 Static(Box<StaticMemory>),
208}
209
210pub struct UnsharedMemory {
212 internal: Arc<UnsharedMemoryInternal>,
213}
214
215struct UnsharedMemoryInternal {
216 storage: StdMutex<UnsharedMemoryStorage>,
217 local: Cell<vm::LocalMemory>,
218}
219
220unsafe impl Sync for UnsharedMemoryInternal {}
223
224impl UnsharedMemory {
225 pub fn new(desc: MemoryDescriptor) -> Result<Self, CreationError> {
227 let mut local = vm::LocalMemory {
228 base: std::ptr::null_mut(),
229 bound: 0,
230 memory: std::ptr::null_mut(),
231 };
232
233 let storage = match desc.memory_type() {
234 MemoryType::Dynamic => {
235 UnsharedMemoryStorage::Dynamic(DynamicMemory::new(desc, &mut local)?)
236 }
237 MemoryType::Static => {
238 UnsharedMemoryStorage::Static(StaticMemory::new(desc, &mut local)?)
239 }
240 MemoryType::SharedStatic => {
241 return Err(CreationError::InvalidDescriptor(
242 "attempting to create shared unshared memory".to_string(),
243 ));
244 }
245 };
246
247 Ok(Self {
248 internal: Arc::new(UnsharedMemoryInternal {
249 storage: StdMutex::new(storage),
250 local: Cell::new(local),
251 }),
252 })
253 }
254
255 pub fn grow(&self, delta: Pages) -> Result<Pages, GrowError> {
257 let mut storage = self.internal.storage.lock().unwrap();
258
259 let mut local = self.internal.local.get();
260
261 let pages = match &mut *storage {
262 UnsharedMemoryStorage::Dynamic(dynamic_memory) => {
263 dynamic_memory.grow(delta, &mut local)
264 }
265 UnsharedMemoryStorage::Static(static_memory) => static_memory.grow(delta, &mut local),
266 };
267
268 self.internal.local.set(local);
269
270 pages
271 }
272
273 pub fn size(&self) -> Pages {
275 let storage = self.internal.storage.lock().unwrap();
276
277 match &*storage {
278 UnsharedMemoryStorage::Dynamic(ref dynamic_memory) => dynamic_memory.size(),
279 UnsharedMemoryStorage::Static(ref static_memory) => static_memory.size(),
280 }
281 }
282
283 pub(crate) fn vm_local_memory(&self) -> *mut vm::LocalMemory {
284 self.internal.local.as_ptr()
285 }
286}
287
288impl Clone for UnsharedMemory {
289 fn clone(&self) -> Self {
290 UnsharedMemory {
291 internal: Arc::clone(&self.internal),
292 }
293 }
294}
295
296pub struct SharedMemory {
298 internal: Arc<SharedMemoryInternal>,
299}
300
301pub struct SharedMemoryInternal {
303 memory: StdMutex<Box<StaticMemory>>,
304 local: Cell<vm::LocalMemory>,
305 lock: Mutex<()>,
306}
307
308unsafe impl Sync for SharedMemoryInternal {}
311
312impl SharedMemory {
313 fn new(desc: MemoryDescriptor) -> Result<Self, CreationError> {
314 let mut local = vm::LocalMemory {
315 base: std::ptr::null_mut(),
316 bound: 0,
317 memory: std::ptr::null_mut(),
318 };
319
320 let memory = StaticMemory::new(desc, &mut local)?;
321
322 Ok(Self {
323 internal: Arc::new(SharedMemoryInternal {
324 memory: StdMutex::new(memory),
325 local: Cell::new(local),
326 lock: Mutex::new(()),
327 }),
328 })
329 }
330
331 pub fn grow(&self, delta: Pages) -> Result<Pages, GrowError> {
333 let _guard = self.internal.lock.lock();
334 let mut local = self.internal.local.get();
335 let mut memory = self.internal.memory.lock().unwrap();
336 let pages = memory.grow(delta, &mut local);
337 pages
338 }
339
340 pub fn size(&self) -> Pages {
342 let _guard = self.internal.lock.lock();
343 let memory = self.internal.memory.lock().unwrap();
344 memory.size()
345 }
346
347 pub(crate) fn vm_local_memory(&self) -> *mut vm::LocalMemory {
350 self.internal.local.as_ptr()
351 }
352}
353
354impl Clone for SharedMemory {
355 fn clone(&self) -> Self {
356 SharedMemory {
357 internal: Arc::clone(&self.internal),
358 }
359 }
360}
361
362#[cfg(test)]
363mod memory_tests {
364
365 use super::{Memory, MemoryDescriptor, Pages};
366
367 #[test]
368 fn test_initial_memory_size() {
369 let memory_desc = MemoryDescriptor::new(Pages(10), Some(Pages(20)), false).unwrap();
370 let unshared_memory = Memory::new(memory_desc).unwrap();
371 assert_eq!(unshared_memory.size(), Pages(10));
372 }
373
374 #[test]
375 fn test_invalid_descriptor_returns_error() {
376 let memory_desc = MemoryDescriptor::new(Pages(10), None, true);
377 assert!(
378 memory_desc.is_err(),
379 "Max number of pages is required for shared memory"
380 )
381 }
382}