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