wasmer/entities/memory/
inner.rs

1use super::{SharedMemory, shared_memory_detach_error, 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        }
46    }
47
48    /// Create a memory object from an existing memory and attaches it to the store
49    #[inline]
50    pub fn new_from_existing(new_store: &mut impl AsStoreMut, memory: VMMemory) -> Self {
51        match new_store.as_store_mut().inner.store {
52            #[cfg(feature = "sys")]
53            crate::BackendStore::Sys(_) => Self::Sys(
54                crate::backend::sys::entities::memory::Memory::new_from_existing(
55                    new_store,
56                    memory.unwrap_sys(),
57                ),
58            ),
59            #[cfg(feature = "v8")]
60            crate::BackendStore::V8(_) => Self::V8(
61                crate::backend::v8::entities::memory::Memory::new_from_existing(
62                    new_store,
63                    memory.unwrap_v_8(),
64                ),
65            ),
66            #[cfg(feature = "js")]
67            crate::BackendStore::Js(_) => Self::Js(
68                crate::backend::js::entities::memory::Memory::new_from_existing(
69                    new_store,
70                    memory.unwrap_js(),
71                ),
72            ),
73        }
74    }
75
76    /// Returns the [`MemoryType`] of the [`BackendMemory`].
77    ///
78    /// # Example
79    ///
80    /// ```
81    /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
82    /// # let mut store = Store::default();
83    /// #
84    /// let mt = MemoryType::new(1, None, false);
85    /// let m = Memory::new(&mut store, mt).unwrap();
86    ///
87    /// assert_eq!(m.ty(&mut store), mt);
88    /// ```
89    #[inline]
90    pub fn ty(&self, store: &impl AsStoreRef) -> MemoryType {
91        match_rt!(on self => s {
92            s.ty(store)
93        })
94    }
95
96    /// Retrieve the size of the memory in pages.
97    pub fn size(&self, store: &impl AsStoreRef) -> Pages {
98        match_rt!(on self => s {
99            s.size(store)
100        })
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    #[inline]
136    pub fn grow<IntoPages>(
137        &self,
138        store: &mut impl AsStoreMut,
139        delta: IntoPages,
140    ) -> Result<Pages, MemoryError>
141    where
142        IntoPages: Into<Pages>,
143    {
144        match_rt!(on self => s {
145            s.grow(store, delta)
146        })
147    }
148
149    /// Grows the memory to at least a minimum size.
150    ///
151    /// # Note
152    ///
153    /// If the memory is already big enough for the min size this function does nothing.
154    #[inline]
155    pub fn grow_at_least(
156        &self,
157        store: &mut impl AsStoreMut,
158        min_size: u64,
159    ) -> Result<(), MemoryError> {
160        match_rt!(on self => s {
161            s.grow_at_least(store, min_size)
162        })
163    }
164
165    /// Resets the memory back to zero length
166    #[inline]
167    pub fn reset(&self, store: &mut impl AsStoreMut) -> Result<(), MemoryError> {
168        match_rt!(on self => s {
169            s.reset(store)
170        })
171    }
172
173    /// Attempts to duplicate this memory in a new store with a byte-for-byte copy
174    #[inline]
175    #[deprecated(
176        since = "8.0.0",
177        note = "Since `Store` is no longer `Send + Sync`, this method cannot be used meaningfully. \
178                Use `copy`, then `attach` on the thread owning the other `Store` instead."
179    )]
180    pub fn copy_to_store(
181        &self,
182        store: &impl AsStoreRef,
183        new_store: &mut impl AsStoreMut,
184    ) -> Result<Self, MemoryError> {
185        self.copy(store)
186            .map(|new_memory| new_memory.attach(new_store).0)
187    }
188
189    #[inline]
190    pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternMemory) -> Self {
191        match &store.as_store_mut().inner.store {
192            #[cfg(feature = "sys")]
193            crate::BackendStore::Sys(s) => Self::Sys(
194                crate::backend::sys::entities::memory::Memory::from_vm_extern(store, vm_extern),
195            ),
196            #[cfg(feature = "v8")]
197            crate::BackendStore::V8(s) => Self::V8(
198                crate::backend::v8::entities::memory::Memory::from_vm_extern(store, vm_extern),
199            ),
200            #[cfg(feature = "js")]
201            crate::BackendStore::Js(s) => Self::Js(
202                crate::backend::js::entities::memory::Memory::from_vm_extern(store, vm_extern),
203            ),
204        }
205    }
206
207    /// Checks whether this `Memory` can be used with the given context.
208    #[inline]
209    pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
210        match_rt!(on self => s {
211            s.is_from_store(store)
212        })
213    }
214
215    /// Attempts to create a detached copied memory handle that can later be
216    /// attached to a different store.
217    #[inline]
218    pub fn copy(&self, store: &impl AsStoreRef) -> Result<SharedMemory, MemoryError> {
219        match_rt!(on self => s {
220            s.copy(store)
221        })
222    }
223
224    /// Attempts to clone this memory (if its cloneable) in a new store
225    /// (cloned memory will be shared between those that clone it)
226    #[inline]
227    #[deprecated(
228        since = "8.0.0",
229        note = "Since `Store` is no longer `Send + Sync`, this method cannot be used meaningfully. \
230                Use `as_shared`, then `attach` on the thread owning the other `Store` instead."
231    )]
232    pub fn share_in_store(
233        &self,
234        store: &impl AsStoreRef,
235        new_store: &mut impl AsStoreMut,
236    ) -> Result<Self, MemoryError> {
237        if !self.ty(store).shared {
238            return Err(MemoryError::MemoryNotShared);
239        }
240
241        self.as_shared(store)
242            .ok_or_else(shared_memory_detach_error)
243            .map(|new_memory| new_memory.attach(new_store).0)
244    }
245
246    /// Get a [`SharedMemory`].
247    ///
248    /// Only returns `Some(_)` if the memory is shared, and if the target
249    /// backend supports shared memory operations.
250    ///
251    /// See [`SharedMemory`] and its methods for more information.
252    #[inline]
253    pub fn as_shared(&self, store: &impl AsStoreRef) -> Option<SharedMemory> {
254        if !self.ty(store).shared {
255            return None;
256        }
257
258        match_rt!(on self => s {
259            s.as_shared(store).ok()
260        })
261    }
262
263    /// Create a [`VMExtern`] from self.
264    #[inline]
265    pub(crate) fn to_vm_extern(&self) -> VMExtern {
266        match_rt!(on self => s {
267            s.to_vm_extern()
268        })
269    }
270}