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, true)
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 = usize::try_from(style.offset_guard_size()).map_err(|e| {
330 MemoryError::Generic(format!("cannot install memory guard page: {e}"))
331 })?;
332
333 let minimum_pages = match style {
334 MemoryStyle::Dynamic { .. } => memory.minimum,
335 MemoryStyle::Static => {
336 let bound = MemoryStyle::static_bound();
337 assert_ge!(bound, memory.minimum);
338 bound
339 }
340 };
341 let minimum_bytes = minimum_pages.bytes().0;
342 let request_bytes = minimum_bytes.checked_add(offset_guard_bytes).unwrap();
343 let mapped_pages = memory.minimum;
344 let mapped_bytes = mapped_pages.bytes();
345
346 let mut alloc = Mmap::accessible_reserved(
347 mapped_bytes.0,
348 request_bytes,
349 backing_file,
350 memory_type,
351 true,
352 )
353 .map_err(MemoryError::Region)?;
354
355 let base_ptr = alloc.as_mut_ptr();
356 let mem_length = memory
357 .minimum
358 .bytes()
359 .0
360 .max(alloc.as_slice_accessible().len());
361 let mmap = WasmMmap {
362 vm_memory_definition: if let Some(mem_loc) = vm_memory_location {
363 {
364 let mut ptr = mem_loc;
365 let md = ptr.as_mut();
366 md.base = base_ptr;
367 md.current_length = mem_length;
368 }
369 MaybeInstanceOwned::Instance(mem_loc)
370 } else {
371 MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(VMMemoryDefinition {
372 base: base_ptr,
373 current_length: mem_length,
374 })))
375 },
376 alloc,
377 size: Bytes::from(mem_length).try_into().unwrap(),
378 };
379
380 Ok(Self {
381 mmap,
382 config: VMMemoryConfig {
383 maximum: memory.maximum,
384 offset_guard_size: offset_guard_bytes,
385 memory: *memory,
386 style: *style,
387 },
388 })
389 }
390 }
391
392 pub fn to_shared(self) -> VMSharedMemory {
394 VMSharedMemory {
395 mmap: Arc::new(RwLock::new(self.mmap)),
396 config: self.config,
397 conditions: ThreadConditions::new(),
398 }
399 }
400
401 pub fn copy(&self) -> Result<Self, MemoryError> {
403 Ok(Self {
404 mmap: self.mmap.copy()?,
405 config: self.config.clone(),
406 })
407 }
408}
409
410impl LinearMemory for VMOwnedMemory {
412 fn ty(&self) -> MemoryType {
414 let minimum = self.mmap.size();
415 self.config.ty(minimum)
416 }
417
418 fn size(&self) -> Pages {
420 self.mmap.size()
421 }
422
423 fn style(&self) -> MemoryStyle {
425 self.config.style()
426 }
427
428 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
433 self.mmap.grow(delta, self.config.clone())
434 }
435
436 fn grow_at_least(&mut self, min_size: u64) -> Result<(), MemoryError> {
439 self.mmap.grow_at_least(min_size, self.config.clone())
440 }
441
442 fn reset(&mut self) -> Result<(), MemoryError> {
444 self.mmap.reset()?;
445 Ok(())
446 }
447
448 fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
450 self.mmap.vm_memory_definition.as_ptr()
451 }
452
453 fn try_clone(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
455 Err(MemoryError::MemoryNotShared)
456 }
457
458 fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
460 let forked = Self::copy(self)?;
461 Ok(Box::new(forked))
462 }
463
464 fn as_shared(&self) -> Result<VMSharedMemory, MemoryError> {
466 Err(MemoryError::MemoryNotShared)
467 }
468}
469
470#[derive(Debug, Clone)]
472pub struct VMSharedMemory {
473 mmap: Arc<RwLock<WasmMmap>>,
475 config: VMMemoryConfig,
477 conditions: ThreadConditions,
479}
480
481impl VMSharedMemory {
482 pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result<Self, MemoryError> {
487 Ok(VMOwnedMemory::new(memory, style)?.to_shared())
488 }
489
490 pub fn new_with_file(
497 memory: &MemoryType,
498 style: &MemoryStyle,
499 backing_file: std::path::PathBuf,
500 memory_type: MmapType,
501 ) -> Result<Self, MemoryError> {
502 Ok(VMOwnedMemory::new_with_file(memory, style, backing_file, memory_type)?.to_shared())
503 }
504
505 pub unsafe fn from_definition(
513 memory: &MemoryType,
514 style: &MemoryStyle,
515 vm_memory_location: NonNull<VMMemoryDefinition>,
516 ) -> Result<Self, MemoryError> {
517 unsafe {
518 Ok(VMOwnedMemory::from_definition(memory, style, vm_memory_location)?.to_shared())
519 }
520 }
521
522 pub unsafe fn from_definition_with_file(
532 memory: &MemoryType,
533 style: &MemoryStyle,
534 vm_memory_location: NonNull<VMMemoryDefinition>,
535 backing_file: Option<std::path::PathBuf>,
536 memory_type: MmapType,
537 ) -> Result<Self, MemoryError> {
538 unsafe {
539 Ok(VMOwnedMemory::from_definition_with_file(
540 memory,
541 style,
542 vm_memory_location,
543 backing_file,
544 memory_type,
545 )?
546 .to_shared())
547 }
548 }
549
550 pub fn copy(&self) -> Result<Self, MemoryError> {
552 let guard = self.mmap.read().unwrap();
553 Ok(Self {
554 mmap: Arc::new(RwLock::new(guard.copy()?)),
555 config: self.config.clone(),
556 conditions: ThreadConditions::new(),
557 })
558 }
559}
560
561impl LinearMemory for VMSharedMemory {
562 fn ty(&self) -> MemoryType {
564 let minimum = {
565 let guard = self.mmap.read().unwrap();
566 guard.size()
567 };
568 self.config.ty(minimum)
569 }
570
571 fn size(&self) -> Pages {
573 let guard = self.mmap.read().unwrap();
574 guard.size()
575 }
576
577 fn style(&self) -> MemoryStyle {
579 self.config.style()
580 }
581
582 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
587 let mut guard = self.mmap.write().unwrap();
588 guard.grow(delta, self.config.clone())
589 }
590
591 fn grow_at_least(&mut self, min_size: u64) -> Result<(), MemoryError> {
594 let mut guard = self.mmap.write().unwrap();
595 guard.grow_at_least(min_size, self.config.clone())
596 }
597
598 fn reset(&mut self) -> Result<(), MemoryError> {
600 let mut guard = self.mmap.write().unwrap();
601 guard.reset()?;
602 Ok(())
603 }
604
605 fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
607 let guard = self.mmap.read().unwrap();
608 guard.vm_memory_definition.as_ptr()
609 }
610
611 fn try_clone(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
613 Ok(Box::new(self.clone()))
614 }
615
616 fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
618 let forked = Self::copy(self)?;
619 Ok(Box::new(forked))
620 }
621
622 fn as_shared(&self) -> Result<VMSharedMemory, MemoryError> {
624 Ok(self.clone())
625 }
626
627 unsafe fn do_wait(
629 &mut self,
630 dst: u32,
631 expected: ExpectedValue,
632 timeout: Option<Duration>,
633 ) -> Result<u32, WaiterError> {
634 let dst = NotifyLocation {
635 address: dst,
636 memory_base: self.mmap.read().unwrap().alloc.as_ptr() as *mut _,
637 };
638 unsafe { self.conditions.do_wait(dst, expected, timeout) }
639 }
640
641 fn do_notify(&mut self, dst: u32, count: u32) -> u32 {
643 self.conditions.do_notify(dst, count)
644 }
645
646 fn thread_conditions(&self) -> Option<&ThreadConditions> {
647 Some(&self.conditions)
648 }
649}
650
651impl From<VMOwnedMemory> for VMMemory {
652 fn from(mem: VMOwnedMemory) -> Self {
653 Self(Box::new(mem))
654 }
655}
656
657impl From<VMSharedMemory> for VMMemory {
658 fn from(mem: VMSharedMemory) -> Self {
659 Self(Box::new(mem))
660 }
661}
662
663#[derive(Debug)]
665pub struct VMMemory(pub Box<dyn LinearMemory + Send + Sync + 'static>);
666
667impl From<Box<dyn LinearMemory + Send + Sync + 'static>> for VMMemory {
668 fn from(mem: Box<dyn LinearMemory + Send + Sync + 'static>) -> Self {
669 Self(mem)
670 }
671}
672
673impl LinearMemory for VMMemory {
674 fn ty(&self) -> MemoryType {
676 self.0.ty()
677 }
678
679 fn size(&self) -> Pages {
681 self.0.size()
682 }
683
684 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
689 self.0.grow(delta)
690 }
691
692 fn grow_at_least(&mut self, min_size: u64) -> Result<(), MemoryError> {
695 self.0.grow_at_least(min_size)
696 }
697
698 fn reset(&mut self) -> Result<(), MemoryError> {
700 self.0.reset()?;
701 Ok(())
702 }
703
704 fn style(&self) -> MemoryStyle {
706 self.0.style()
707 }
708
709 fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
711 self.0.vmmemory()
712 }
713
714 fn try_clone(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
716 self.0.try_clone()
717 }
718
719 unsafe fn initialize_with_data(&self, start: usize, data: &[u8]) -> Result<(), Trap> {
721 unsafe { self.0.initialize_with_data(start, data) }
722 }
723
724 fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
726 self.0.copy()
727 }
728
729 fn as_shared(&self) -> Result<VMSharedMemory, MemoryError> {
730 self.0.as_shared()
731 }
732
733 unsafe fn do_wait(
735 &mut self,
736 dst: u32,
737 expected: ExpectedValue,
738 timeout: Option<Duration>,
739 ) -> Result<u32, WaiterError> {
740 unsafe { self.0.do_wait(dst, expected, timeout) }
741 }
742
743 fn do_notify(&mut self, dst: u32, count: u32) -> u32 {
745 self.0.do_notify(dst, count)
746 }
747
748 fn thread_conditions(&self) -> Option<&ThreadConditions> {
749 self.0.thread_conditions()
750 }
751}
752
753impl VMMemory {
754 pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result<Self, MemoryError> {
760 Ok(if memory.shared {
761 Self(Box::new(VMSharedMemory::new(memory, style)?))
762 } else {
763 Self(Box::new(VMOwnedMemory::new(memory, style)?))
764 })
765 }
766
767 pub fn get_runtime_size(&self) -> u32 {
769 self.0.size().0
770 }
771
772 pub unsafe fn from_definition(
780 memory: &MemoryType,
781 style: &MemoryStyle,
782 vm_memory_location: NonNull<VMMemoryDefinition>,
783 ) -> Result<Self, MemoryError> {
784 unsafe {
785 Ok(if memory.shared {
786 Self(Box::new(VMSharedMemory::from_definition(
787 memory,
788 style,
789 vm_memory_location,
790 )?))
791 } else {
792 Self(Box::new(VMOwnedMemory::from_definition(
793 memory,
794 style,
795 vm_memory_location,
796 )?))
797 })
798 }
799 }
800
801 pub fn from_custom<IntoVMMemory>(memory: IntoVMMemory) -> Self
806 where
807 IntoVMMemory: Into<Self>,
808 {
809 memory.into()
810 }
811
812 pub fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
814 LinearMemory::copy(self)
815 }
816
817 pub fn try_clone(&self) -> Result<Self, MemoryError> {
819 LinearMemory::try_clone(self).map(Self)
820 }
821}
822
823#[doc(hidden)]
824pub unsafe fn initialize_memory_with_data(
826 memory: &VMMemoryDefinition,
827 start: usize,
828 data: &[u8],
829) -> Result<(), Trap> {
830 unsafe {
831 let mem_slice = slice::from_raw_parts_mut(memory.base, memory.current_length);
832 let end = start + data.len();
833 let to_init = &mut mem_slice[start..end];
834 to_init.copy_from_slice(data);
835
836 Ok(())
837 }
838}
839
840pub trait LinearMemory
842where
843 Self: std::fmt::Debug + Send,
844{
845 fn ty(&self) -> MemoryType;
847
848 fn size(&self) -> Pages;
850
851 fn style(&self) -> MemoryStyle;
853
854 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError>;
859
860 fn grow_at_least(&mut self, _min_size: u64) -> Result<(), MemoryError> {
863 Err(MemoryError::UnsupportedOperation {
864 message: "grow_at_least() is not supported".to_string(),
865 })
866 }
867
868 fn reset(&mut self) -> Result<(), MemoryError> {
870 Err(MemoryError::UnsupportedOperation {
871 message: "reset() is not supported".to_string(),
872 })
873 }
874
875 fn vmmemory(&self) -> NonNull<VMMemoryDefinition>;
877
878 fn try_clone(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError>;
880
881 #[doc(hidden)]
882 unsafe fn initialize_with_data(&self, start: usize, data: &[u8]) -> Result<(), Trap> {
886 unsafe {
887 let memory = self.vmmemory().as_ref();
888
889 initialize_memory_with_data(memory, start, data)
890 }
891 }
892
893 fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError>;
895
896 fn as_shared(&self) -> Result<VMSharedMemory, MemoryError> {
898 Err(MemoryError::MemoryNotShared)
899 }
900
901 unsafe fn do_wait(
910 &mut self,
911 _dst: u32,
912 _expected: ExpectedValue,
913 _timeout: Option<Duration>,
914 ) -> Result<u32, WaiterError> {
915 Err(WaiterError::Unimplemented)
916 }
917
918 fn do_notify(&mut self, _dst: u32, _count: u32) -> u32 {
920 0
921 }
922
923 fn thread_conditions(&self) -> Option<&ThreadConditions> {
927 None
928 }
929}