1use std::{
8 cell::UnsafeCell,
9 convert::TryInto,
10 ptr::NonNull,
11 sync::{Arc, RwLock},
12};
13
14use wasmer::{Bytes, MemoryError, MemoryType, Pages};
15use wasmer_types::{MemoryStyle, WASM_PAGE_SIZE};
16use wasmer_vm::{
17 LinearMemory, MaybeInstanceOwned, ThreadConditions, Trap, VMMemoryDefinition, WaiterError,
18};
19
20use super::fd_mmap::FdMmap;
21
22#[derive(Debug)]
34struct WasmMmap {
35 alloc: FdMmap,
37 size: Pages,
39 vm_memory_definition: MaybeInstanceOwned<VMMemoryDefinition>,
41}
42
43unsafe impl Send for WasmMmap {}
47unsafe impl Sync for WasmMmap {}
49
50impl WasmMmap {
51 fn get_vm_memory_definition(&self) -> NonNull<VMMemoryDefinition> {
52 self.vm_memory_definition.as_ptr()
53 }
54
55 fn size(&self) -> Pages {
56 unsafe {
57 let md_ptr = self.get_vm_memory_definition();
58 let md = md_ptr.as_ref();
59 Bytes::from(md.current_length).try_into().unwrap()
60 }
61 }
62
63 fn grow(&mut self, delta: Pages, conf: VMMemoryConfig) -> Result<Pages, MemoryError> {
64 if delta.0 == 0 {
66 return Ok(self.size);
67 }
68
69 let new_pages = self
70 .size
71 .checked_add(delta)
72 .ok_or(MemoryError::CouldNotGrow {
73 current: self.size,
74 attempted_delta: delta,
75 })?;
76 let prev_pages = self.size;
77
78 if let Some(maximum) = conf.maximum
79 && new_pages > maximum
80 {
81 return Err(MemoryError::CouldNotGrow {
82 current: self.size,
83 attempted_delta: delta,
84 });
85 }
86
87 if new_pages >= Pages::max_value() {
91 return Err(MemoryError::CouldNotGrow {
93 current: self.size,
94 attempted_delta: delta,
95 });
96 }
97
98 let delta_bytes = delta.bytes().0;
99 let prev_bytes = prev_pages.bytes().0;
100 let new_bytes = new_pages.bytes().0;
101
102 if new_bytes > self.alloc.len() - conf.offset_guard_size {
103 let guard_bytes = conf.offset_guard_size;
106 let request_bytes =
107 new_bytes
108 .checked_add(guard_bytes)
109 .ok_or_else(|| MemoryError::CouldNotGrow {
110 current: new_pages,
111 attempted_delta: Bytes(guard_bytes).try_into().unwrap(),
112 })?;
113
114 let mut new_mmap = FdMmap::accessible_reserved(new_bytes, request_bytes)
115 .map_err(MemoryError::Region)?;
116
117 let copy_len = self.alloc.len() - conf.offset_guard_size;
118 new_mmap.as_mut_slice()[..copy_len].copy_from_slice(&self.alloc.as_slice()[..copy_len]);
119
120 self.alloc = new_mmap;
121 } else if delta_bytes > 0 {
122 self.alloc
124 .make_accessible(prev_bytes, delta_bytes)
125 .map_err(MemoryError::Region)?;
126 }
127
128 self.size = new_pages;
129
130 unsafe {
132 let mut md_ptr = self.vm_memory_definition.as_ptr();
133 let md = md_ptr.as_mut();
134 md.current_length = new_pages.bytes().0;
135 md.base = self.alloc.as_mut_ptr() as _;
136 }
137
138 Ok(prev_pages)
139 }
140
141 fn grow_at_least(&mut self, min_size: u64, conf: VMMemoryConfig) -> Result<(), MemoryError> {
144 let cur_size = self.size.bytes().0 as u64;
145 if cur_size < min_size {
146 let growth = min_size - cur_size;
147 let growth_pages = ((growth - 1) / WASM_PAGE_SIZE as u64) + 1;
148 self.grow(Pages(growth_pages as u32), conf)?;
149 }
150
151 Ok(())
152 }
153
154 fn reset(&mut self) -> Result<(), MemoryError> {
155 self.size.0 = 0;
156 Ok(())
157 }
158
159 pub fn copy(&self) -> Result<Self, MemoryError> {
162 let mem_length = self.size.bytes().0;
163 let mut alloc = self
164 .alloc
165 .duplicate(Some(mem_length))
166 .map_err(MemoryError::Generic)?;
167 let base_ptr = alloc.as_mut_ptr();
168 Ok(Self {
169 vm_memory_definition: MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(
170 VMMemoryDefinition {
171 base: base_ptr,
172 current_length: mem_length,
173 },
174 ))),
175 alloc,
176 size: self.size,
177 })
178 }
179}
180
181#[derive(Debug, Clone)]
183struct VMMemoryConfig {
184 maximum: Option<Pages>,
186 memory: MemoryType,
188 style: MemoryStyle,
190 offset_guard_size: usize,
193}
194
195impl VMMemoryConfig {
196 fn ty(&self, minimum: Pages) -> MemoryType {
197 let mut out = self.memory;
198 out.minimum = minimum;
199
200 out
201 }
202
203 fn style(&self) -> MemoryStyle {
204 self.style
205 }
206}
207
208#[derive(Debug)]
210pub struct VMOwnedMemory {
211 mmap: WasmMmap,
213 config: VMMemoryConfig,
215}
216
217unsafe impl Send for VMOwnedMemory {}
218unsafe impl Sync for VMOwnedMemory {}
219
220impl VMOwnedMemory {
221 pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result<Self, MemoryError> {
226 unsafe { Self::new_internal(memory, style, None) }
227 }
228
229 pub unsafe fn from_definition(
237 memory: &MemoryType,
238 style: &MemoryStyle,
239 vm_memory_location: NonNull<VMMemoryDefinition>,
240 ) -> Result<Self, MemoryError> {
241 unsafe { Self::new_internal(memory, style, Some(vm_memory_location)) }
242 }
243
244 unsafe fn new_internal(
246 memory: &MemoryType,
247 style: &MemoryStyle,
248 vm_memory_location: Option<NonNull<VMMemoryDefinition>>,
249 ) -> Result<Self, MemoryError> {
250 if memory.minimum > Pages::max_value() {
251 return Err(MemoryError::MinimumMemoryTooLarge {
252 min_requested: memory.minimum,
253 max_allowed: Pages::max_value(),
254 });
255 }
256 if let Some(max) = memory.maximum {
258 if max > Pages::max_value() {
259 return Err(MemoryError::MaximumMemoryTooLarge {
260 max_requested: max,
261 max_allowed: Pages::max_value(),
262 });
263 }
264 if max < memory.minimum {
265 return Err(MemoryError::InvalidMemory {
266 reason: format!(
267 "the maximum ({} pages) is less than the minimum ({} pages)",
268 max.0, memory.minimum.0
269 ),
270 });
271 }
272 }
273
274 let offset_guard_bytes = style.offset_guard_size() as usize;
275
276 let minimum_pages = match style {
277 MemoryStyle::Dynamic { .. } => memory.minimum,
278 MemoryStyle::Static { bound, .. } => {
279 assert!(*bound >= memory.minimum);
280 *bound
281 }
282 };
283 let minimum_bytes = minimum_pages.bytes().0;
284 let request_bytes = minimum_bytes.checked_add(offset_guard_bytes).unwrap();
285 let mapped_pages = memory.minimum;
286 let mapped_bytes = mapped_pages.bytes();
287
288 let mut alloc = FdMmap::accessible_reserved(mapped_bytes.0, request_bytes)
289 .map_err(MemoryError::Region)?;
290 let base_ptr = alloc.as_mut_ptr();
291 let mem_length = memory.minimum.bytes().0;
292 let mmap = WasmMmap {
293 vm_memory_definition: if let Some(mem_loc) = vm_memory_location {
294 {
295 let mut ptr = mem_loc;
296 let md = unsafe { ptr.as_mut() };
297 md.base = base_ptr;
298 md.current_length = mem_length;
299 }
300 MaybeInstanceOwned::Instance(mem_loc)
301 } else {
302 MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(VMMemoryDefinition {
303 base: base_ptr,
304 current_length: mem_length,
305 })))
306 },
307 alloc,
308 size: memory.minimum,
309 };
310
311 Ok(Self {
312 mmap,
313 config: VMMemoryConfig {
314 maximum: memory.maximum,
315 offset_guard_size: offset_guard_bytes,
316 memory: *memory,
317 style: *style,
318 },
319 })
320 }
321
322 pub fn to_shared(self) -> VMSharedMemory {
324 VMSharedMemory {
325 mmap: Arc::new(RwLock::new(self.mmap)),
326 config: self.config,
327 conditions: ThreadConditions::new(),
328 }
329 }
330
331 pub fn copy(&self) -> Result<Self, MemoryError> {
333 Ok(Self {
334 mmap: self.mmap.copy()?,
335 config: self.config.clone(),
336 })
337 }
338}
339
340impl LinearMemory for VMOwnedMemory {
341 fn ty(&self) -> MemoryType {
343 let minimum = self.mmap.size();
344 self.config.ty(minimum)
345 }
346
347 fn size(&self) -> Pages {
349 self.mmap.size()
350 }
351
352 fn style(&self) -> MemoryStyle {
354 self.config.style()
355 }
356
357 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
362 self.mmap.grow(delta, self.config.clone())
363 }
364
365 fn grow_at_least(&mut self, min_size: u64) -> Result<(), MemoryError> {
368 self.mmap.grow_at_least(min_size, self.config.clone())
369 }
370
371 fn reset(&mut self) -> Result<(), MemoryError> {
372 self.mmap.reset()?;
373 Ok(())
374 }
375
376 fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
378 self.mmap.vm_memory_definition.as_ptr()
379 }
380
381 fn try_clone(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
383 Err(MemoryError::MemoryNotShared)
384 }
385
386 fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
388 let forked = Self::copy(self)?;
389 Ok(Box::new(forked))
390 }
391}
392
393#[derive(Debug, Clone)]
395pub struct VMSharedMemory {
396 mmap: Arc<RwLock<WasmMmap>>,
398 config: VMMemoryConfig,
400 conditions: ThreadConditions,
401}
402
403impl VMSharedMemory {
404 pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result<Self, MemoryError> {
409 Ok(VMOwnedMemory::new(memory, style)?.to_shared())
410 }
411
412 pub unsafe fn from_definition(
420 memory: &MemoryType,
421 style: &MemoryStyle,
422 vm_memory_location: NonNull<VMMemoryDefinition>,
423 ) -> Result<Self, MemoryError> {
424 let owned = unsafe { VMOwnedMemory::from_definition(memory, style, vm_memory_location)? };
425 Ok(owned.to_shared())
426 }
427
428 pub fn copy(&self) -> Result<Self, MemoryError> {
430 let guard = self.mmap.read().unwrap();
431 Ok(Self {
432 mmap: Arc::new(RwLock::new(guard.copy()?)),
433 config: self.config.clone(),
434 conditions: ThreadConditions::new(),
435 })
436 }
437}
438
439impl LinearMemory for VMSharedMemory {
440 fn ty(&self) -> MemoryType {
442 let minimum = {
443 let guard = self.mmap.read().unwrap();
444 guard.size()
445 };
446 self.config.ty(minimum)
447 }
448
449 fn size(&self) -> Pages {
451 let guard = self.mmap.read().unwrap();
452 guard.size()
453 }
454
455 fn reset(&mut self) -> Result<(), MemoryError> {
457 let mut guard = self.mmap.write().unwrap();
458 guard.reset()?;
459 Ok(())
460 }
461
462 fn style(&self) -> MemoryStyle {
464 self.config.style()
465 }
466
467 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
472 let mut guard = self.mmap.write().unwrap();
473 guard.grow(delta, self.config.clone())
474 }
475
476 fn grow_at_least(&mut self, min_size: u64) -> Result<(), MemoryError> {
479 let mut guard = self.mmap.write().unwrap();
480 guard.grow_at_least(min_size, self.config.clone())
481 }
482
483 fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
485 let guard = self.mmap.read().unwrap();
486 guard.vm_memory_definition.as_ptr()
487 }
488
489 fn try_clone(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
491 Ok(Box::new(self.clone()))
492 }
493
494 fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
496 let forked = Self::copy(self)?;
497 Ok(Box::new(forked))
498 }
499
500 unsafe fn do_wait(
501 &mut self,
502 dst: u32,
503 expected: wasmer_vm::ExpectedValue,
504 timeout: Option<std::time::Duration>,
505 ) -> Result<u32, WaiterError> {
506 unsafe {
507 let dst = wasmer_vm::NotifyLocation {
508 address: dst,
509 memory_base: self
510 .mmap
511 .read()
512 .unwrap()
513 .vm_memory_definition
514 .as_ptr()
515 .as_ref()
516 .base,
517 };
518 self.conditions.do_wait(dst, expected, timeout)
519 }
520 }
521
522 fn do_notify(&mut self, dst: u32, count: u32) -> u32 {
523 self.conditions.do_notify(dst, count)
524 }
525}
526
527impl From<VMOwnedMemory> for VMMemory {
528 fn from(mem: VMOwnedMemory) -> Self {
529 Self(Box::new(mem))
530 }
531}
532
533impl From<VMSharedMemory> for VMMemory {
534 fn from(mem: VMSharedMemory) -> Self {
535 Self(Box::new(mem))
536 }
537}
538
539#[derive(Debug)]
541pub struct VMMemory(pub Box<dyn LinearMemory + 'static>);
542
543impl From<Box<dyn LinearMemory + 'static>> for VMMemory {
544 fn from(mem: Box<dyn LinearMemory + 'static>) -> Self {
545 Self(mem)
546 }
547}
548
549impl LinearMemory for VMMemory {
550 fn ty(&self) -> MemoryType {
552 self.0.ty()
553 }
554
555 fn size(&self) -> Pages {
557 self.0.size()
558 }
559
560 fn grow(&mut self, delta: Pages) -> Result<Pages, MemoryError> {
565 self.0.grow(delta)
566 }
567
568 fn grow_at_least(&mut self, min_size: u64) -> Result<(), MemoryError> {
571 self.0.grow_at_least(min_size)
572 }
573
574 fn reset(&mut self) -> Result<(), MemoryError> {
576 self.0.reset()?;
577 Ok(())
578 }
579
580 fn style(&self) -> MemoryStyle {
582 self.0.style()
583 }
584
585 fn vmmemory(&self) -> NonNull<VMMemoryDefinition> {
587 self.0.vmmemory()
588 }
589
590 fn try_clone(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
592 self.0.try_clone()
593 }
594
595 unsafe fn initialize_with_data(&self, start: usize, data: &[u8]) -> Result<(), Trap> {
597 unsafe { self.0.initialize_with_data(start, data) }
598 }
599
600 fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
602 self.0.copy()
603 }
604}
605
606impl VMMemory {
607 pub fn new(memory: &MemoryType, style: &MemoryStyle) -> Result<Self, MemoryError> {
613 Ok(if memory.shared {
614 Self(Box::new(VMSharedMemory::new(memory, style)?))
615 } else {
616 Self(Box::new(VMOwnedMemory::new(memory, style)?))
617 })
618 }
619
620 pub fn get_runtime_size(&self) -> u32 {
622 self.0.size().0
623 }
624
625 pub unsafe fn from_definition(
633 memory: &MemoryType,
634 style: &MemoryStyle,
635 vm_memory_location: NonNull<VMMemoryDefinition>,
636 ) -> Result<Self, MemoryError> {
637 Ok(if memory.shared {
638 let shared =
639 unsafe { VMSharedMemory::from_definition(memory, style, vm_memory_location)? };
640 Self(Box::new(shared))
641 } else {
642 let owned =
643 unsafe { VMOwnedMemory::from_definition(memory, style, vm_memory_location)? };
644 Self(Box::new(owned))
645 })
646 }
647
648 pub fn from_custom<IntoVMMemory>(memory: IntoVMMemory) -> Self
653 where
654 IntoVMMemory: Into<Self>,
655 {
656 memory.into()
657 }
658
659 pub fn copy(&self) -> Result<Box<dyn LinearMemory + Send + Sync + 'static>, MemoryError> {
661 LinearMemory::copy(self)
662 }
663}
664
665#[doc(hidden)]
666pub unsafe fn initialize_memory_with_data(
668 memory: &VMMemoryDefinition,
669 start: usize,
670 data: &[u8],
671) -> Result<(), Trap> {
672 let mem_slice = unsafe { std::slice::from_raw_parts_mut(memory.base, memory.current_length) };
673 let end = start + data.len();
674 let to_init = &mut mem_slice[start..end];
675 to_init.copy_from_slice(data);
676
677 Ok(())
678}