1use crate::mmap::MmapType;
9use crate::threadconditions::ThreadConditions;
10pub use crate::threadconditions::{NotifyLocation, WaiterError};
11use crate::trap::Trap;
12use crate::{mmap::Mmap, store::MaybeInstanceOwned, vmcontext::VMMemoryDefinition};
13use more_asserts::assert_ge;
14use std::cell::UnsafeCell;
15use std::convert::TryInto;
16use std::ptr::NonNull;
17use std::rc::Rc;
18use std::slice;
19use std::sync::RwLock;
20use std::time::Duration;
21use wasmer_types::{Bytes, MemoryError, MemoryStyle, MemoryType, Pages, WASM_PAGE_SIZE};
22
23#[derive(Debug)]
25struct WasmMmap {
26 alloc: Mmap,
28 size: Pages,
30 vm_memory_definition: MaybeInstanceOwned<VMMemoryDefinition>,
32}
33
34impl WasmMmap {
35 fn get_vm_memory_definition(&self) -> NonNull<VMMemoryDefinition> {
36 self.vm_memory_definition.as_ptr()
37 }
38
39 fn size(&self) -> Pages {
40 unsafe {
41 let md_ptr = self.get_vm_memory_definition();
42 let md = md_ptr.as_ref();
43 Bytes::from(md.current_length).try_into().unwrap()
44 }
45 }
46
47 fn grow(&mut self, delta: Pages, conf: VMMemoryConfig) -> Result<Pages, MemoryError> {
48 if delta.0 == 0 {
50 return Ok(self.size);
51 }
52
53 let new_pages = self
54 .size
55 .checked_add(delta)
56 .ok_or(MemoryError::CouldNotGrow {
57 current: self.size,
58 attempted_delta: delta,
59 })?;
60 let prev_pages = self.size;
61
62 if let Some(maximum) = conf.maximum {
63 if new_pages > maximum {
64 return Err(MemoryError::CouldNotGrow {
65 current: self.size,
66 attempted_delta: delta,
67 });
68 }
69 }
70
71 if new_pages > Pages::max_value() {
75 return Err(MemoryError::CouldNotGrow {
77 current: self.size,
78 attempted_delta: delta,
79 });
80 }
81
82 let delta_bytes = delta.bytes().0;
83 let prev_bytes = prev_pages.bytes().0;
84 let new_bytes = new_pages.bytes().0;
85
86 if new_bytes > self.alloc.len() - conf.offset_guard_size {
87 let guard_bytes = conf.offset_guard_size;
90 let request_bytes =
91 new_bytes
92 .checked_add(guard_bytes)
93 .ok_or_else(|| MemoryError::CouldNotGrow {
94 current: new_pages,
95 attempted_delta: Bytes(guard_bytes).try_into().unwrap(),
96 })?;
97
98 let mut new_mmap =
99 Mmap::accessible_reserved(new_bytes, request_bytes, None, MmapType::Private)
100 .map_err(MemoryError::Region)?;
101
102 let copy_len = self.alloc.len() - conf.offset_guard_size;
103 new_mmap.as_mut_slice()[..copy_len].copy_from_slice(&self.alloc.as_slice()[..copy_len]);
104
105 self.alloc = new_mmap;
106 } else if delta_bytes > 0 {
107 self.alloc
109 .make_accessible(prev_bytes, delta_bytes)
110 .map_err(MemoryError::Region)?;
111 }
112
113 self.size = new_pages;
114
115 unsafe {
117 let mut md_ptr = self.vm_memory_definition.as_ptr();
118 let md = md_ptr.as_mut();
119 md.current_length = new_pages.bytes().0;
120 md.base = self.alloc.as_mut_ptr() as _;
121 }
122
123 Ok(prev_pages)
124 }
125
126 fn grow_at_least(&mut self, min_size: u64, conf: VMMemoryConfig) -> Result<(), MemoryError> {
129 let cur_size = self.size.bytes().0 as u64;
130 if cur_size < min_size {
131 let growth = min_size - cur_size;
132 let growth_pages = ((growth - 1) / WASM_PAGE_SIZE as u64) + 1;
133 self.grow(Pages(growth_pages as u32), conf)?;
134 }
135
136 Ok(())
137 }
138
139 fn reset(&mut self) -> Result<(), MemoryError> {
141 self.size.0 = 0;
142 Ok(())
143 }
144
145 pub fn copy(&mut self) -> Result<Self, MemoryError> {
148 let mem_length = self.size.bytes().0;
149 let mut alloc = self
150 .alloc
151 .copy(Some(mem_length))
152 .map_err(MemoryError::Generic)?;
153 let base_ptr = alloc.as_mut_ptr();
154 Ok(Self {
155 vm_memory_definition: MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(
156 VMMemoryDefinition {
157 base: base_ptr,
158 current_length: mem_length,
159 },
160 ))),
161 alloc,
162 size: self.size,
163 })
164 }
165}
166
167#[derive(Debug, Clone)]
169struct VMMemoryConfig {
170 maximum: Option<Pages>,
172 memory: MemoryType,
174 style: MemoryStyle,
176 offset_guard_size: usize,
179}
180
181impl VMMemoryConfig {
182 fn ty(&self, minimum: Pages) -> MemoryType {
183 let mut out = self.memory;
184 out.minimum = minimum;
185
186 out
187 }
188
189 fn style(&self) -> MemoryStyle {
190 self.style
191 }
192}
193
194#[derive(Debug)]
196pub struct VMOwnedMemory {
197 mmap: WasmMmap,
199 config: VMMemoryConfig,
201}
202
203unsafe impl Send for VMOwnedMemory {}
204unsafe impl Sync for VMOwnedMemory {}
205
206impl VMOwnedMemory {
207 pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result<Self, MemoryError> {
212 unsafe { Self::new_internal(memory, style, None, None, MmapType::Private) }
213 }
214
215 pub fn new_with_file(
222 memory: &MemoryType,
223 style: &MemoryStyle,
224 backing_file: std::path::PathBuf,
225 memory_type: MmapType,
226 ) -> Result<Self, MemoryError> {
227 unsafe { Self::new_internal(memory, style, None, Some(backing_file), memory_type) }
228 }
229
230 pub unsafe fn from_definition(
238 memory: &MemoryType,
239 style: &MemoryStyle,
240 vm_memory_location: NonNull<VMMemoryDefinition>,
241 ) -> Result<Self, MemoryError> {
242 unsafe {
243 Self::new_internal(
244 memory,
245 style,
246 Some(vm_memory_location),
247 None,
248 MmapType::Private,
249 )
250 }
251 }
252
253 pub unsafe fn from_definition_with_file(
263 memory: &MemoryType,
264 style: &MemoryStyle,
265 vm_memory_location: NonNull<VMMemoryDefinition>,
266 backing_file: Option<std::path::PathBuf>,
267 memory_type: MmapType,
268 ) -> Result<Self, MemoryError> {
269 unsafe {
270 Self::new_internal(
271 memory,
272 style,
273 Some(vm_memory_location),
274 backing_file,
275 memory_type,
276 )
277 }
278 }
279
280 unsafe fn new_internal(
282 memory: &MemoryType,
283 style: &MemoryStyle,
284 vm_memory_location: Option<NonNull<VMMemoryDefinition>>,
285 backing_file: Option<std::path::PathBuf>,
286 memory_type: MmapType,
287 ) -> Result<Self, MemoryError> {
288 unsafe {
289 if memory.minimum > Pages::max_value() {
290 return Err(MemoryError::MinimumMemoryTooLarge {
291 min_requested: memory.minimum,
292 max_allowed: Pages::max_value(),
293 });
294 }
295 if let Some(max) = memory.maximum {
297 if max > Pages::max_value() {
298 return Err(MemoryError::MaximumMemoryTooLarge {
299 max_requested: max,
300 max_allowed: Pages::max_value(),
301 });
302 }
303 if max < memory.minimum {
304 return Err(MemoryError::InvalidMemory {
305 reason: format!(
306 "the maximum ({} pages) is less than the minimum ({} pages)",
307 max.0, memory.minimum.0
308 ),
309 });
310 }
311 }
312
313 let offset_guard_bytes = style.offset_guard_size() as usize;
314
315 let minimum_pages = match style {
316 MemoryStyle::Dynamic { .. } => memory.minimum,
317 MemoryStyle::Static { bound, .. } => {
318 assert_ge!(*bound, memory.minimum);
319 *bound
320 }
321 };
322 let minimum_bytes = minimum_pages.bytes().0;
323 let request_bytes = minimum_bytes.checked_add(offset_guard_bytes).unwrap();
324 let mapped_pages = memory.minimum;
325 let mapped_bytes = mapped_pages.bytes();
326
327 let mut alloc =
328 Mmap::accessible_reserved(mapped_bytes.0, request_bytes, backing_file, memory_type)
329 .map_err(MemoryError::Region)?;
330
331 let base_ptr = alloc.as_mut_ptr();
332 let mem_length = memory
333 .minimum
334 .bytes()
335 .0
336 .max(alloc.as_slice_accessible().len());
337 let mmap = WasmMmap {
338 vm_memory_definition: if let Some(mem_loc) = vm_memory_location {
339 {
340 let mut ptr = mem_loc;
341 let md = ptr.as_mut();
342 md.base = base_ptr;
343 md.current_length = mem_length;
344 }
345 MaybeInstanceOwned::Instance(mem_loc)
346 } else {
347 MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(VMMemoryDefinition {
348 base: base_ptr,
349 current_length: mem_length,
350 })))
351 },
352 alloc,
353 size: Bytes::from(mem_length).try_into().unwrap(),
354 };
355
356 Ok(Self {
357 mmap,
358 config: VMMemoryConfig {
359 maximum: memory.maximum,
360 offset_guard_size: offset_guard_bytes,
361 memory: *memory,
362 style: *style,
363 },
364 })
365 }
366 }
367
368 pub fn to_shared(self) -> VMSharedMemory {
370 VMSharedMemory {
371 mmap: Rc::new(RwLock::new(self.mmap)),
372 config: self.config,
373 conditions: ThreadConditions::new(),
374 }
375 }
376
377 pub fn copy(&mut self) -> Result<Self, MemoryError> {
379 Ok(Self {
380 mmap: self.mmap.copy()?,
381 config: self.config.clone(),
382 })
383 }
384}
385
386impl LinearMemory for VMOwnedMemory {
387 fn ty(&self) -> MemoryType {
389 let minimum = self.mmap.size();
390 self.config.ty(minimum)
391 }
392
393 fn size(&self) -> Pages {
395 self.mmap.size()
396 }
397
398 fn style(&self) -> MemoryStyle {
400 self.config.style()
401 }
402
403 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
408 self.mmap.grow(delta, self.config.clone())
409 }
410
411 fn grow_at_least(&mut self, min_size: u64) -> Result<(), MemoryError> {
414 self.mmap.grow_at_least(min_size, self.config.clone())
415 }
416
417 fn reset(&mut self) -> Result<(), MemoryError> {
419 self.mmap.reset()?;
420 Ok(())
421 }
422
423 fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
425 self.mmap.vm_memory_definition.as_ptr()
426 }
427
428 fn try_clone(&self) -> Result<Box<dyn LinearMemory + 'static>, MemoryError> {
430 Err(MemoryError::MemoryNotShared)
431 }
432
433 fn copy(&mut self) -> Result<Box<dyn LinearMemory + 'static>, MemoryError> {
435 let forked = Self::copy(self)?;
436 Ok(Box::new(forked))
437 }
438}
439
440#[derive(Debug, Clone)]
442pub struct VMSharedMemory {
443 mmap: Rc<RwLock<WasmMmap>>,
445 config: VMMemoryConfig,
447 conditions: ThreadConditions,
449}
450
451unsafe impl Send for VMSharedMemory {}
452unsafe impl Sync for VMSharedMemory {}
453
454impl VMSharedMemory {
455 pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result<Self, MemoryError> {
460 Ok(VMOwnedMemory::new(memory, style)?.to_shared())
461 }
462
463 pub fn new_with_file(
470 memory: &MemoryType,
471 style: &MemoryStyle,
472 backing_file: std::path::PathBuf,
473 memory_type: MmapType,
474 ) -> Result<Self, MemoryError> {
475 Ok(VMOwnedMemory::new_with_file(memory, style, backing_file, memory_type)?.to_shared())
476 }
477
478 pub unsafe fn from_definition(
486 memory: &MemoryType,
487 style: &MemoryStyle,
488 vm_memory_location: NonNull<VMMemoryDefinition>,
489 ) -> Result<Self, MemoryError> {
490 unsafe {
491 Ok(VMOwnedMemory::from_definition(memory, style, vm_memory_location)?.to_shared())
492 }
493 }
494
495 pub unsafe fn from_definition_with_file(
505 memory: &MemoryType,
506 style: &MemoryStyle,
507 vm_memory_location: NonNull<VMMemoryDefinition>,
508 backing_file: Option<std::path::PathBuf>,
509 memory_type: MmapType,
510 ) -> Result<Self, MemoryError> {
511 unsafe {
512 Ok(VMOwnedMemory::from_definition_with_file(
513 memory,
514 style,
515 vm_memory_location,
516 backing_file,
517 memory_type,
518 )?
519 .to_shared())
520 }
521 }
522
523 pub fn copy(&mut self) -> Result<Self, MemoryError> {
525 let mut guard = self.mmap.write().unwrap();
526 Ok(Self {
527 mmap: Rc::new(RwLock::new(guard.copy()?)),
528 config: self.config.clone(),
529 conditions: ThreadConditions::new(),
530 })
531 }
532}
533
534impl LinearMemory for VMSharedMemory {
535 fn ty(&self) -> MemoryType {
537 let minimum = {
538 let guard = self.mmap.read().unwrap();
539 guard.size()
540 };
541 self.config.ty(minimum)
542 }
543
544 fn size(&self) -> Pages {
546 let guard = self.mmap.read().unwrap();
547 guard.size()
548 }
549
550 fn style(&self) -> MemoryStyle {
552 self.config.style()
553 }
554
555 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
560 let mut guard = self.mmap.write().unwrap();
561 guard.grow(delta, self.config.clone())
562 }
563
564 fn grow_at_least(&mut self, min_size: u64) -> Result<(), MemoryError> {
567 let mut guard = self.mmap.write().unwrap();
568 guard.grow_at_least(min_size, self.config.clone())
569 }
570
571 fn reset(&mut self) -> Result<(), MemoryError> {
573 let mut guard = self.mmap.write().unwrap();
574 guard.reset()?;
575 Ok(())
576 }
577
578 fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
580 let guard = self.mmap.read().unwrap();
581 guard.vm_memory_definition.as_ptr()
582 }
583
584 fn try_clone(&self) -> Result<Box<dyn LinearMemory + 'static>, MemoryError> {
586 Ok(Box::new(self.clone()))
587 }
588
589 fn copy(&mut self) -> Result<Box<dyn LinearMemory + 'static>, MemoryError> {
591 let forked = Self::copy(self)?;
592 Ok(Box::new(forked))
593 }
594
595 fn do_wait(
597 &mut self,
598 dst: NotifyLocation,
599 timeout: Option<Duration>,
600 ) -> Result<u32, WaiterError> {
601 self.conditions.do_wait(dst, timeout)
602 }
603
604 fn do_notify(&mut self, dst: NotifyLocation, count: u32) -> u32 {
606 self.conditions.do_notify(dst, count)
607 }
608
609 fn thread_conditions(&self) -> Option<&ThreadConditions> {
610 Some(&self.conditions)
611 }
612}
613
614impl From<VMOwnedMemory> for VMMemory {
615 fn from(mem: VMOwnedMemory) -> Self {
616 Self(Box::new(mem))
617 }
618}
619
620impl From<VMSharedMemory> for VMMemory {
621 fn from(mem: VMSharedMemory) -> Self {
622 Self(Box::new(mem))
623 }
624}
625
626#[derive(Debug)]
628pub struct VMMemory(pub Box<dyn LinearMemory + 'static>);
629
630impl From<Box<dyn LinearMemory + 'static>> for VMMemory {
631 fn from(mem: Box<dyn LinearMemory + 'static>) -> Self {
632 Self(mem)
633 }
634}
635
636impl LinearMemory for VMMemory {
637 fn ty(&self) -> MemoryType {
639 self.0.ty()
640 }
641
642 fn size(&self) -> Pages {
644 self.0.size()
645 }
646
647 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
652 self.0.grow(delta)
653 }
654
655 fn grow_at_least(&mut self, min_size: u64) -> Result<(), MemoryError> {
658 self.0.grow_at_least(min_size)
659 }
660
661 fn reset(&mut self) -> Result<(), MemoryError> {
663 self.0.reset()?;
664 Ok(())
665 }
666
667 fn style(&self) -> MemoryStyle {
669 self.0.style()
670 }
671
672 fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
674 self.0.vmmemory()
675 }
676
677 fn try_clone(&self) -> Result<Box<dyn LinearMemory + 'static>, MemoryError> {
679 self.0.try_clone()
680 }
681
682 unsafe fn initialize_with_data(&self, start: usize, data: &[u8]) -> Result<(), Trap> {
684 unsafe { self.0.initialize_with_data(start, data) }
685 }
686
687 fn copy(&mut self) -> Result<Box<dyn LinearMemory + 'static>, MemoryError> {
689 self.0.copy()
690 }
691
692 fn do_wait(
694 &mut self,
695 dst: NotifyLocation,
696 timeout: Option<Duration>,
697 ) -> Result<u32, WaiterError> {
698 self.0.do_wait(dst, timeout)
699 }
700
701 fn do_notify(&mut self, dst: NotifyLocation, count: u32) -> u32 {
703 self.0.do_notify(dst, count)
704 }
705
706 fn thread_conditions(&self) -> Option<&ThreadConditions> {
707 self.0.thread_conditions()
708 }
709}
710
711impl VMMemory {
712 pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result<Self, MemoryError> {
718 Ok(if memory.shared {
719 Self(Box::new(VMSharedMemory::new(memory, style)?))
720 } else {
721 Self(Box::new(VMOwnedMemory::new(memory, style)?))
722 })
723 }
724
725 pub fn get_runtime_size(&self) -> u32 {
727 self.0.size().0
728 }
729
730 pub unsafe fn from_definition(
738 memory: &MemoryType,
739 style: &MemoryStyle,
740 vm_memory_location: NonNull<VMMemoryDefinition>,
741 ) -> Result<Self, MemoryError> {
742 unsafe {
743 Ok(if memory.shared {
744 Self(Box::new(VMSharedMemory::from_definition(
745 memory,
746 style,
747 vm_memory_location,
748 )?))
749 } else {
750 Self(Box::new(VMOwnedMemory::from_definition(
751 memory,
752 style,
753 vm_memory_location,
754 )?))
755 })
756 }
757 }
758
759 pub fn from_custom<IntoVMMemory>(memory: IntoVMMemory) -> Self
764 where
765 IntoVMMemory: Into<Self>,
766 {
767 memory.into()
768 }
769
770 pub fn copy(&mut self) -> Result<Box<dyn LinearMemory + 'static>, MemoryError> {
772 LinearMemory::copy(self)
773 }
774}
775
776#[doc(hidden)]
777pub unsafe fn initialize_memory_with_data(
779 memory: &VMMemoryDefinition,
780 start: usize,
781 data: &[u8],
782) -> Result<(), Trap> {
783 unsafe {
784 let mem_slice = slice::from_raw_parts_mut(memory.base, memory.current_length);
785 let end = start + data.len();
786 let to_init = &mut mem_slice[start..end];
787 to_init.copy_from_slice(data);
788
789 Ok(())
790 }
791}
792
793pub trait LinearMemory
795where
796 Self: std::fmt::Debug + Send,
797{
798 fn ty(&self) -> MemoryType;
800
801 fn size(&self) -> Pages;
803
804 fn style(&self) -> MemoryStyle;
806
807 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError>;
812
813 fn grow_at_least(&mut self, _min_size: u64) -> Result<(), MemoryError> {
816 Err(MemoryError::UnsupportedOperation {
817 message: "grow_at_least() is not supported".to_string(),
818 })
819 }
820
821 fn reset(&mut self) -> Result<(), MemoryError> {
823 Err(MemoryError::UnsupportedOperation {
824 message: "reset() is not supported".to_string(),
825 })
826 }
827
828 fn vmmemory(&self) -> NonNull<VMMemoryDefinition>;
830
831 fn try_clone(&self) -> Result<Box<dyn LinearMemory + 'static>, MemoryError>;
833
834 #[doc(hidden)]
835 unsafe fn initialize_with_data(&self, start: usize, data: &[u8]) -> Result<(), Trap> {
839 unsafe {
840 let memory = self.vmmemory().as_ref();
841
842 initialize_memory_with_data(memory, start, data)
843 }
844 }
845
846 fn copy(&mut self) -> Result<Box<dyn LinearMemory + 'static>, MemoryError>;
848
849 fn do_wait(
852 &mut self,
853 _dst: NotifyLocation,
854 _timeout: Option<Duration>,
855 ) -> Result<u32, WaiterError> {
856 Err(WaiterError::Unimplemented)
857 }
858
859 fn do_notify(&mut self, _dst: NotifyLocation, _count: u32) -> u32 {
861 0
862 }
863
864 fn thread_conditions(&self) -> Option<&ThreadConditions> {
868 None
869 }
870}