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}