1use crate::threadconditions::ThreadConditions;
9pub use crate::threadconditions::{NotifyLocation, WaiterError};
10use crate::trap::Trap;
11use crate::{
12 mmap::{Mmap, MmapType},
13 store::MaybeInstanceOwned,
14 threadconditions::ExpectedValue,
15 vmcontext::VMMemoryDefinition,
16};
17use more_asserts::assert_ge;
18use std::cell::UnsafeCell;
19use std::convert::TryInto;
20use std::ptr::NonNull;
21use std::slice;
22use std::sync::{Arc, RwLock};
23use std::time::Duration;
24use wasmer_types::{Bytes, MemoryError, MemoryStyle, MemoryType, Pages, WASM_PAGE_SIZE};
25
26#[derive(Debug)]
28struct WasmMmap {
29 alloc: Mmap,
31 size: Pages,
33 vm_memory_definition: MaybeInstanceOwned<VMMemoryDefinition>,
35}
36
37unsafe impl Send for WasmMmap {}
41unsafe impl Sync for WasmMmap {}
43
44impl WasmMmap {
45 fn get_vm_memory_definition(&self) -> NonNull<VMMemoryDefinition> {
46 self.vm_memory_definition.as_ptr()
47 }
48
49 fn size(&self) -> Pages {
50 unsafe {
51 let md_ptr = self.get_vm_memory_definition();
52 let md = md_ptr.as_ref();
53 Bytes::from(md.current_length).try_into().unwrap()
54 }
55 }
56
57 fn grow(&mut self, delta: Pages, conf: VMMemoryConfig) -> Result<Pages, MemoryError> {
58 if delta.0 == 0 {
60 return Ok(self.size);
61 }
62
63 let new_pages = self
64 .size
65 .checked_add(delta)
66 .ok_or(MemoryError::CouldNotGrow {
67 current: self.size,
68 attempted_delta: delta,
69 })?;
70 let prev_pages = self.size;
71
72 if let Some(maximum) = conf.maximum
73 && new_pages > maximum
74 {
75 return Err(MemoryError::CouldNotGrow {
76 current: self.size,
77 attempted_delta: delta,
78 });
79 }
80
81 if new_pages > Pages::max_value() {
85 return Err(MemoryError::CouldNotGrow {
87 current: self.size,
88 attempted_delta: delta,
89 });
90 }
91
92 let delta_bytes = delta.bytes().0;
93 let prev_bytes = prev_pages.bytes().0;
94 let new_bytes = new_pages.bytes().0;
95
96 if new_bytes > self.alloc.len() - conf.offset_guard_size {
97 let guard_bytes = conf.offset_guard_size;
100 let request_bytes =
101 new_bytes
102 .checked_add(guard_bytes)
103 .ok_or_else(|| MemoryError::CouldNotGrow {
104 current: new_pages,
105 attempted_delta: Bytes(guard_bytes).try_into().unwrap(),
106 })?;
107
108 let mut new_mmap =
109 Mmap::accessible_reserved(new_bytes, request_bytes, None, MmapType::Private)
110 .map_err(MemoryError::Region)?;
111
112 let copy_len = self.alloc.len() - conf.offset_guard_size;
113 new_mmap.as_mut_slice()[..copy_len].copy_from_slice(&self.alloc.as_slice()[..copy_len]);
114
115 self.alloc = new_mmap;
116 } else if delta_bytes > 0 {
117 self.alloc
119 .make_accessible(prev_bytes, delta_bytes)
120 .map_err(MemoryError::Region)?;
121 }
122
123 self.size = new_pages;
124
125 unsafe {
127 let mut md_ptr = self.vm_memory_definition.as_ptr();
128 let md = md_ptr.as_mut();
129 md.current_length = new_pages.bytes().0;
130 md.base = self.alloc.as_mut_ptr() as _;
131 }
132
133 Ok(prev_pages)
134 }
135
136 fn grow_at_least(&mut self, min_size: u64, conf: VMMemoryConfig) -> Result<(), MemoryError> {
139 let cur_size = self.size.bytes().0 as u64;
140 if cur_size < min_size {
141 let growth = min_size - cur_size;
142 let growth_pages = ((growth - 1) / WASM_PAGE_SIZE as u64) + 1;
143 self.grow(Pages(growth_pages as u32), conf)?;
144 }
145
146 Ok(())
147 }
148
149 fn reset(&mut self) -> Result<(), MemoryError> {
151 self.size.0 = 0;
152 unsafe {
154 let mut md_ptr = self.vm_memory_definition.as_ptr();
155 let md = md_ptr.as_mut();
156 md.current_length = 0;
157 }
158 Ok(())
159 }
160
161 pub fn copy(&self) -> Result<Self, MemoryError> {
164 let mem_length = self.size.bytes().0;
165 let mut alloc = self
166 .alloc
167 .copy(Some(mem_length))
168 .map_err(MemoryError::Generic)?;
169 let base_ptr = alloc.as_mut_ptr();
170 Ok(Self {
171 vm_memory_definition: MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(
172 VMMemoryDefinition {
173 base: base_ptr,
174 current_length: mem_length,
175 },
176 ))),
177 alloc,
178 size: self.size,
179 })
180 }
181}
182
183#[derive(Debug, Clone)]
185struct VMMemoryConfig {
186 maximum: Option<Pages>,
188 memory: MemoryType,
190 style: MemoryStyle,
192 offset_guard_size: usize,
195}
196
197impl VMMemoryConfig {
198 fn ty(&self, minimum: Pages) -> MemoryType {
199 let mut out = self.memory;
200 out.minimum = minimum;
201
202 out
203 }
204
205 fn style(&self) -> MemoryStyle {
206 self.style
207 }
208}
209
210#[derive(Debug)]
212pub struct VMOwnedMemory {
213 mmap: WasmMmap,
215 config: VMMemoryConfig,
217}
218
219unsafe impl Send for VMOwnedMemory {}
220unsafe impl Sync for VMOwnedMemory {}
221
222impl VMOwnedMemory {
223 pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result<Self, MemoryError> {
228 unsafe { Self::new_internal(memory, style, None, None, MmapType::Private) }
229 }
230
231 pub fn new_with_file(
238 memory: &MemoryType,
239 style: &MemoryStyle,
240 backing_file: std::path::PathBuf,
241 memory_type: MmapType,
242 ) -> Result<Self, MemoryError> {
243 unsafe { Self::new_internal(memory, style, None, Some(backing_file), memory_type) }
244 }
245
246 pub unsafe fn from_definition(
254 memory: &MemoryType,
255 style: &MemoryStyle,
256 vm_memory_location: NonNull<VMMemoryDefinition>,
257 ) -> Result<Self, MemoryError> {
258 unsafe {
259 Self::new_internal(
260 memory,
261 style,
262 Some(vm_memory_location),
263 None,
264 MmapType::Private,
265 )
266 }
267 }
268
269 pub unsafe fn from_definition_with_file(
279 memory: &MemoryType,
280 style: &MemoryStyle,
281 vm_memory_location: NonNull<VMMemoryDefinition>,
282 backing_file: Option<std::path::PathBuf>,
283 memory_type: MmapType,
284 ) -> Result<Self, MemoryError> {
285 unsafe {
286 Self::new_internal(
287 memory,
288 style,
289 Some(vm_memory_location),
290 backing_file,
291 memory_type,
292 )
293 }
294 }
295
296 unsafe fn new_internal(
298 memory: &MemoryType,
299 style: &MemoryStyle,
300 vm_memory_location: Option<NonNull<VMMemoryDefinition>>,
301 backing_file: Option<std::path::PathBuf>,
302 memory_type: MmapType,
303 ) -> Result<Self, MemoryError> {
304 unsafe {
305 if memory.minimum > Pages::max_value() {
306 return Err(MemoryError::MinimumMemoryTooLarge {
307 min_requested: memory.minimum,
308 max_allowed: Pages::max_value(),
309 });
310 }
311 if let Some(max) = memory.maximum {
313 if max > Pages::max_value() {
314 return Err(MemoryError::MaximumMemoryTooLarge {
315 max_requested: max,
316 max_allowed: Pages::max_value(),
317 });
318 }
319 if max < memory.minimum {
320 return Err(MemoryError::InvalidMemory {
321 reason: format!(
322 "the maximum ({} pages) is less than the minimum ({} pages)",
323 max.0, memory.minimum.0
324 ),
325 });
326 }
327 }
328
329 let offset_guard_bytes = style.offset_guard_size() as usize;
330
331 let minimum_pages = match style {
332 MemoryStyle::Dynamic { .. } => memory.minimum,
333 MemoryStyle::Static { bound, .. } => {
334 assert_ge!(*bound, memory.minimum);
335 *bound
336 }
337 };
338 let minimum_bytes = minimum_pages.bytes().0;
339 let request_bytes = minimum_bytes.checked_add(offset_guard_bytes).unwrap();
340 let mapped_pages = memory.minimum;
341 let mapped_bytes = mapped_pages.bytes();
342
343 let mut alloc =
344 Mmap::accessible_reserved(mapped_bytes.0, request_bytes, backing_file, memory_type)
345 .map_err(MemoryError::Region)?;
346
347 let base_ptr = alloc.as_mut_ptr();
348 let mem_length = memory
349 .minimum
350 .bytes()
351 .0
352 .max(alloc.as_slice_accessible().len());
353 let mmap = WasmMmap {
354 vm_memory_definition: if let Some(mem_loc) = vm_memory_location {
355 {
356 let mut ptr = mem_loc;
357 let md = ptr.as_mut();
358 md.base = base_ptr;
359 md.current_length = mem_length;
360 }
361 MaybeInstanceOwned::Instance(mem_loc)
362 } else {
363 MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(VMMemoryDefinition {
364 base: base_ptr,
365 current_length: mem_length,
366 })))
367 },
368 alloc,
369 size: Bytes::from(mem_length).try_into().unwrap(),
370 };
371
372 Ok(Self {
373 mmap,
374 config: VMMemoryConfig {
375 maximum: memory.maximum,
376 offset_guard_size: offset_guard_bytes,
377 memory: *memory,
378 style: *style,
379 },
380 })
381 }
382 }
383
384 pub fn to_shared(self) -> VMSharedMemory {
386 VMSharedMemory {
387 mmap: Arc::new(RwLock::new(self.mmap)),
388 config: self.config,
389 conditions: ThreadConditions::new(),
390 }
391 }
392
393 pub fn copy(&self) -> Result<Self, MemoryError> {
395 Ok(Self {
396 mmap: self.mmap.copy()?,
397 config: self.config.clone(),
398 })
399 }
400}
401
402impl LinearMemory for VMOwnedMemory {
404 fn ty(&self) -> MemoryType {
406 let minimum = self.mmap.size();
407 self.config.ty(minimum)
408 }
409
410 fn size(&self) -> Pages {
412 self.mmap.size()
413 }
414
415 fn style(&self) -> MemoryStyle {
417 self.config.style()
418 }
419
420 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
425 self.mmap.grow(delta, self.config.clone())
426 }
427
428 fn grow_at_least(&mut self, min_size: u64) -> Result<(), MemoryError> {
431 self.mmap.grow_at_least(min_size, self.config.clone())
432 }
433
434 fn reset(&mut self) -> Result<(), MemoryError> {
436 self.mmap.reset()?;
437 Ok(())
438 }
439
440 fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
442 self.mmap.vm_memory_definition.as_ptr()
443 }
444
445 fn try_clone(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
447 Err(MemoryError::MemoryNotShared)
448 }
449
450 fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
452 let forked = Self::copy(self)?;
453 Ok(Box::new(forked))
454 }
455
456 fn as_shared(&self) -> Result<VMSharedMemory, MemoryError> {
458 Err(MemoryError::MemoryNotShared)
459 }
460}
461
462#[derive(Debug, Clone)]
464pub struct VMSharedMemory {
465 mmap: Arc<RwLock<WasmMmap>>,
467 config: VMMemoryConfig,
469 conditions: ThreadConditions,
471}
472
473impl VMSharedMemory {
474 pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result<Self, MemoryError> {
479 Ok(VMOwnedMemory::new(memory, style)?.to_shared())
480 }
481
482 pub fn new_with_file(
489 memory: &MemoryType,
490 style: &MemoryStyle,
491 backing_file: std::path::PathBuf,
492 memory_type: MmapType,
493 ) -> Result<Self, MemoryError> {
494 Ok(VMOwnedMemory::new_with_file(memory, style, backing_file, memory_type)?.to_shared())
495 }
496
497 pub unsafe fn from_definition(
505 memory: &MemoryType,
506 style: &MemoryStyle,
507 vm_memory_location: NonNull<VMMemoryDefinition>,
508 ) -> Result<Self, MemoryError> {
509 unsafe {
510 Ok(VMOwnedMemory::from_definition(memory, style, vm_memory_location)?.to_shared())
511 }
512 }
513
514 pub unsafe fn from_definition_with_file(
524 memory: &MemoryType,
525 style: &MemoryStyle,
526 vm_memory_location: NonNull<VMMemoryDefinition>,
527 backing_file: Option<std::path::PathBuf>,
528 memory_type: MmapType,
529 ) -> Result<Self, MemoryError> {
530 unsafe {
531 Ok(VMOwnedMemory::from_definition_with_file(
532 memory,
533 style,
534 vm_memory_location,
535 backing_file,
536 memory_type,
537 )?
538 .to_shared())
539 }
540 }
541
542 pub fn copy(&self) -> Result<Self, MemoryError> {
544 let guard = self.mmap.read().unwrap();
545 Ok(Self {
546 mmap: Arc::new(RwLock::new(guard.copy()?)),
547 config: self.config.clone(),
548 conditions: ThreadConditions::new(),
549 })
550 }
551}
552
553impl LinearMemory for VMSharedMemory {
554 fn ty(&self) -> MemoryType {
556 let minimum = {
557 let guard = self.mmap.read().unwrap();
558 guard.size()
559 };
560 self.config.ty(minimum)
561 }
562
563 fn size(&self) -> Pages {
565 let guard = self.mmap.read().unwrap();
566 guard.size()
567 }
568
569 fn style(&self) -> MemoryStyle {
571 self.config.style()
572 }
573
574 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
579 let mut guard = self.mmap.write().unwrap();
580 guard.grow(delta, self.config.clone())
581 }
582
583 fn grow_at_least(&mut self, min_size: u64) -> Result<(), MemoryError> {
586 let mut guard = self.mmap.write().unwrap();
587 guard.grow_at_least(min_size, self.config.clone())
588 }
589
590 fn reset(&mut self) -> Result<(), MemoryError> {
592 let mut guard = self.mmap.write().unwrap();
593 guard.reset()?;
594 Ok(())
595 }
596
597 fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
599 let guard = self.mmap.read().unwrap();
600 guard.vm_memory_definition.as_ptr()
601 }
602
603 fn try_clone(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
605 Ok(Box::new(self.clone()))
606 }
607
608 fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
610 let forked = Self::copy(self)?;
611 Ok(Box::new(forked))
612 }
613
614 fn as_shared(&self) -> Result<VMSharedMemory, MemoryError> {
616 Ok(self.clone())
617 }
618
619 unsafe fn do_wait(
621 &mut self,
622 dst: u32,
623 expected: ExpectedValue,
624 timeout: Option<Duration>,
625 ) -> Result<u32, WaiterError> {
626 let dst = NotifyLocation {
627 address: dst,
628 memory_base: self.mmap.read().unwrap().alloc.as_ptr() as *mut _,
629 };
630 unsafe { self.conditions.do_wait(dst, expected, timeout) }
631 }
632
633 fn do_notify(&mut self, dst: u32, count: u32) -> u32 {
635 self.conditions.do_notify(dst, count)
636 }
637
638 fn thread_conditions(&self) -> Option<&ThreadConditions> {
639 Some(&self.conditions)
640 }
641}
642
643impl From<VMOwnedMemory> for VMMemory {
644 fn from(mem: VMOwnedMemory) -> Self {
645 Self(Box::new(mem))
646 }
647}
648
649impl From<VMSharedMemory> for VMMemory {
650 fn from(mem: VMSharedMemory) -> Self {
651 Self(Box::new(mem))
652 }
653}
654
655#[derive(Debug)]
657pub struct VMMemory(pub Box<dyn LinearMemory + Send + Sync + 'static>);
658
659impl From<Box<dyn LinearMemory + Send + Sync + 'static>> for VMMemory {
660 fn from(mem: Box<dyn LinearMemory + Send + Sync + 'static>) -> Self {
661 Self(mem)
662 }
663}
664
665impl LinearMemory for VMMemory {
666 fn ty(&self) -> MemoryType {
668 self.0.ty()
669 }
670
671 fn size(&self) -> Pages {
673 self.0.size()
674 }
675
676 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
681 self.0.grow(delta)
682 }
683
684 fn grow_at_least(&mut self, min_size: u64) -> Result<(), MemoryError> {
687 self.0.grow_at_least(min_size)
688 }
689
690 fn reset(&mut self) -> Result<(), MemoryError> {
692 self.0.reset()?;
693 Ok(())
694 }
695
696 fn style(&self) -> MemoryStyle {
698 self.0.style()
699 }
700
701 fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
703 self.0.vmmemory()
704 }
705
706 fn try_clone(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
708 self.0.try_clone()
709 }
710
711 unsafe fn initialize_with_data(&self, start: usize, data: &[u8]) -> Result<(), Trap> {
713 unsafe { self.0.initialize_with_data(start, data) }
714 }
715
716 fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
718 self.0.copy()
719 }
720
721 fn as_shared(&self) -> Result<VMSharedMemory, MemoryError> {
722 self.0.as_shared()
723 }
724
725 unsafe fn do_wait(
727 &mut self,
728 dst: u32,
729 expected: ExpectedValue,
730 timeout: Option<Duration>,
731 ) -> Result<u32, WaiterError> {
732 unsafe { self.0.do_wait(dst, expected, timeout) }
733 }
734
735 fn do_notify(&mut self, dst: u32, count: u32) -> u32 {
737 self.0.do_notify(dst, count)
738 }
739
740 fn thread_conditions(&self) -> Option<&ThreadConditions> {
741 self.0.thread_conditions()
742 }
743}
744
745impl VMMemory {
746 pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result<Self, MemoryError> {
752 Ok(if memory.shared {
753 Self(Box::new(VMSharedMemory::new(memory, style)?))
754 } else {
755 Self(Box::new(VMOwnedMemory::new(memory, style)?))
756 })
757 }
758
759 pub fn get_runtime_size(&self) -> u32 {
761 self.0.size().0
762 }
763
764 pub unsafe fn from_definition(
772 memory: &MemoryType,
773 style: &MemoryStyle,
774 vm_memory_location: NonNull<VMMemoryDefinition>,
775 ) -> Result<Self, MemoryError> {
776 unsafe {
777 Ok(if memory.shared {
778 Self(Box::new(VMSharedMemory::from_definition(
779 memory,
780 style,
781 vm_memory_location,
782 )?))
783 } else {
784 Self(Box::new(VMOwnedMemory::from_definition(
785 memory,
786 style,
787 vm_memory_location,
788 )?))
789 })
790 }
791 }
792
793 pub fn from_custom<IntoVMMemory>(memory: IntoVMMemory) -> Self
798 where
799 IntoVMMemory: Into<Self>,
800 {
801 memory.into()
802 }
803
804 pub fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
806 LinearMemory::copy(self)
807 }
808
809 pub fn try_clone(&self) -> Result<Self, MemoryError> {
811 LinearMemory::try_clone(self).map(Self)
812 }
813}
814
815#[doc(hidden)]
816pub unsafe fn initialize_memory_with_data(
818 memory: &VMMemoryDefinition,
819 start: usize,
820 data: &[u8],
821) -> Result<(), Trap> {
822 unsafe {
823 let mem_slice = slice::from_raw_parts_mut(memory.base, memory.current_length);
824 let end = start + data.len();
825 let to_init = &mut mem_slice[start..end];
826 to_init.copy_from_slice(data);
827
828 Ok(())
829 }
830}
831
832pub trait LinearMemory
834where
835 Self: std::fmt::Debug + Send,
836{
837 fn ty(&self) -> MemoryType;
839
840 fn size(&self) -> Pages;
842
843 fn style(&self) -> MemoryStyle;
845
846 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError>;
851
852 fn grow_at_least(&mut self, _min_size: u64) -> Result<(), MemoryError> {
855 Err(MemoryError::UnsupportedOperation {
856 message: "grow_at_least() is not supported".to_string(),
857 })
858 }
859
860 fn reset(&mut self) -> Result<(), MemoryError> {
862 Err(MemoryError::UnsupportedOperation {
863 message: "reset() is not supported".to_string(),
864 })
865 }
866
867 fn vmmemory(&self) -> NonNull<VMMemoryDefinition>;
869
870 fn try_clone(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError>;
872
873 #[doc(hidden)]
874 unsafe fn initialize_with_data(&self, start: usize, data: &[u8]) -> Result<(), Trap> {
878 unsafe {
879 let memory = self.vmmemory().as_ref();
880
881 initialize_memory_with_data(memory, start, data)
882 }
883 }
884
885 fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError>;
887
888 fn as_shared(&self) -> Result<VMSharedMemory, MemoryError> {
890 Err(MemoryError::MemoryNotShared)
891 }
892
893 unsafe fn do_wait(
902 &mut self,
903 _dst: u32,
904 _expected: ExpectedValue,
905 _timeout: Option<Duration>,
906 ) -> Result<u32, WaiterError> {
907 Err(WaiterError::Unimplemented)
908 }
909
910 fn do_notify(&mut self, _dst: u32, _count: u32) -> u32 {
912 0
913 }
914
915 fn thread_conditions(&self) -> Option<&ThreadConditions> {
919 None
920 }
921}