1extern crate radix_wasmi_arena as wasmi_arena;
2
3mod byte_buffer;
4
5use self::byte_buffer::ByteBuffer;
6use super::{AsContext, AsContextMut, StoreContext, StoreContextMut, Stored};
7use core::{fmt, fmt::Display};
8use wasmi_arena::ArenaIndex;
9use wasmi_core::Pages;
10
11#[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#[derive(Debug)]
30#[non_exhaustive]
31pub enum MemoryError {
32 OutOfBoundsAllocation,
34 OutOfBoundsGrowth,
36 OutOfBoundsAccess,
38 InvalidMemoryType,
40 UnsatisfyingMemoryType {
42 unsatisfying: MemoryType,
44 required: MemoryType,
46 },
47}
48
49impl Display for MemoryError {
50 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
51 match self {
52 Self::OutOfBoundsAllocation => {
53 write!(f, "tried to allocate too much virtual memory")
54 }
55 Self::OutOfBoundsGrowth => {
56 write!(f, "tried to grow virtual memory out of bounds")
57 }
58 Self::OutOfBoundsAccess => {
59 write!(f, "tried to access virtual memory out of bounds")
60 }
61 Self::InvalidMemoryType => {
62 write!(f, "tried to create an invalid virtual memory type")
63 }
64 Self::UnsatisfyingMemoryType {
65 unsatisfying,
66 required,
67 } => {
68 write!(
69 f,
70 "memory type {unsatisfying:?} does not \
71 satisfy requirements of {required:?}",
72 )
73 }
74 }
75 }
76}
77
78#[derive(Debug, Copy, Clone, PartialEq, Eq)]
80pub struct MemoryType {
81 initial_pages: Pages,
82 maximum_pages: Option<Pages>,
83}
84
85impl MemoryType {
86 pub fn new(initial: u32, maximum: Option<u32>) -> Result<Self, MemoryError> {
93 let initial_pages = Pages::new(initial).ok_or(MemoryError::InvalidMemoryType)?;
94 let maximum_pages = match maximum {
95 Some(maximum) => Pages::new(maximum)
96 .ok_or(MemoryError::InvalidMemoryType)?
97 .into(),
98 None => None,
99 };
100 Ok(Self {
101 initial_pages,
102 maximum_pages,
103 })
104 }
105
106 pub fn initial_pages(self) -> Pages {
108 self.initial_pages
109 }
110
111 pub fn maximum_pages(self) -> Option<Pages> {
118 self.maximum_pages
119 }
120
121 pub(crate) fn satisfies(&self, required: &MemoryType) -> Result<(), MemoryError> {
128 if required.initial_pages() > self.initial_pages() {
129 return Err(MemoryError::UnsatisfyingMemoryType {
130 unsatisfying: *self,
131 required: *required,
132 });
133 }
134 match (required.maximum_pages(), self.maximum_pages()) {
135 (None, _) => (),
136 (Some(max_required), Some(max)) if max_required >= max => (),
137 _ => {
138 return Err(MemoryError::UnsatisfyingMemoryType {
139 unsatisfying: *self,
140 required: *required,
141 });
142 }
143 }
144 Ok(())
145 }
146}
147
148#[derive(Debug, Clone)]
150pub struct MemoryEntity {
151 bytes: ByteBuffer,
152 memory_type: MemoryType,
153 current_pages: Pages,
154}
155
156impl MemoryEntity {
157 pub fn new(memory_type: MemoryType) -> Result<Self, MemoryError> {
159 let initial_pages = memory_type.initial_pages();
160 let initial_len = initial_pages
161 .to_bytes()
162 .ok_or(MemoryError::OutOfBoundsAllocation)?;
163 let memory = Self {
164 bytes: ByteBuffer::new(initial_len),
165 memory_type,
166 current_pages: initial_pages,
167 };
168 Ok(memory)
169 }
170
171 pub fn ty(&self) -> MemoryType {
173 self.memory_type
174 }
175
176 pub fn current_pages(&self) -> Pages {
178 self.current_pages
179 }
180
181 pub fn grow(&mut self, additional: Pages) -> Result<Pages, MemoryError> {
190 let current_pages = self.current_pages();
191 if additional == Pages::default() {
192 return Ok(current_pages);
194 }
195 let maximum_pages = self.ty().maximum_pages().unwrap_or_else(Pages::max);
196 let new_pages = current_pages
197 .checked_add(additional)
198 .filter(|&new_pages| new_pages <= maximum_pages)
199 .ok_or(MemoryError::OutOfBoundsGrowth)?;
200 let new_size = new_pages
201 .to_bytes()
202 .ok_or(MemoryError::OutOfBoundsAllocation)?;
203 self.bytes.grow(new_size);
206 self.current_pages = new_pages;
207 Ok(current_pages)
208 }
209
210 pub fn data(&self) -> &[u8] {
212 self.bytes.data()
213 }
214
215 pub fn data_mut(&mut self) -> &mut [u8] {
217 self.bytes.data_mut()
218 }
219
220 pub fn read(&self, offset: usize, buffer: &mut [u8]) -> Result<(), MemoryError> {
227 let len_buffer = buffer.len();
228 let slice = self
229 .data()
230 .get(offset..(offset + len_buffer))
231 .ok_or(MemoryError::OutOfBoundsAccess)?;
232 buffer.copy_from_slice(slice);
233 Ok(())
234 }
235
236 pub fn write(&mut self, offset: usize, buffer: &[u8]) -> Result<(), MemoryError> {
243 let len_buffer = buffer.len();
244 let slice = self
245 .data_mut()
246 .get_mut(offset..(offset + len_buffer))
247 .ok_or(MemoryError::OutOfBoundsAccess)?;
248 slice.copy_from_slice(buffer);
249 Ok(())
250 }
251}
252
253#[derive(Debug, Copy, Clone)]
255#[repr(transparent)]
256pub struct Memory(Stored<MemoryIdx>);
257
258impl Memory {
259 pub(super) fn from_inner(stored: Stored<MemoryIdx>) -> Self {
261 Self(stored)
262 }
263
264 pub(super) fn into_inner(self) -> Stored<MemoryIdx> {
266 self.0
267 }
268
269 pub fn new(mut ctx: impl AsContextMut, ty: MemoryType) -> Result<Self, MemoryError> {
275 let entity = MemoryEntity::new(ty)?;
276 let memory = ctx.as_context_mut().store.alloc_memory(entity);
277 Ok(memory)
278 }
279
280 pub fn ty(&self, ctx: impl AsContext) -> MemoryType {
286 ctx.as_context().store.resolve_memory(*self).ty()
287 }
288
289 pub fn current_pages(&self, ctx: impl AsContext) -> Pages {
295 ctx.as_context().store.resolve_memory(*self).current_pages()
296 }
297
298 pub fn grow(
311 &self,
312 mut ctx: impl AsContextMut,
313 additional: Pages,
314 ) -> Result<Pages, MemoryError> {
315 ctx.as_context_mut()
316 .store
317 .resolve_memory_mut(*self)
318 .grow(additional)
319 }
320
321 pub fn data<'a, T: 'a>(&self, ctx: impl Into<StoreContext<'a, T>>) -> &'a [u8] {
327 ctx.into().store.resolve_memory(*self).data()
328 }
329
330 pub fn data_mut<'a, T: 'a>(&self, ctx: impl Into<StoreContextMut<'a, T>>) -> &'a mut [u8] {
336 ctx.into().store.resolve_memory_mut(*self).data_mut()
337 }
338
339 pub fn data_and_store_mut<'a, T: 'a>(
346 &self,
347 ctx: impl Into<StoreContextMut<'a, T>>,
348 ) -> (&'a mut [u8], &'a mut T) {
349 let (memory, store) = ctx.into().store.resolve_memory_and_state_mut(*self);
350 (memory.data_mut(), store)
351 }
352
353 pub fn read(
364 &self,
365 ctx: impl AsContext,
366 offset: usize,
367 buffer: &mut [u8],
368 ) -> Result<(), MemoryError> {
369 ctx.as_context()
370 .store
371 .resolve_memory(*self)
372 .read(offset, buffer)
373 }
374
375 pub fn write(
386 &self,
387 mut ctx: impl AsContextMut,
388 offset: usize,
389 buffer: &[u8],
390 ) -> Result<(), MemoryError> {
391 ctx.as_context_mut()
392 .store
393 .resolve_memory_mut(*self)
394 .write(offset, buffer)
395 }
396}