wasmer/entities/memory/mod.rs
1pub use shared::{MemoryOps, SharedMemory};
2use wasmer_types::{MemoryError, MemoryType, Pages};
3
4use crate::{
5 AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, StoreMut, StoreRef,
6 vm::{VMExtern, VMExternMemory, VMMemory},
7};
8
9pub(crate) mod buffer;
10pub(crate) mod inner;
11pub(crate) mod location;
12pub(crate) mod shared;
13pub(crate) mod view;
14
15pub(crate) use inner::*;
16pub use view::*;
17
18#[inline]
19pub(crate) fn shared_memory_detach_error() -> MemoryError {
20 MemoryError::Generic(
21 "could not detach shared WebAssembly memory for use outside the store: duplicating the \
22 backing handle failed, synchronization support may be unavailable, or the backend does \
23 not support exposing this shared memory independently of its store"
24 .into(),
25 )
26}
27
28/// A WebAssembly `memory` instance.
29///
30/// A memory instance is the runtime representation of a linear memory.
31/// It consists of a vector of bytes and an optional maximum size.
32///
33/// The length of the vector always is a multiple of the WebAssembly
34/// page size, which is defined to be the constant 65536 – abbreviated 64Ki.
35/// Like in a memory type, the maximum size in a memory instance is
36/// given in units of this page size.
37///
38/// A memory created by the host or in WebAssembly code will be accessible and
39/// mutable from both host and WebAssembly.
40///
41/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances>
42#[derive(Debug, Clone, PartialEq, Eq, derive_more::From)]
43#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
44pub struct Memory(pub(crate) BackendMemory);
45
46impl Memory {
47 /// Creates a new host [`Memory`] from the provided [`MemoryType`].
48 ///
49 /// This function will construct the `Memory` using the store
50 /// `BaseTunables`.
51 ///
52 /// # Example
53 ///
54 /// ```
55 /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
56 /// # let mut store = Store::default();
57 /// #
58 /// let m = Memory::new(&mut store, MemoryType::new(1, None, false)).unwrap();
59 /// ```
60 pub fn new(store: &mut impl AsStoreMut, ty: MemoryType) -> Result<Self, MemoryError> {
61 BackendMemory::new(store, ty).map(Self)
62 }
63
64 /// Create a memory object from an existing memory and attaches it to the store
65 pub fn new_from_existing<IntoVMMemory>(
66 new_store: &mut impl AsStoreMut,
67 memory: IntoVMMemory,
68 ) -> Self
69 where
70 IntoVMMemory: Into<VMMemory>,
71 {
72 Self(BackendMemory::new_from_existing(new_store, memory.into()))
73 }
74
75 /// Returns the [`MemoryType`] of the `Memory`.
76 ///
77 /// # Example
78 ///
79 /// ```
80 /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
81 /// # let mut store = Store::default();
82 /// #
83 /// let mt = MemoryType::new(1, None, false);
84 /// let m = Memory::new(&mut store, mt).unwrap();
85 ///
86 /// assert_eq!(m.ty(&mut store), mt);
87 /// ```
88 pub fn ty(&self, store: &impl AsStoreRef) -> MemoryType {
89 self.0.ty(store)
90 }
91
92 /// Creates a view into the memory that then allows for
93 /// read and write
94 pub fn view<'a>(&self, store: &'a (impl AsStoreRef + ?Sized)) -> MemoryView<'a> {
95 MemoryView::new(self, store)
96 }
97
98 /// Retrieve the size of the memory in pages.
99 pub fn size(&self, store: &impl AsStoreRef) -> Pages {
100 self.0.size(store)
101 }
102
103 /// Grow memory by the specified amount of WebAssembly [`Pages`] and return
104 /// the previous memory size.
105 ///
106 /// # Example
107 ///
108 /// ```
109 /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value, WASM_MAX_PAGES};
110 /// # let mut store = Store::default();
111 /// #
112 /// let m = Memory::new(&mut store, MemoryType::new(1, Some(3), false)).unwrap();
113 /// let p = m.grow(&mut store, 2).unwrap();
114 ///
115 /// assert_eq!(p, Pages(1));
116 /// assert_eq!(m.view(&mut store).size(), Pages(3));
117 /// ```
118 ///
119 /// # Errors
120 ///
121 /// Returns an error if memory can't be grown by the specified amount
122 /// of pages.
123 ///
124 /// ```should_panic
125 /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value, WASM_MAX_PAGES};
126 /// # use wasmer::FunctionEnv;
127 /// # let mut store = Store::default();
128 /// # let env = FunctionEnv::new(&mut store, ());
129 /// #
130 /// let m = Memory::new(&mut store, MemoryType::new(1, Some(1), false)).unwrap();
131 ///
132 /// // This results in an error: `MemoryError::CouldNotGrow`.
133 /// let s = m.grow(&mut store, 1).unwrap();
134 /// ```
135 pub fn grow<IntoPages>(
136 &self,
137 store: &mut impl AsStoreMut,
138 delta: IntoPages,
139 ) -> Result<Pages, MemoryError>
140 where
141 IntoPages: Into<Pages>,
142 {
143 self.0.grow(store, delta)
144 }
145
146 /// Grows the memory to at least a minimum size.
147 ///
148 /// # Note
149 ///
150 /// If the memory is already big enough for the min size this function does nothing.
151 pub fn grow_at_least(
152 &self,
153 store: &mut impl AsStoreMut,
154 min_size: u64,
155 ) -> Result<(), MemoryError> {
156 self.0.grow_at_least(store, min_size)
157 }
158
159 /// Resets the memory back to zero length
160 pub fn reset(&self, store: &mut impl AsStoreMut) -> Result<(), MemoryError> {
161 self.0.reset(store)
162 }
163
164 /// Attempts to duplicate this memory in a new store with a byte-for-byte copy
165 ///
166 /// Since Wasmer 8.0, this function can no longer be used for stores
167 /// in different threads; for that, use `copy`, and then `attach`
168 /// on the thread owning the other `Store`.
169 pub fn copy_to_store(
170 &self,
171 store: &impl AsStoreRef,
172 new_store: &mut impl AsStoreMut,
173 ) -> Result<Self, MemoryError> {
174 self.copy(store).map(|memory| memory.attach(new_store))
175 }
176
177 pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternMemory) -> Self {
178 Self(BackendMemory::from_vm_extern(store, vm_extern))
179 }
180
181 /// Checks whether this `Memory` can be used with the given context.
182 pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
183 self.0.is_from_store(store)
184 }
185
186 /// Attempts to create a detached copied memory handle that can later be
187 /// attached to a different store.
188 ///
189 /// If the memory is shared, this returns a shared handle. Otherwise, it
190 /// creates an independent byte-for-byte copy.
191 pub fn copy(&self, store: &impl AsStoreRef) -> Result<SharedMemory, MemoryError> {
192 self.0.copy(store)
193 }
194
195 /// Attempts to clone this memory (if its cloneable) in a new store
196 /// (cloned memory will be shared between those that clone it)
197 ///
198 /// Since Wasmer 8.0, this function can no longer be used for stores
199 /// in different threads; for that, use `as_shared`, and then `attach`
200 /// on the thread owning the other `Store`.
201 pub fn share_in_store(
202 &self,
203 store: &impl AsStoreRef,
204 new_store: &mut impl AsStoreMut,
205 ) -> Result<Self, MemoryError> {
206 if !self.ty(store).shared {
207 return Err(MemoryError::MemoryNotShared);
208 }
209
210 self.as_shared(store)
211 .ok_or_else(shared_memory_detach_error)
212 .map(|memory| memory.attach(new_store))
213 }
214
215 /// Get a [`SharedMemory`].
216 ///
217 /// Only returns `Some(_)` if the memory is shared, and if the target
218 /// backend supports shared memory operations.
219 ///
220 /// See [`SharedMemory`] and its methods for more information.
221 pub fn as_shared(&self, store: &impl AsStoreRef) -> Option<SharedMemory> {
222 self.0.as_shared(store)
223 }
224
225 /// Create a [`VMExtern`] from self.
226 pub(crate) fn to_vm_extern(&self) -> VMExtern {
227 self.0.to_vm_extern()
228 }
229}
230
231impl<'a> Exportable<'a> for Memory {
232 fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> {
233 match _extern {
234 Extern::Memory(memory) => Ok(memory),
235 _ => Err(ExportError::IncompatibleType),
236 }
237 }
238}