wasmer/entities/memory/
inner.rs

1use super::{shared::SharedMemory, view::*};
2use wasmer_types::{MemoryError, MemoryType, Pages};
3
4use crate::{
5    AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, StoreMut, StoreRef,
6    macros::backend::{gen_rt_ty, match_rt},
7    vm::{VMExtern, VMExternMemory, VMMemory},
8};
9
10gen_rt_ty! {
11    #[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
12    #[derive(Debug, Clone, PartialEq, Eq, derive_more::From)]
13    pub BackendMemory(entities::memory::Memory);
14}
15
16impl BackendMemory {
17    /// Creates a new host [`BackendMemory`] from the provided [`MemoryType`].
18    ///
19    /// This function will construct the `Memory` using the store
20    /// `BaseTunables`.
21    ///
22    /// # Example
23    ///
24    /// ```
25    /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
26    /// # let mut store = Store::default();
27    /// #
28    /// let m = Memory::new(&mut store, MemoryType::new(1, None, false)).unwrap();
29    /// ```
30    #[inline]
31    pub fn new(store: &mut impl AsStoreMut, ty: MemoryType) -> Result<Self, MemoryError> {
32        match &store.as_store_mut().inner.store {
33            #[cfg(feature = "sys")]
34            crate::BackendStore::Sys(s) => Ok(Self::Sys(
35                crate::backend::sys::entities::memory::Memory::new(store, ty)?,
36            )),
37            #[cfg(feature = "v8")]
38            crate::BackendStore::V8(s) => Ok(Self::V8(
39                crate::backend::v8::entities::memory::Memory::new(store, ty)?,
40            )),
41            #[cfg(feature = "js")]
42            crate::BackendStore::Js(s) => Ok(Self::Js(
43                crate::backend::js::entities::memory::Memory::new(store, ty)?,
44            )),
45            #[cfg(feature = "jsc")]
46            crate::BackendStore::Jsc(s) => Ok(Self::Jsc(
47                crate::backend::jsc::entities::memory::Memory::new(store, ty)?,
48            )),
49        }
50    }
51
52    /// Create a memory object from an existing memory and attaches it to the store
53    #[inline]
54    pub fn new_from_existing(new_store: &mut impl AsStoreMut, memory: VMMemory) -> Self {
55        match new_store.as_store_mut().inner.store {
56            #[cfg(feature = "sys")]
57            crate::BackendStore::Sys(_) => Self::Sys(
58                crate::backend::sys::entities::memory::Memory::new_from_existing(
59                    new_store,
60                    memory.unwrap_sys(),
61                ),
62            ),
63            #[cfg(feature = "v8")]
64            crate::BackendStore::V8(_) => Self::V8(
65                crate::backend::v8::entities::memory::Memory::new_from_existing(
66                    new_store,
67                    memory.unwrap_v_8(),
68                ),
69            ),
70            #[cfg(feature = "js")]
71            crate::BackendStore::Js(_) => Self::Js(
72                crate::backend::js::entities::memory::Memory::new_from_existing(
73                    new_store,
74                    memory.unwrap_js(),
75                ),
76            ),
77            #[cfg(feature = "jsc")]
78            crate::BackendStore::Jsc(_) => Self::Jsc(
79                crate::backend::jsc::entities::memory::Memory::new_from_existing(
80                    new_store,
81                    memory.unwrap_jsc(),
82                ),
83            ),
84        }
85    }
86
87    /// Returns the [`MemoryType`] of the [`BackendMemory`].
88    ///
89    /// # Example
90    ///
91    /// ```
92    /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
93    /// # let mut store = Store::default();
94    /// #
95    /// let mt = MemoryType::new(1, None, false);
96    /// let m = Memory::new(&mut store, mt).unwrap();
97    ///
98    /// assert_eq!(m.ty(&mut store), mt);
99    /// ```
100    #[inline]
101    pub fn ty(&self, store: &impl AsStoreRef) -> MemoryType {
102        match_rt!(on self => s {
103            s.ty(store)
104        })
105    }
106
107    /// Retrieve the size of the memory in pages.
108    pub fn size(&self, store: &impl AsStoreRef) -> Pages {
109        match_rt!(on self => s {
110            s.size(store)
111        })
112    }
113
114    /// Grow memory by the specified amount of WebAssembly [`Pages`] and return
115    /// the previous memory size.
116    ///
117    /// # Example
118    ///
119    /// ```
120    /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value, WASM_MAX_PAGES};
121    /// # let mut store = Store::default();
122    /// #
123    /// let m = Memory::new(&mut store, MemoryType::new(1, Some(3), false)).unwrap();
124    /// let p = m.grow(&mut store, 2).unwrap();
125    ///
126    /// assert_eq!(p, Pages(1));
127    /// assert_eq!(m.view(&mut store).size(), Pages(3));
128    /// ```
129    ///
130    /// # Errors
131    ///
132    /// Returns an error if memory can't be grown by the specified amount
133    /// of pages.
134    ///
135    /// ```should_panic
136    /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value, WASM_MAX_PAGES};
137    /// # use wasmer::FunctionEnv;
138    /// # let mut store = Store::default();
139    /// # let env = FunctionEnv::new(&mut store, ());
140    /// #
141    /// let m = Memory::new(&mut store, MemoryType::new(1, Some(1), false)).unwrap();
142    ///
143    /// // This results in an error: `MemoryError::CouldNotGrow`.
144    /// let s = m.grow(&mut store, 1).unwrap();
145    /// ```
146    #[inline]
147    pub fn grow<IntoPages>(
148        &self,
149        store: &mut impl AsStoreMut,
150        delta: IntoPages,
151    ) -> Result<Pages, MemoryError>
152    where
153        IntoPages: Into<Pages>,
154    {
155        match_rt!(on self => s {
156            s.grow(store, delta)
157        })
158    }
159
160    /// Grows the memory to at least a minimum size.
161    ///
162    /// # Note
163    ///
164    /// If the memory is already big enough for the min size this function does nothing.
165    #[inline]
166    pub fn grow_at_least(
167        &self,
168        store: &mut impl AsStoreMut,
169        min_size: u64,
170    ) -> Result<(), MemoryError> {
171        match_rt!(on self => s {
172            s.grow_at_least(store, min_size)
173        })
174    }
175
176    /// Resets the memory back to zero length
177    #[inline]
178    pub fn reset(&self, store: &mut impl AsStoreMut) -> Result<(), MemoryError> {
179        match_rt!(on self => s {
180            s.reset(store)
181        })
182    }
183
184    /// Attempts to duplicate this memory (if its clonable) in a new store
185    /// (copied memory)
186    #[inline]
187    pub fn copy_to_store(
188        &self,
189        store: &impl AsStoreRef,
190        new_store: &mut impl AsStoreMut,
191    ) -> Result<Self, MemoryError> {
192        if !self.ty(store).shared {
193            // We should only be able to duplicate in a new store if the memory is shared
194            return Err(MemoryError::InvalidMemory {
195                reason: "memory is not a shared memory type".to_string(),
196            });
197        }
198
199        match self {
200            #[cfg(feature = "sys")]
201            Self::Sys(s) => s.try_copy(store).map(|new_memory| {
202                Self::new_from_existing(
203                    new_store,
204                    VMMemory::Sys(crate::backend::sys::vm::VMMemory(new_memory)),
205                )
206            }),
207
208            #[cfg(feature = "v8")]
209            Self::V8(s) => s
210                .try_copy(store)
211                .map(|new_memory| Self::new_from_existing(new_store, VMMemory::V8(new_memory))),
212            #[cfg(feature = "js")]
213            Self::Js(s) => s
214                .try_copy(store)
215                .map(|new_memory| Self::new_from_existing(new_store, VMMemory::Js(new_memory))),
216            #[cfg(feature = "jsc")]
217            Self::Jsc(s) => s
218                .try_copy(store)
219                .map(|new_memory| Self::new_from_existing(new_store, VMMemory::Jsc(new_memory))),
220        }
221    }
222
223    #[inline]
224    pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternMemory) -> Self {
225        match &store.as_store_mut().inner.store {
226            #[cfg(feature = "sys")]
227            crate::BackendStore::Sys(s) => Self::Sys(
228                crate::backend::sys::entities::memory::Memory::from_vm_extern(store, vm_extern),
229            ),
230            #[cfg(feature = "v8")]
231            crate::BackendStore::V8(s) => Self::V8(
232                crate::backend::v8::entities::memory::Memory::from_vm_extern(store, vm_extern),
233            ),
234            #[cfg(feature = "js")]
235            crate::BackendStore::Js(s) => Self::Js(
236                crate::backend::js::entities::memory::Memory::from_vm_extern(store, vm_extern),
237            ),
238            #[cfg(feature = "jsc")]
239            crate::BackendStore::Jsc(s) => Self::Jsc(
240                crate::backend::jsc::entities::memory::Memory::from_vm_extern(store, vm_extern),
241            ),
242        }
243    }
244
245    /// Checks whether this `Memory` can be used with the given context.
246    #[inline]
247    pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
248        match_rt!(on self => s {
249            s.is_from_store(store)
250        })
251    }
252
253    /// Attempt to create a new reference to the underlying memory; this new reference can then be
254    /// used within a different store (from the same implementer).
255    ///
256    /// # Errors
257    ///
258    /// Fails if the underlying memory is not clonable.
259    #[inline]
260    pub fn try_clone(&self, store: &impl AsStoreRef) -> Result<VMMemory, MemoryError> {
261        match self {
262            #[cfg(feature = "sys")]
263            Self::Sys(s) => s.try_clone(store).map(VMMemory::Sys),
264            #[cfg(feature = "v8")]
265            Self::V8(s) => s.try_clone(store).map(VMMemory::V8),
266            #[cfg(feature = "js")]
267            Self::Js(s) => s.try_clone(store).map(VMMemory::Js),
268            #[cfg(feature = "jsc")]
269            Self::Jsc(s) => s.try_clone(store).map(VMMemory::Jsc),
270        }
271    }
272
273    /// Attempts to clone this memory (if its clonable) in a new store
274    /// (cloned memory will be shared between those that clone it)
275    #[inline]
276    pub fn share_in_store(
277        &self,
278        store: &impl AsStoreRef,
279        new_store: &mut impl AsStoreMut,
280    ) -> Result<Self, MemoryError> {
281        if !self.ty(store).shared {
282            // We should only be able to duplicate in a new store if the memory is shared
283            return Err(MemoryError::InvalidMemory {
284                reason: "memory is not a shared memory type".to_string(),
285            });
286        }
287
288        match self {
289            #[cfg(feature = "sys")]
290            Self::Sys(s) => s
291                .try_clone(store)
292                .map(|new_memory| Self::new_from_existing(new_store, VMMemory::Sys(new_memory))),
293            #[cfg(feature = "v8")]
294            Self::V8(s) => s
295                .try_clone(store)
296                .map(|new_memory| Self::new_from_existing(new_store, VMMemory::V8(new_memory))),
297            #[cfg(feature = "js")]
298            Self::Js(s) => s
299                .try_clone(store)
300                .map(|new_memory| Self::new_from_existing(new_store, VMMemory::Js(new_memory))),
301            #[cfg(feature = "jsc")]
302            Self::Jsc(s) => s
303                .try_clone(store)
304                .map(|new_memory| Self::new_from_existing(new_store, VMMemory::Jsc(new_memory))),
305        }
306    }
307
308    /// Get a [`SharedMemory`].
309    ///
310    /// Only returns `Some(_)` if the memory is shared, and if the target
311    /// backend supports shared memory operations.
312    ///
313    /// See [`SharedMemory`] and its methods for more information.
314    #[inline]
315    pub fn as_shared(&self, store: &impl AsStoreRef) -> Option<SharedMemory> {
316        if !self.ty(store).shared {
317            return None;
318        }
319
320        match_rt!(on self => s {
321            s.as_shared(store)
322        })
323    }
324
325    /// Create a [`VMExtern`] from self.
326    #[inline]
327    pub(crate) fn to_vm_extern(&self) -> VMExtern {
328        match_rt!(on self => s {
329            s.to_vm_extern()
330        })
331    }
332}