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
457#[derive(Debug, Clone)]
459pub struct VMSharedMemory {
460 mmap: Arc<RwLock<WasmMmap>>,
462 config: VMMemoryConfig,
464 conditions: ThreadConditions,
466}
467
468impl VMSharedMemory {
469 pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result<Self, MemoryError> {
474 Ok(VMOwnedMemory::new(memory, style)?.to_shared())
475 }
476
477 pub fn new_with_file(
484 memory: &MemoryType,
485 style: &MemoryStyle,
486 backing_file: std::path::PathBuf,
487 memory_type: MmapType,
488 ) -> Result<Self, MemoryError> {
489 Ok(VMOwnedMemory::new_with_file(memory, style, backing_file, memory_type)?.to_shared())
490 }
491
492 pub unsafe fn from_definition(
500 memory: &MemoryType,
501 style: &MemoryStyle,
502 vm_memory_location: NonNull<VMMemoryDefinition>,
503 ) -> Result<Self, MemoryError> {
504 unsafe {
505 Ok(VMOwnedMemory::from_definition(memory, style, vm_memory_location)?.to_shared())
506 }
507 }
508
509 pub unsafe fn from_definition_with_file(
519 memory: &MemoryType,
520 style: &MemoryStyle,
521 vm_memory_location: NonNull<VMMemoryDefinition>,
522 backing_file: Option<std::path::PathBuf>,
523 memory_type: MmapType,
524 ) -> Result<Self, MemoryError> {
525 unsafe {
526 Ok(VMOwnedMemory::from_definition_with_file(
527 memory,
528 style,
529 vm_memory_location,
530 backing_file,
531 memory_type,
532 )?
533 .to_shared())
534 }
535 }
536
537 pub fn copy(&self) -> Result<Self, MemoryError> {
539 let guard = self.mmap.read().unwrap();
540 Ok(Self {
541 mmap: Arc::new(RwLock::new(guard.copy()?)),
542 config: self.config.clone(),
543 conditions: ThreadConditions::new(),
544 })
545 }
546}
547
548impl LinearMemory for VMSharedMemory {
549 fn ty(&self) -> MemoryType {
551 let minimum = {
552 let guard = self.mmap.read().unwrap();
553 guard.size()
554 };
555 self.config.ty(minimum)
556 }
557
558 fn size(&self) -> Pages {
560 let guard = self.mmap.read().unwrap();
561 guard.size()
562 }
563
564 fn style(&self) -> MemoryStyle {
566 self.config.style()
567 }
568
569 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
574 let mut guard = self.mmap.write().unwrap();
575 guard.grow(delta, self.config.clone())
576 }
577
578 fn grow_at_least(&mut self, min_size: u64) -> Result<(), MemoryError> {
581 let mut guard = self.mmap.write().unwrap();
582 guard.grow_at_least(min_size, self.config.clone())
583 }
584
585 fn reset(&mut self) -> Result<(), MemoryError> {
587 let mut guard = self.mmap.write().unwrap();
588 guard.reset()?;
589 Ok(())
590 }
591
592 fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
594 let guard = self.mmap.read().unwrap();
595 guard.vm_memory_definition.as_ptr()
596 }
597
598 fn try_clone(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
600 Ok(Box::new(self.clone()))
601 }
602
603 fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
605 let forked = Self::copy(self)?;
606 Ok(Box::new(forked))
607 }
608
609 unsafe fn do_wait(
611 &mut self,
612 dst: u32,
613 expected: ExpectedValue,
614 timeout: Option<Duration>,
615 ) -> Result<u32, WaiterError> {
616 let dst = NotifyLocation {
617 address: dst,
618 memory_base: self.mmap.read().unwrap().alloc.as_ptr() as *mut _,
619 };
620 unsafe { self.conditions.do_wait(dst, expected, timeout) }
621 }
622
623 fn do_notify(&mut self, dst: u32, count: u32) -> u32 {
625 self.conditions.do_notify(dst, count)
626 }
627
628 fn thread_conditions(&self) -> Option<&ThreadConditions> {
629 Some(&self.conditions)
630 }
631}
632
633impl From<VMOwnedMemory> for VMMemory {
634 fn from(mem: VMOwnedMemory) -> Self {
635 Self(Box::new(mem))
636 }
637}
638
639impl From<VMSharedMemory> for VMMemory {
640 fn from(mem: VMSharedMemory) -> Self {
641 Self(Box::new(mem))
642 }
643}
644
645#[derive(Debug)]
647pub struct VMMemory(pub Box<dyn LinearMemory + Send + Sync + 'static>);
648
649impl From<Box<dyn LinearMemory + Send + Sync + 'static>> for VMMemory {
650 fn from(mem: Box<dyn LinearMemory + Send + Sync + 'static>) -> Self {
651 Self(mem)
652 }
653}
654
655impl LinearMemory for VMMemory {
656 fn ty(&self) -> MemoryType {
658 self.0.ty()
659 }
660
661 fn size(&self) -> Pages {
663 self.0.size()
664 }
665
666 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
671 self.0.grow(delta)
672 }
673
674 fn grow_at_least(&mut self, min_size: u64) -> Result<(), MemoryError> {
677 self.0.grow_at_least(min_size)
678 }
679
680 fn reset(&mut self) -> Result<(), MemoryError> {
682 self.0.reset()?;
683 Ok(())
684 }
685
686 fn style(&self) -> MemoryStyle {
688 self.0.style()
689 }
690
691 fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
693 self.0.vmmemory()
694 }
695
696 fn try_clone(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
698 self.0.try_clone()
699 }
700
701 unsafe fn initialize_with_data(&self, start: usize, data: &[u8]) -> Result<(), Trap> {
703 unsafe { self.0.initialize_with_data(start, data) }
704 }
705
706 fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
708 self.0.copy()
709 }
710
711 unsafe fn do_wait(
713 &mut self,
714 dst: u32,
715 expected: ExpectedValue,
716 timeout: Option<Duration>,
717 ) -> Result<u32, WaiterError> {
718 unsafe { self.0.do_wait(dst, expected, timeout) }
719 }
720
721 fn do_notify(&mut self, dst: u32, count: u32) -> u32 {
723 self.0.do_notify(dst, count)
724 }
725
726 fn thread_conditions(&self) -> Option<&ThreadConditions> {
727 self.0.thread_conditions()
728 }
729}
730
731impl VMMemory {
732 pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result<Self, MemoryError> {
738 Ok(if memory.shared {
739 Self(Box::new(VMSharedMemory::new(memory, style)?))
740 } else {
741 Self(Box::new(VMOwnedMemory::new(memory, style)?))
742 })
743 }
744
745 pub fn get_runtime_size(&self) -> u32 {
747 self.0.size().0
748 }
749
750 pub unsafe fn from_definition(
758 memory: &MemoryType,
759 style: &MemoryStyle,
760 vm_memory_location: NonNull<VMMemoryDefinition>,
761 ) -> Result<Self, MemoryError> {
762 unsafe {
763 Ok(if memory.shared {
764 Self(Box::new(VMSharedMemory::from_definition(
765 memory,
766 style,
767 vm_memory_location,
768 )?))
769 } else {
770 Self(Box::new(VMOwnedMemory::from_definition(
771 memory,
772 style,
773 vm_memory_location,
774 )?))
775 })
776 }
777 }
778
779 pub fn from_custom<IntoVMMemory>(memory: IntoVMMemory) -> Self
784 where
785 IntoVMMemory: Into<Self>,
786 {
787 memory.into()
788 }
789
790 pub fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
792 LinearMemory::copy(self)
793 }
794
795 pub fn try_clone(&self) -> Result<Self, MemoryError> {
797 LinearMemory::try_clone(self).map(Self)
798 }
799}
800
801#[doc(hidden)]
802pub unsafe fn initialize_memory_with_data(
804 memory: &VMMemoryDefinition,
805 start: usize,
806 data: &[u8],
807) -> Result<(), Trap> {
808 unsafe {
809 let mem_slice = slice::from_raw_parts_mut(memory.base, memory.current_length);
810 let end = start + data.len();
811 let to_init = &mut mem_slice[start..end];
812 to_init.copy_from_slice(data);
813
814 Ok(())
815 }
816}
817
818pub trait LinearMemory
820where
821 Self: std::fmt::Debug + Send,
822{
823 fn ty(&self) -> MemoryType;
825
826 fn size(&self) -> Pages;
828
829 fn style(&self) -> MemoryStyle;
831
832 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError>;
837
838 fn grow_at_least(&mut self, _min_size: u64) -> Result<(), MemoryError> {
841 Err(MemoryError::UnsupportedOperation {
842 message: "grow_at_least() is not supported".to_string(),
843 })
844 }
845
846 fn reset(&mut self) -> Result<(), MemoryError> {
848 Err(MemoryError::UnsupportedOperation {
849 message: "reset() is not supported".to_string(),
850 })
851 }
852
853 fn vmmemory(&self) -> NonNull<VMMemoryDefinition>;
855
856 fn try_clone(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError>;
858
859 #[doc(hidden)]
860 unsafe fn initialize_with_data(&self, start: usize, data: &[u8]) -> Result<(), Trap> {
864 unsafe {
865 let memory = self.vmmemory().as_ref();
866
867 initialize_memory_with_data(memory, start, data)
868 }
869 }
870
871 fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError>;
873
874 unsafe fn do_wait(
883 &mut self,
884 _dst: u32,
885 _expected: ExpectedValue,
886 _timeout: Option<Duration>,
887 ) -> Result<u32, WaiterError> {
888 Err(WaiterError::Unimplemented)
889 }
890
891 fn do_notify(&mut self, _dst: u32, _count: u32) -> u32 {
893 0
894 }
895
896 fn thread_conditions(&self) -> Option<&ThreadConditions> {
900 None
901 }
902}