1use std::{
8 cell::UnsafeCell,
9 convert::TryInto,
10 ptr::NonNull,
11 sync::{Arc, RwLock},
12};
13
14use wasmer::{Bytes, MemoryError, MemoryType, Pages};
15use wasmer_types::{MemoryStyle, WASM_PAGE_SIZE};
16use wasmer_vm::{
17 LinearMemory, MaybeInstanceOwned, ThreadConditions, Trap, VMMemoryDefinition, WaiterError,
18};
19
20use super::fd_mmap::FdMmap;
21
22#[derive(Debug)]
34struct WasmMmap {
35 alloc: FdMmap,
37 size: Pages,
39 vm_memory_definition: MaybeInstanceOwned<VMMemoryDefinition>,
41}
42
43unsafe impl Send for WasmMmap {}
47unsafe impl Sync for WasmMmap {}
49
50impl WasmMmap {
51 fn get_vm_memory_definition(&self) -> NonNull<VMMemoryDefinition> {
52 self.vm_memory_definition.as_ptr()
53 }
54
55 fn size(&self) -> Pages {
56 unsafe {
57 let md_ptr = self.get_vm_memory_definition();
58 let md = md_ptr.as_ref();
59 Bytes::from(md.current_length).try_into().unwrap()
60 }
61 }
62
63 fn grow(&mut self, delta: Pages, conf: VMMemoryConfig) -> Result<Pages, MemoryError> {
64 if delta.0 == 0 {
66 return Ok(self.size);
67 }
68
69 let new_pages = self
70 .size
71 .checked_add(delta)
72 .ok_or(MemoryError::CouldNotGrow {
73 current: self.size,
74 attempted_delta: delta,
75 })?;
76 let prev_pages = self.size;
77
78 if let Some(maximum) = conf.maximum
79 && new_pages > maximum
80 {
81 return Err(MemoryError::CouldNotGrow {
82 current: self.size,
83 attempted_delta: delta,
84 });
85 }
86
87 if new_pages >= Pages::max_value() {
91 return Err(MemoryError::CouldNotGrow {
93 current: self.size,
94 attempted_delta: delta,
95 });
96 }
97
98 let delta_bytes = delta.bytes().0;
99 let prev_bytes = prev_pages.bytes().0;
100 let new_bytes = new_pages.bytes().0;
101
102 if new_bytes > self.alloc.len() - conf.offset_guard_size {
103 let guard_bytes = conf.offset_guard_size;
106 let request_bytes =
107 new_bytes
108 .checked_add(guard_bytes)
109 .ok_or_else(|| MemoryError::CouldNotGrow {
110 current: new_pages,
111 attempted_delta: Bytes(guard_bytes).try_into().unwrap(),
112 })?;
113
114 let mut new_mmap = FdMmap::accessible_reserved(new_bytes, request_bytes)
115 .map_err(MemoryError::Region)?;
116
117 let copy_len = self.alloc.len() - conf.offset_guard_size;
118 new_mmap.as_mut_slice()[..copy_len].copy_from_slice(&self.alloc.as_slice()[..copy_len]);
119
120 self.alloc = new_mmap;
121 } else if delta_bytes > 0 {
122 self.alloc
124 .make_accessible(prev_bytes, delta_bytes)
125 .map_err(MemoryError::Region)?;
126 }
127
128 self.size = new_pages;
129
130 unsafe {
132 let mut md_ptr = self.vm_memory_definition.as_ptr();
133 let md = md_ptr.as_mut();
134 md.current_length = new_pages.bytes().0;
135 md.base = self.alloc.as_mut_ptr() as _;
136 }
137
138 Ok(prev_pages)
139 }
140
141 fn grow_at_least(&mut self, min_size: u64, conf: VMMemoryConfig) -> Result<(), MemoryError> {
144 let cur_size = self.size.bytes().0 as u64;
145 if cur_size < min_size {
146 let growth = min_size - cur_size;
147 let growth_pages = ((growth - 1) / WASM_PAGE_SIZE as u64) + 1;
148 self.grow(Pages(growth_pages as u32), conf)?;
149 }
150
151 Ok(())
152 }
153
154 fn reset(&mut self) -> Result<(), MemoryError> {
155 self.size.0 = 0;
156 Ok(())
157 }
158
159 pub fn copy(&self) -> Result<Self, MemoryError> {
162 let mem_length = self.size.bytes().0;
163 let mut alloc = self
164 .alloc
165 .duplicate(Some(mem_length))
166 .map_err(MemoryError::Generic)?;
167 let base_ptr = alloc.as_mut_ptr();
168 Ok(Self {
169 vm_memory_definition: MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(
170 VMMemoryDefinition {
171 base: base_ptr,
172 current_length: mem_length,
173 },
174 ))),
175 alloc,
176 size: self.size,
177 })
178 }
179}
180
181#[derive(Debug, Clone)]
183struct VMMemoryConfig {
184 maximum: Option<Pages>,
186 memory: MemoryType,
188 style: MemoryStyle,
190 offset_guard_size: usize,
193}
194
195impl VMMemoryConfig {
196 fn ty(&self, minimum: Pages) -> MemoryType {
197 let mut out = self.memory;
198 out.minimum = minimum;
199
200 out
201 }
202
203 fn style(&self) -> MemoryStyle {
204 self.style
205 }
206}
207
208#[derive(Debug)]
210pub struct VMOwnedMemory {
211 mmap: WasmMmap,
213 config: VMMemoryConfig,
215}
216
217unsafe impl Send for VMOwnedMemory {}
218unsafe impl Sync for VMOwnedMemory {}
219
220impl VMOwnedMemory {
221 pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result<Self, MemoryError> {
226 unsafe { Self::new_internal(memory, style, None) }
227 }
228
229 pub unsafe fn from_definition(
237 memory: &MemoryType,
238 style: &MemoryStyle,
239 vm_memory_location: NonNull<VMMemoryDefinition>,
240 ) -> Result<Self, MemoryError> {
241 unsafe { Self::new_internal(memory, style, Some(vm_memory_location)) }
242 }
243
244 unsafe fn new_internal(
246 memory: &MemoryType,
247 style: &MemoryStyle,
248 vm_memory_location: Option<NonNull<VMMemoryDefinition>>,
249 ) -> Result<Self, MemoryError> {
250 if memory.minimum > Pages::max_value() {
251 return Err(MemoryError::MinimumMemoryTooLarge {
252 min_requested: memory.minimum,
253 max_allowed: Pages::max_value(),
254 });
255 }
256 if let Some(max) = memory.maximum {
258 if max > Pages::max_value() {
259 return Err(MemoryError::MaximumMemoryTooLarge {
260 max_requested: max,
261 max_allowed: Pages::max_value(),
262 });
263 }
264 if max < memory.minimum {
265 return Err(MemoryError::InvalidMemory {
266 reason: format!(
267 "the maximum ({} pages) is less than the minimum ({} pages)",
268 max.0, memory.minimum.0
269 ),
270 });
271 }
272 }
273
274 let offset_guard_bytes = usize::try_from(style.offset_guard_size())
275 .map_err(|e| MemoryError::Generic(format!("cannot install memory guard page: {e}")))?;
276
277 let minimum_pages = match style {
278 MemoryStyle::Dynamic { .. } => memory.minimum,
279 MemoryStyle::Static => {
280 let bound = MemoryStyle::static_bound();
281 assert!(bound >= memory.minimum);
282 bound
283 }
284 };
285 let minimum_bytes = minimum_pages.bytes().0;
286 let request_bytes = minimum_bytes.checked_add(offset_guard_bytes).unwrap();
287 let mapped_pages = memory.minimum;
288 let mapped_bytes = mapped_pages.bytes();
289
290 let mut alloc = FdMmap::accessible_reserved(mapped_bytes.0, request_bytes)
291 .map_err(MemoryError::Region)?;
292 let base_ptr = alloc.as_mut_ptr();
293 let mem_length = memory.minimum.bytes().0;
294 let mmap = WasmMmap {
295 vm_memory_definition: if let Some(mem_loc) = vm_memory_location {
296 {
297 let mut ptr = mem_loc;
298 let md = unsafe { ptr.as_mut() };
299 md.base = base_ptr;
300 md.current_length = mem_length;
301 }
302 MaybeInstanceOwned::Instance(mem_loc)
303 } else {
304 MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(VMMemoryDefinition {
305 base: base_ptr,
306 current_length: mem_length,
307 })))
308 },
309 alloc,
310 size: memory.minimum,
311 };
312
313 Ok(Self {
314 mmap,
315 config: VMMemoryConfig {
316 maximum: memory.maximum,
317 offset_guard_size: offset_guard_bytes,
318 memory: *memory,
319 style: *style,
320 },
321 })
322 }
323
324 pub fn to_shared(self) -> VMSharedMemory {
326 VMSharedMemory {
327 mmap: Arc::new(RwLock::new(self.mmap)),
328 config: self.config,
329 conditions: ThreadConditions::new(),
330 }
331 }
332
333 pub fn copy(&self) -> Result<Self, MemoryError> {
335 Ok(Self {
336 mmap: self.mmap.copy()?,
337 config: self.config.clone(),
338 })
339 }
340}
341
342impl LinearMemory for VMOwnedMemory {
343 fn ty(&self) -> MemoryType {
345 let minimum = self.mmap.size();
346 self.config.ty(minimum)
347 }
348
349 fn size(&self) -> Pages {
351 self.mmap.size()
352 }
353
354 fn style(&self) -> MemoryStyle {
356 self.config.style()
357 }
358
359 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
364 self.mmap.grow(delta, self.config.clone())
365 }
366
367 fn grow_at_least(&mut self, min_size: u64) -> Result<(), MemoryError> {
370 self.mmap.grow_at_least(min_size, self.config.clone())
371 }
372
373 fn reset(&mut self) -> Result<(), MemoryError> {
374 self.mmap.reset()?;
375 Ok(())
376 }
377
378 fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
380 self.mmap.vm_memory_definition.as_ptr()
381 }
382
383 fn try_clone(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
385 Err(MemoryError::MemoryNotShared)
386 }
387
388 fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
390 let forked = Self::copy(self)?;
391 Ok(Box::new(forked))
392 }
393}
394
395#[derive(Debug, Clone)]
397pub struct VMSharedMemory {
398 mmap: Arc<RwLock<WasmMmap>>,
400 config: VMMemoryConfig,
402 conditions: ThreadConditions,
403}
404
405impl VMSharedMemory {
406 pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result<Self, MemoryError> {
411 Ok(VMOwnedMemory::new(memory, style)?.to_shared())
412 }
413
414 pub unsafe fn from_definition(
422 memory: &MemoryType,
423 style: &MemoryStyle,
424 vm_memory_location: NonNull<VMMemoryDefinition>,
425 ) -> Result<Self, MemoryError> {
426 let owned = unsafe { VMOwnedMemory::from_definition(memory, style, vm_memory_location)? };
427 Ok(owned.to_shared())
428 }
429
430 pub fn copy(&self) -> Result<Self, MemoryError> {
432 let guard = self.mmap.read().unwrap();
433 Ok(Self {
434 mmap: Arc::new(RwLock::new(guard.copy()?)),
435 config: self.config.clone(),
436 conditions: ThreadConditions::new(),
437 })
438 }
439}
440
441impl LinearMemory for VMSharedMemory {
442 fn ty(&self) -> MemoryType {
444 let minimum = {
445 let guard = self.mmap.read().unwrap();
446 guard.size()
447 };
448 self.config.ty(minimum)
449 }
450
451 fn size(&self) -> Pages {
453 let guard = self.mmap.read().unwrap();
454 guard.size()
455 }
456
457 fn reset(&mut self) -> Result<(), MemoryError> {
459 let mut guard = self.mmap.write().unwrap();
460 guard.reset()?;
461 Ok(())
462 }
463
464 fn style(&self) -> MemoryStyle {
466 self.config.style()
467 }
468
469 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
474 let mut guard = self.mmap.write().unwrap();
475 guard.grow(delta, self.config.clone())
476 }
477
478 fn grow_at_least(&mut self, min_size: u64) -> Result<(), MemoryError> {
481 let mut guard = self.mmap.write().unwrap();
482 guard.grow_at_least(min_size, self.config.clone())
483 }
484
485 fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
487 let guard = self.mmap.read().unwrap();
488 guard.vm_memory_definition.as_ptr()
489 }
490
491 fn try_clone(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
493 Ok(Box::new(self.clone()))
494 }
495
496 fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
498 let forked = Self::copy(self)?;
499 Ok(Box::new(forked))
500 }
501
502 unsafe fn do_wait(
503 &mut self,
504 dst: u32,
505 expected: wasmer_vm::ExpectedValue,
506 timeout: Option<std::time::Duration>,
507 ) -> Result<u32, WaiterError> {
508 unsafe {
509 let dst = wasmer_vm::NotifyLocation {
510 address: dst,
511 memory_base: self
512 .mmap
513 .read()
514 .unwrap()
515 .vm_memory_definition
516 .as_ptr()
517 .as_ref()
518 .base,
519 };
520 self.conditions.do_wait(dst, expected, timeout)
521 }
522 }
523
524 fn do_notify(&mut self, dst: u32, count: u32) -> u32 {
525 self.conditions.do_notify(dst, count)
526 }
527}
528
529impl From<VMOwnedMemory> for VMMemory {
530 fn from(mem: VMOwnedMemory) -> Self {
531 Self(Box::new(mem))
532 }
533}
534
535impl From<VMSharedMemory> for VMMemory {
536 fn from(mem: VMSharedMemory) -> Self {
537 Self(Box::new(mem))
538 }
539}
540
541#[derive(Debug)]
543pub struct VMMemory(pub Box<dyn LinearMemory + 'static>);
544
545impl From<Box<dyn LinearMemory + 'static>> for VMMemory {
546 fn from(mem: Box<dyn LinearMemory + 'static>) -> Self {
547 Self(mem)
548 }
549}
550
551impl LinearMemory for VMMemory {
552 fn ty(&self) -> MemoryType {
554 self.0.ty()
555 }
556
557 fn size(&self) -> Pages {
559 self.0.size()
560 }
561
562 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
567 self.0.grow(delta)
568 }
569
570 fn grow_at_least(&mut self, min_size: u64) -> Result<(), MemoryError> {
573 self.0.grow_at_least(min_size)
574 }
575
576 fn reset(&mut self) -> Result<(), MemoryError> {
578 self.0.reset()?;
579 Ok(())
580 }
581
582 fn style(&self) -> MemoryStyle {
584 self.0.style()
585 }
586
587 fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
589 self.0.vmmemory()
590 }
591
592 fn try_clone(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
594 self.0.try_clone()
595 }
596
597 unsafe fn initialize_with_data(&self, start: usize, data: &[u8]) -> Result<(), Trap> {
599 unsafe { self.0.initialize_with_data(start, data) }
600 }
601
602 fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
604 self.0.copy()
605 }
606}
607
608impl VMMemory {
609 pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result<Self, MemoryError> {
615 Ok(if memory.shared {
616 Self(Box::new(VMSharedMemory::new(memory, style)?))
617 } else {
618 Self(Box::new(VMOwnedMemory::new(memory, style)?))
619 })
620 }
621
622 pub fn get_runtime_size(&self) -> u32 {
624 self.0.size().0
625 }
626
627 pub unsafe fn from_definition(
635 memory: &MemoryType,
636 style: &MemoryStyle,
637 vm_memory_location: NonNull<VMMemoryDefinition>,
638 ) -> Result<Self, MemoryError> {
639 Ok(if memory.shared {
640 let shared =
641 unsafe { VMSharedMemory::from_definition(memory, style, vm_memory_location)? };
642 Self(Box::new(shared))
643 } else {
644 let owned =
645 unsafe { VMOwnedMemory::from_definition(memory, style, vm_memory_location)? };
646 Self(Box::new(owned))
647 })
648 }
649
650 pub fn from_custom<IntoVMMemory>(memory: IntoVMMemory) -> Self
655 where
656 IntoVMMemory: Into<Self>,
657 {
658 memory.into()
659 }
660
661 pub fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
663 LinearMemory::copy(self)
664 }
665}
666
667#[doc(hidden)]
668pub unsafe fn initialize_memory_with_data(
670 memory: &VMMemoryDefinition,
671 start: usize,
672 data: &[u8],
673) -> Result<(), Trap> {
674 let mem_slice = unsafe { std::slice::from_raw_parts_mut(memory.base, memory.current_length) };
675 let end = start + data.len();
676 let to_init = &mut mem_slice[start..end];
677 to_init.copy_from_slice(data);
678
679 Ok(())
680}