wasmi/memory/
mod.rs

1mod data;
2mod ty;
3
4pub use self::{
5    data::{DataSegment, DataSegmentEntity, DataSegmentIdx},
6    ty::{MemoryType, MemoryTypeBuilder},
7};
8use super::{AsContext, AsContextMut, StoreContext, StoreContextMut, Stored};
9use crate::{collections::arena::ArenaIndex, core::CoreMemory, errors::MemoryError, Error};
10
11/// A raw index to a linear memory entity.
12#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
13pub struct MemoryIdx(u32);
14
15impl ArenaIndex for MemoryIdx {
16    fn into_usize(self) -> usize {
17        self.0 as usize
18    }
19
20    fn from_usize(value: usize) -> Self {
21        let value = value.try_into().unwrap_or_else(|error| {
22            panic!("index {value} is out of bounds as memory index: {error}")
23        });
24        Self(value)
25    }
26}
27
28/// A Wasm linear memory reference.
29#[derive(Debug, Copy, Clone)]
30#[repr(transparent)]
31pub struct Memory(Stored<MemoryIdx>);
32
33impl Memory {
34    /// Creates a new linear memory reference.
35    pub(super) fn from_inner(stored: Stored<MemoryIdx>) -> Self {
36        Self(stored)
37    }
38
39    /// Returns the underlying stored representation.
40    pub(super) fn as_inner(&self) -> &Stored<MemoryIdx> {
41        &self.0
42    }
43
44    /// Creates a new linear memory to the store.
45    ///
46    /// # Errors
47    ///
48    /// If more than [`u32::MAX`] much linear memory is allocated.
49    pub fn new(mut ctx: impl AsContextMut, ty: MemoryType) -> Result<Self, Error> {
50        let (inner, mut resource_limiter) = ctx
51            .as_context_mut()
52            .store
53            .store_inner_and_resource_limiter_ref();
54        let entity = CoreMemory::new(ty.core, &mut resource_limiter)?;
55        let memory = inner.alloc_memory(entity);
56        Ok(memory)
57    }
58
59    /// Creates a new linear memory to the store.
60    ///
61    /// # Errors
62    ///
63    /// If more than [`u32::MAX`] much linear memory is allocated.
64    /// - If static buffer is invalid
65    pub fn new_static(
66        mut ctx: impl AsContextMut,
67        ty: MemoryType,
68        buf: &'static mut [u8],
69    ) -> Result<Self, Error> {
70        let (inner, mut resource_limiter) = ctx
71            .as_context_mut()
72            .store
73            .store_inner_and_resource_limiter_ref();
74        let entity = CoreMemory::new_static(ty.core, &mut resource_limiter, buf)?;
75        let memory = inner.alloc_memory(entity);
76        Ok(memory)
77    }
78
79    /// Returns the memory type of the linear memory.
80    ///
81    /// # Panics
82    ///
83    /// Panics if `ctx` does not own this [`Memory`].
84    pub fn ty(&self, ctx: impl AsContext) -> MemoryType {
85        let core = ctx.as_context().store.inner.resolve_memory(self).ty();
86        MemoryType { core }
87    }
88
89    /// Returns the dynamic [`MemoryType`] of the [`Memory`].
90    ///
91    /// # Note
92    ///
93    /// This respects the current size of the [`Memory`] as
94    /// its minimum size and is useful for import subtyping checks.
95    ///
96    /// # Panics
97    ///
98    /// Panics if `ctx` does not own this [`Memory`].
99    pub(crate) fn dynamic_ty(&self, ctx: impl AsContext) -> MemoryType {
100        let core = ctx
101            .as_context()
102            .store
103            .inner
104            .resolve_memory(self)
105            .dynamic_ty();
106        MemoryType { core }
107    }
108
109    /// Returns the size, in WebAssembly pages, of this Wasm linear memory.
110    ///
111    /// # Panics
112    ///
113    /// Panics if `ctx` does not own this [`Memory`].
114    pub fn size(&self, ctx: impl AsContext) -> u64 {
115        ctx.as_context().store.inner.resolve_memory(self).size()
116    }
117
118    /// Grows the linear memory by the given amount of new pages.
119    ///
120    /// Returns the amount of pages before the operation upon success.
121    ///
122    /// # Errors
123    ///
124    /// If the linear memory would grow beyond its maximum limit after
125    /// the grow operation.
126    ///
127    /// # Panics
128    ///
129    /// Panics if `ctx` does not own this [`Memory`].
130    pub fn grow(&self, mut ctx: impl AsContextMut, additional: u64) -> Result<u64, MemoryError> {
131        let (inner, mut limiter) = ctx
132            .as_context_mut()
133            .store
134            .store_inner_and_resource_limiter_ref();
135        inner
136            .resolve_memory_mut(self)
137            .grow(additional, None, &mut limiter)
138            .map_err(|_| MemoryError::OutOfBoundsGrowth)
139    }
140
141    /// Returns a shared slice to the bytes underlying the [`Memory`].
142    ///
143    /// # Panics
144    ///
145    /// Panics if `ctx` does not own this [`Memory`].
146    pub fn data<'a, T: 'a>(&self, ctx: impl Into<StoreContext<'a, T>>) -> &'a [u8] {
147        ctx.into().store.inner.resolve_memory(self).data()
148    }
149
150    /// Returns an exclusive slice to the bytes underlying the [`Memory`].
151    ///
152    /// # Panics
153    ///
154    /// Panics if `ctx` does not own this [`Memory`].
155    pub fn data_mut<'a, T: 'a>(&self, ctx: impl Into<StoreContextMut<'a, T>>) -> &'a mut [u8] {
156        ctx.into().store.inner.resolve_memory_mut(self).data_mut()
157    }
158
159    /// Returns an exclusive slice to the bytes underlying the [`Memory`], and an exclusive
160    /// reference to the user provided state.
161    ///
162    /// # Panics
163    ///
164    /// Panics if `ctx` does not own this [`Memory`].
165    pub fn data_and_store_mut<'a, T: 'a>(
166        &self,
167        ctx: impl Into<StoreContextMut<'a, T>>,
168    ) -> (&'a mut [u8], &'a mut T) {
169        let (memory, store) = ctx.into().store.resolve_memory_and_state_mut(self);
170        (memory.data_mut(), store)
171    }
172
173    /// Returns the base pointer, in the host’s address space, that the [`Memory`] is located at.
174    ///
175    /// # Panics
176    ///
177    /// Panics if `ctx` does not own this [`Memory`].
178    pub fn data_ptr(&self, ctx: impl AsContext) -> *mut u8 {
179        ctx.as_context().store.inner.resolve_memory(self).data_ptr()
180    }
181
182    /// Returns the byte length of this [`Memory`].
183    ///
184    /// The returned value will be a multiple of the wasm page size, 64k.
185    ///
186    /// # Panics
187    ///
188    /// Panics if `ctx` does not own this [`Memory`].
189    pub fn data_size(&self, ctx: impl AsContext) -> usize {
190        ctx.as_context()
191            .store
192            .inner
193            .resolve_memory(self)
194            .data_size()
195    }
196
197    /// Reads `n` bytes from `memory[offset..offset+n]` into `buffer`
198    /// where `n` is the length of `buffer`.
199    ///
200    /// # Errors
201    ///
202    /// If this operation accesses out of bounds linear memory.
203    ///
204    /// # Panics
205    ///
206    /// Panics if `ctx` does not own this [`Memory`].
207    pub fn read(
208        &self,
209        ctx: impl AsContext,
210        offset: usize,
211        buffer: &mut [u8],
212    ) -> Result<(), MemoryError> {
213        ctx.as_context()
214            .store
215            .inner
216            .resolve_memory(self)
217            .read(offset, buffer)
218    }
219
220    /// Writes `n` bytes to `memory[offset..offset+n]` from `buffer`
221    /// where `n` if the length of `buffer`.
222    ///
223    /// # Errors
224    ///
225    /// If this operation accesses out of bounds linear memory.
226    ///
227    /// # Panics
228    ///
229    /// Panics if `ctx` does not own this [`Memory`].
230    pub fn write(
231        &self,
232        mut ctx: impl AsContextMut,
233        offset: usize,
234        buffer: &[u8],
235    ) -> Result<(), MemoryError> {
236        ctx.as_context_mut()
237            .store
238            .inner
239            .resolve_memory_mut(self)
240            .write(offset, buffer)
241    }
242}