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 = 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 =
347 Mmap::accessible_reserved(mapped_bytes.0, request_bytes, backing_file, memory_type)
348 .map_err(MemoryError::Region)?;
349
350 let base_ptr = alloc.as_mut_ptr();
351 let mem_length = memory
352 .minimum
353 .bytes()
354 .0
355 .max(alloc.as_slice_accessible().len());
356 let mmap = WasmMmap {
357 vm_memory_definition: if let Some(mem_loc) = vm_memory_location {
358 {
359 let mut ptr = mem_loc;
360 let md = ptr.as_mut();
361 md.base = base_ptr;
362 md.current_length = mem_length;
363 }
364 MaybeInstanceOwned::Instance(mem_loc)
365 } else {
366 MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(VMMemoryDefinition {
367 base: base_ptr,
368 current_length: mem_length,
369 })))
370 },
371 alloc,
372 size: Bytes::from(mem_length).try_into().unwrap(),
373 };
374
375 Ok(Self {
376 mmap,
377 config: VMMemoryConfig {
378 maximum: memory.maximum,
379 offset_guard_size: offset_guard_bytes,
380 memory: *memory,
381 style: *style,
382 },
383 })
384 }
385 }
386
387 pub fn to_shared(self) -> VMSharedMemory {
389 VMSharedMemory {
390 mmap: Arc::new(RwLock::new(self.mmap)),
391 config: self.config,
392 conditions: ThreadConditions::new(),
393 }
394 }
395
396 pub fn copy(&self) -> Result<Self, MemoryError> {
398 Ok(Self {
399 mmap: self.mmap.copy()?,
400 config: self.config.clone(),
401 })
402 }
403}
404
405impl LinearMemory for VMOwnedMemory {
407 fn ty(&self) -> MemoryType {
409 let minimum = self.mmap.size();
410 self.config.ty(minimum)
411 }
412
413 fn size(&self) -> Pages {
415 self.mmap.size()
416 }
417
418 fn style(&self) -> MemoryStyle {
420 self.config.style()
421 }
422
423 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
428 self.mmap.grow(delta, self.config.clone())
429 }
430
431 fn grow_at_least(&mut self, min_size: u64) -> Result<(), MemoryError> {
434 self.mmap.grow_at_least(min_size, self.config.clone())
435 }
436
437 fn reset(&mut self) -> Result<(), MemoryError> {
439 self.mmap.reset()?;
440 Ok(())
441 }
442
443 fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
445 self.mmap.vm_memory_definition.as_ptr()
446 }
447
448 fn try_clone(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
450 Err(MemoryError::MemoryNotShared)
451 }
452
453 fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
455 let forked = Self::copy(self)?;
456 Ok(Box::new(forked))
457 }
458
459 fn as_shared(&self) -> Result<VMSharedMemory, MemoryError> {
461 Err(MemoryError::MemoryNotShared)
462 }
463}
464
465#[derive(Debug, Clone)]
467pub struct VMSharedMemory {
468 mmap: Arc<RwLock<WasmMmap>>,
470 config: VMMemoryConfig,
472 conditions: ThreadConditions,
474}
475
476impl VMSharedMemory {
477 pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result<Self, MemoryError> {
482 Ok(VMOwnedMemory::new(memory, style)?.to_shared())
483 }
484
485 pub fn new_with_file(
492 memory: &MemoryType,
493 style: &MemoryStyle,
494 backing_file: std::path::PathBuf,
495 memory_type: MmapType,
496 ) -> Result<Self, MemoryError> {
497 Ok(VMOwnedMemory::new_with_file(memory, style, backing_file, memory_type)?.to_shared())
498 }
499
500 pub unsafe fn from_definition(
508 memory: &MemoryType,
509 style: &MemoryStyle,
510 vm_memory_location: NonNull<VMMemoryDefinition>,
511 ) -> Result<Self, MemoryError> {
512 unsafe {
513 Ok(VMOwnedMemory::from_definition(memory, style, vm_memory_location)?.to_shared())
514 }
515 }
516
517 pub unsafe fn from_definition_with_file(
527 memory: &MemoryType,
528 style: &MemoryStyle,
529 vm_memory_location: NonNull<VMMemoryDefinition>,
530 backing_file: Option<std::path::PathBuf>,
531 memory_type: MmapType,
532 ) -> Result<Self, MemoryError> {
533 unsafe {
534 Ok(VMOwnedMemory::from_definition_with_file(
535 memory,
536 style,
537 vm_memory_location,
538 backing_file,
539 memory_type,
540 )?
541 .to_shared())
542 }
543 }
544
545 pub fn copy(&self) -> Result<Self, MemoryError> {
547 let guard = self.mmap.read().unwrap();
548 Ok(Self {
549 mmap: Arc::new(RwLock::new(guard.copy()?)),
550 config: self.config.clone(),
551 conditions: ThreadConditions::new(),
552 })
553 }
554}
555
556impl LinearMemory for VMSharedMemory {
557 fn ty(&self) -> MemoryType {
559 let minimum = {
560 let guard = self.mmap.read().unwrap();
561 guard.size()
562 };
563 self.config.ty(minimum)
564 }
565
566 fn size(&self) -> Pages {
568 let guard = self.mmap.read().unwrap();
569 guard.size()
570 }
571
572 fn style(&self) -> MemoryStyle {
574 self.config.style()
575 }
576
577 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
582 let mut guard = self.mmap.write().unwrap();
583 guard.grow(delta, self.config.clone())
584 }
585
586 fn grow_at_least(&mut self, min_size: u64) -> Result<(), MemoryError> {
589 let mut guard = self.mmap.write().unwrap();
590 guard.grow_at_least(min_size, self.config.clone())
591 }
592
593 fn reset(&mut self) -> Result<(), MemoryError> {
595 let mut guard = self.mmap.write().unwrap();
596 guard.reset()?;
597 Ok(())
598 }
599
600 fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
602 let guard = self.mmap.read().unwrap();
603 guard.vm_memory_definition.as_ptr()
604 }
605
606 fn try_clone(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
608 Ok(Box::new(self.clone()))
609 }
610
611 fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
613 let forked = Self::copy(self)?;
614 Ok(Box::new(forked))
615 }
616
617 fn as_shared(&self) -> Result<VMSharedMemory, MemoryError> {
619 Ok(self.clone())
620 }
621
622 unsafe fn do_wait(
624 &mut self,
625 dst: u32,
626 expected: ExpectedValue,
627 timeout: Option<Duration>,
628 ) -> Result<u32, WaiterError> {
629 let dst = NotifyLocation {
630 address: dst,
631 memory_base: self.mmap.read().unwrap().alloc.as_ptr() as *mut _,
632 };
633 unsafe { self.conditions.do_wait(dst, expected, timeout) }
634 }
635
636 fn do_notify(&mut self, dst: u32, count: u32) -> u32 {
638 self.conditions.do_notify(dst, count)
639 }
640
641 fn thread_conditions(&self) -> Option<&ThreadConditions> {
642 Some(&self.conditions)
643 }
644}
645
646impl From<VMOwnedMemory> for VMMemory {
647 fn from(mem: VMOwnedMemory) -> Self {
648 Self(Box::new(mem))
649 }
650}
651
652impl From<VMSharedMemory> for VMMemory {
653 fn from(mem: VMSharedMemory) -> Self {
654 Self(Box::new(mem))
655 }
656}
657
658#[derive(Debug)]
660pub struct VMMemory(pub Box<dyn LinearMemory + Send + Sync + 'static>);
661
662impl From<Box<dyn LinearMemory + Send + Sync + 'static>> for VMMemory {
663 fn from(mem: Box<dyn LinearMemory + Send + Sync + 'static>) -> Self {
664 Self(mem)
665 }
666}
667
668impl LinearMemory for VMMemory {
669 fn ty(&self) -> MemoryType {
671 self.0.ty()
672 }
673
674 fn size(&self) -> Pages {
676 self.0.size()
677 }
678
679 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
684 self.0.grow(delta)
685 }
686
687 fn grow_at_least(&mut self, min_size: u64) -> Result<(), MemoryError> {
690 self.0.grow_at_least(min_size)
691 }
692
693 fn reset(&mut self) -> Result<(), MemoryError> {
695 self.0.reset()?;
696 Ok(())
697 }
698
699 fn style(&self) -> MemoryStyle {
701 self.0.style()
702 }
703
704 fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
706 self.0.vmmemory()
707 }
708
709 fn try_clone(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
711 self.0.try_clone()
712 }
713
714 unsafe fn initialize_with_data(&self, start: usize, data: &[u8]) -> Result<(), Trap> {
716 unsafe { self.0.initialize_with_data(start, data) }
717 }
718
719 fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
721 self.0.copy()
722 }
723
724 fn as_shared(&self) -> Result<VMSharedMemory, MemoryError> {
725 self.0.as_shared()
726 }
727
728 unsafe fn do_wait(
730 &mut self,
731 dst: u32,
732 expected: ExpectedValue,
733 timeout: Option<Duration>,
734 ) -> Result<u32, WaiterError> {
735 unsafe { self.0.do_wait(dst, expected, timeout) }
736 }
737
738 fn do_notify(&mut self, dst: u32, count: u32) -> u32 {
740 self.0.do_notify(dst, count)
741 }
742
743 fn thread_conditions(&self) -> Option<&ThreadConditions> {
744 self.0.thread_conditions()
745 }
746}
747
748impl VMMemory {
749 pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result<Self, MemoryError> {
755 Ok(if memory.shared {
756 Self(Box::new(VMSharedMemory::new(memory, style)?))
757 } else {
758 Self(Box::new(VMOwnedMemory::new(memory, style)?))
759 })
760 }
761
762 pub fn get_runtime_size(&self) -> u32 {
764 self.0.size().0
765 }
766
767 pub unsafe fn from_definition(
775 memory: &MemoryType,
776 style: &MemoryStyle,
777 vm_memory_location: NonNull<VMMemoryDefinition>,
778 ) -> Result<Self, MemoryError> {
779 unsafe {
780 Ok(if memory.shared {
781 Self(Box::new(VMSharedMemory::from_definition(
782 memory,
783 style,
784 vm_memory_location,
785 )?))
786 } else {
787 Self(Box::new(VMOwnedMemory::from_definition(
788 memory,
789 style,
790 vm_memory_location,
791 )?))
792 })
793 }
794 }
795
796 pub fn from_custom<IntoVMMemory>(memory: IntoVMMemory) -> Self
801 where
802 IntoVMMemory: Into<Self>,
803 {
804 memory.into()
805 }
806
807 pub fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
809 LinearMemory::copy(self)
810 }
811
812 pub fn try_clone(&self) -> Result<Self, MemoryError> {
814 LinearMemory::try_clone(self).map(Self)
815 }
816}
817
818#[doc(hidden)]
819pub unsafe fn initialize_memory_with_data(
821 memory: &VMMemoryDefinition,
822 start: usize,
823 data: &[u8],
824) -> Result<(), Trap> {
825 unsafe {
826 let mem_slice = slice::from_raw_parts_mut(memory.base, memory.current_length);
827 let end = start + data.len();
828 let to_init = &mut mem_slice[start..end];
829 to_init.copy_from_slice(data);
830
831 Ok(())
832 }
833}
834
835pub trait LinearMemory
837where
838 Self: std::fmt::Debug + Send,
839{
840 fn ty(&self) -> MemoryType;
842
843 fn size(&self) -> Pages;
845
846 fn style(&self) -> MemoryStyle;
848
849 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError>;
854
855 fn grow_at_least(&mut self, _min_size: u64) -> Result<(), MemoryError> {
858 Err(MemoryError::UnsupportedOperation {
859 message: "grow_at_least() is not supported".to_string(),
860 })
861 }
862
863 fn reset(&mut self) -> Result<(), MemoryError> {
865 Err(MemoryError::UnsupportedOperation {
866 message: "reset() is not supported".to_string(),
867 })
868 }
869
870 fn vmmemory(&self) -> NonNull<VMMemoryDefinition>;
872
873 fn try_clone(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError>;
875
876 #[doc(hidden)]
877 unsafe fn initialize_with_data(&self, start: usize, data: &[u8]) -> Result<(), Trap> {
881 unsafe {
882 let memory = self.vmmemory().as_ref();
883
884 initialize_memory_with_data(memory, start, data)
885 }
886 }
887
888 fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError>;
890
891 fn as_shared(&self) -> Result<VMSharedMemory, MemoryError> {
893 Err(MemoryError::MemoryNotShared)
894 }
895
896 unsafe fn do_wait(
905 &mut self,
906 _dst: u32,
907 _expected: ExpectedValue,
908 _timeout: Option<Duration>,
909 ) -> Result<u32, WaiterError> {
910 Err(WaiterError::Unimplemented)
911 }
912
913 fn do_notify(&mut self, _dst: u32, _count: u32) -> u32 {
915 0
916 }
917
918 fn thread_conditions(&self) -> Option<&ThreadConditions> {
922 None
923 }
924}