wasmer_runtime_core_fl/memory/
dynamic.rs1use crate::error::GrowError;
2use crate::{
3 error::CreationError,
4 sys,
5 types::MemoryDescriptor,
6 units::{Bytes, Pages},
7 vm,
8};
9
10pub const DYNAMIC_GUARD_SIZE: usize = 4096;
11
12pub struct DynamicMemory {
26 memory: sys::Memory,
27 current: Pages,
28 max: Option<Pages>,
29}
30
31impl DynamicMemory {
32 pub(super) fn new(
33 desc: MemoryDescriptor,
34 local: &mut vm::LocalMemory,
35 ) -> Result<Box<Self>, CreationError> {
36 let min_bytes: Bytes = desc.minimum.into();
37 let memory = {
38 let mut memory = sys::Memory::with_size(min_bytes.0 + DYNAMIC_GUARD_SIZE)
39 .map_err(|_| CreationError::UnableToCreateMemory)?;
40 if desc.minimum != Pages(0) {
41 unsafe {
42 memory
43 .protect(0..min_bytes.0, sys::Protect::ReadWrite)
44 .map_err(|_| CreationError::UnableToCreateMemory)?;
45 }
46 }
47
48 memory
49 };
50
51 let mut storage = Box::new(DynamicMemory {
52 memory,
53 current: desc.minimum,
54 max: desc.maximum,
55 });
56 let storage_ptr: *mut DynamicMemory = &mut *storage;
57
58 local.base = storage.memory.as_ptr();
59 local.bound = min_bytes.0;
60 local.memory = storage_ptr as *mut ();
61
62 Ok(storage)
63 }
64
65 pub fn size(&self) -> Pages {
67 self.current
68 }
69
70 pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Result<Pages, GrowError> {
72 if delta == Pages(0) {
73 return Ok(self.current);
74 }
75
76 let new_pages = self.current.checked_add(delta).map_err(|e| e.into())?;
77
78 if let Some(max) = self.max {
79 if new_pages > max {
80 return Err(GrowError::ExceededMaxPagesForMemory(
81 new_pages.0 as usize,
82 max.0 as usize,
83 ));
84 }
85 }
86
87 let mut new_memory = sys::Memory::with_size(new_pages.bytes().0 + DYNAMIC_GUARD_SIZE)
88 .map_err(|e| e.into())?;
89
90 unsafe {
91 new_memory
92 .protect(0..new_pages.bytes().0, sys::Protect::ReadWrite)
93 .map_err(|e| e.into())?;
94
95 new_memory.as_slice_mut()[..self.current.bytes().0]
96 .copy_from_slice(&self.memory.as_slice()[..self.current.bytes().0]);
97 }
98
99 self.memory = new_memory; local.base = self.memory.as_ptr();
102 local.bound = new_pages.bytes().0;
103
104 let old_pages = self.current;
105 self.current = new_pages;
106 Ok(old_pages)
107 }
108
109 pub fn as_slice(&self) -> &[u8] {
111 unsafe { &self.memory.as_slice()[0..self.current.bytes().0] }
112 }
113
114 pub fn as_slice_mut(&mut self) -> &mut [u8] {
116 unsafe { &mut self.memory.as_slice_mut()[0..self.current.bytes().0] }
117 }
118}