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}