1use alloc::{boxed::Box, format, sync::Arc};
2use alloc::{vec, vec::Vec};
3use core::cmp::min;
4use core::hint::cold_path;
5use core::ops::{Deref, DerefMut};
6
7use tinywasm_types::MemoryType;
8
9use crate::interpreter::Value128;
10use crate::{Error, Result};
11
12mod instance;
13mod lazy;
14
15mod paged;
16#[path = "vec.rs"]
17mod vec_memory;
18
19pub(crate) use instance::MemoryInstance;
20pub use {lazy::LazyLinearMemory, paged::PagedMemory, vec_memory::VecMemory};
21
22pub trait LinearMemory {
28 fn len(&self) -> usize;
30
31 fn is_empty(&self) -> bool {
33 self.len() == 0
34 }
35
36 fn grow_to(&mut self, new_len: usize) -> core::result::Result<(), crate::Trap>;
41
42 fn read(&self, addr: usize, dst: &mut [u8]) -> usize;
47
48 fn write(&mut self, addr: usize, src: &[u8]) -> usize;
53
54 fn write_all(&mut self, addr: usize, src: &[u8]) -> Option<()> {
56 let end = addr.checked_add(src.len())?;
57 if end > self.len() {
58 return None;
59 }
60
61 let mut offset = 0;
62 while offset < src.len() {
63 let written = self.write(addr + offset, &src[offset..]);
64 if written == 0 {
65 return None;
66 }
67 offset += written;
68 }
69
70 Some(())
71 }
72
73 fn fill(&mut self, addr: usize, len: usize, val: u8) -> Option<()> {
75 let end = addr.checked_add(len)?;
76 if end > self.len() {
77 return None;
78 }
79
80 let mut offset = 0;
81 while offset < len {
82 let chunk_len = min(len - offset, 1024);
83 let chunk = vec![val; chunk_len];
84 self.write_all(addr + offset, &chunk)?;
85 offset += chunk_len;
86 }
87
88 Some(())
89 }
90
91 fn copy_within(&mut self, dst: usize, src: usize, len: usize) -> Option<()> {
93 let src_end = src.checked_add(len)?;
94 let dst_end = dst.checked_add(len)?;
95 if src_end > self.len() || dst_end > self.len() {
96 return None;
97 }
98
99 if len == 0 || dst == src {
100 return Some(());
101 }
102
103 if dst < src || dst >= src_end {
105 let mut offset = 0;
106 while offset < len {
107 let chunk_len = min(len - offset, 1024);
108 let mut chunk = vec![0; chunk_len];
109 self.read_exact(src + offset, &mut chunk)?;
110 self.write_all(dst + offset, &chunk)?;
111 offset += chunk_len;
112 }
113 } else {
114 let mut offset = len;
116 while offset > 0 {
117 let chunk_len = min(offset, 1024);
118 offset -= chunk_len;
119 let mut chunk = vec![0; chunk_len];
120 self.read_exact(src + offset, &mut chunk)?;
121 self.write_all(dst + offset, &chunk)?;
122 }
123 }
124
125 Some(())
126 }
127
128 fn read_exact(&self, addr: usize, dst: &mut [u8]) -> Option<()> {
130 let end = addr.checked_add(dst.len())?;
131 if end > self.len() {
132 return None;
133 }
134
135 let mut offset = 0;
136 while offset < dst.len() {
137 let read = self.read(addr + offset, &mut dst[offset..]);
138 if read == 0 {
139 return None;
140 }
141 offset += read;
142 }
143
144 Some(())
145 }
146
147 fn read_vec(&self, addr: usize, len: usize) -> Option<Vec<u8>> {
149 let end = addr.checked_add(len)?;
150 if end > self.len() {
151 return None;
152 }
153
154 let mut data = vec![0; len];
155 self.read_exact(addr, &mut data)?;
156 Some(data)
157 }
158
159 fn read_8(&self, base: u64, offset: u64) -> core::result::Result<u8, crate::Trap> {
161 let addr = checked_effective_addr::<1>(self.len(), base, offset)?;
162 let mut bytes = [0; 1];
163 self.read_exact(addr, &mut bytes).ok_or_else(|| {
164 cold_path();
165 memory_oob(addr, 1, self.len())
166 })?;
167 Ok(bytes[0])
168 }
169
170 fn read_16(&self, base: u64, offset: u64) -> core::result::Result<[u8; 2], crate::Trap> {
172 let addr = checked_effective_addr::<2>(self.len(), base, offset)?;
173 let mut bytes = [0; 2];
174 self.read_exact(addr, &mut bytes).ok_or_else(|| {
175 cold_path();
176 memory_oob(addr, 2, self.len())
177 })?;
178 Ok(bytes)
179 }
180
181 fn read_32(&self, base: u64, offset: u64) -> core::result::Result<[u8; 4], crate::Trap> {
183 let addr = checked_effective_addr::<4>(self.len(), base, offset)?;
184 let mut bytes = [0; 4];
185 self.read_exact(addr, &mut bytes).ok_or_else(|| {
186 cold_path();
187 memory_oob(addr, 4, self.len())
188 })?;
189 Ok(bytes)
190 }
191
192 fn read_64(&self, base: u64, offset: u64) -> core::result::Result<[u8; 8], crate::Trap> {
194 let addr = checked_effective_addr::<8>(self.len(), base, offset)?;
195 let mut bytes = [0; 8];
196 self.read_exact(addr, &mut bytes).ok_or_else(|| {
197 cold_path();
198 memory_oob(addr, 8, self.len())
199 })?;
200 Ok(bytes)
201 }
202
203 fn read_128(&self, base: u64, offset: u64) -> core::result::Result<[u8; 16], crate::Trap> {
205 let addr = checked_effective_addr::<16>(self.len(), base, offset)?;
206 let mut bytes = [0; 16];
207 self.read_exact(addr, &mut bytes).ok_or_else(|| {
208 cold_path();
209 memory_oob(addr, 16, self.len())
210 })?;
211 Ok(bytes)
212 }
213
214 fn write_8(&mut self, base: u64, offset: u64, byte: u8) -> core::result::Result<(), crate::Trap> {
216 let addr = checked_effective_addr::<1>(self.len(), base, offset)?;
217 self.write(addr, &[byte]);
218 Ok(())
219 }
220
221 fn write_16(&mut self, base: u64, offset: u64, bytes: [u8; 2]) -> core::result::Result<(), crate::Trap> {
223 let addr = checked_effective_addr::<2>(self.len(), base, offset)?;
224 self.write_all(addr, &bytes).ok_or_else(|| {
225 cold_path();
226 memory_oob(addr, 2, self.len())
227 })
228 }
229
230 fn write_32(&mut self, base: u64, offset: u64, bytes: [u8; 4]) -> core::result::Result<(), crate::Trap> {
232 let addr = checked_effective_addr::<4>(self.len(), base, offset)?;
233 self.write_all(addr, &bytes).ok_or_else(|| {
234 cold_path();
235 memory_oob(addr, 4, self.len())
236 })
237 }
238
239 fn write_64(&mut self, base: u64, offset: u64, bytes: [u8; 8]) -> core::result::Result<(), crate::Trap> {
241 let addr = checked_effective_addr::<8>(self.len(), base, offset)?;
242 self.write_all(addr, &bytes).ok_or_else(|| {
243 cold_path();
244 memory_oob(addr, 8, self.len())
245 })
246 }
247
248 fn write_128(&mut self, base: u64, offset: u64, bytes: [u8; 16]) -> core::result::Result<(), crate::Trap> {
250 let addr = checked_effective_addr::<16>(self.len(), base, offset)?;
251 self.write_all(addr, &bytes).ok_or_else(|| {
252 cold_path();
253 memory_oob(addr, 16, self.len())
254 })
255 }
256}
257
258type MemoryFactory = dyn Fn(MemoryType) -> Result<Box<dyn LinearMemory>> + Send + Sync;
259
260#[derive(Clone, Default)]
262pub struct MemoryBackend {
263 kind: MemoryBackendKind,
264}
265
266#[derive(Clone, Default)]
267enum MemoryBackendKind {
268 #[default]
269 Vec,
270 Paged {
271 chunk_size: usize,
272 },
273 Custom(Arc<MemoryFactory>),
274}
275
276impl MemoryBackend {
277 pub const fn vec() -> Self {
282 Self { kind: MemoryBackendKind::Vec }
283 }
284
285 pub fn paged(chunk_size: usize) -> Self {
292 assert!(chunk_size != 0, "chunk_size must be greater than zero");
293 Self { kind: MemoryBackendKind::Paged { chunk_size } }
294 }
295
296 pub fn custom<F, M>(factory: F) -> Self
298 where
299 F: Fn(MemoryType) -> Result<M> + Send + Sync + 'static,
300 M: LinearMemory + 'static,
301 {
302 Self {
303 kind: MemoryBackendKind::Custom(Arc::new(move |ty| {
304 let memory = factory(ty)?;
305 Ok(Box::new(memory) as Box<dyn LinearMemory>)
306 })),
307 }
308 }
309
310 pub(crate) fn create(&self, ty: MemoryType, initial_len: usize) -> Result<MemoryStorage> {
311 let storage = match &self.kind {
312 MemoryBackendKind::Vec => {
313 Box::new(VecMemory::try_new(initial_len).map_err(Error::Trap)?) as Box<dyn LinearMemory>
314 }
315 MemoryBackendKind::Paged { chunk_size } => {
316 Box::new(PagedMemory::try_new(initial_len, *chunk_size).map_err(Error::Trap)?) as Box<dyn LinearMemory>
317 }
318 MemoryBackendKind::Custom(factory) => factory(ty)?,
319 };
320
321 if storage.len() < initial_len {
322 return Err(Error::Other(format!(
323 "memory backend returned {} bytes for a memory that requires at least {initial_len}",
324 storage.len()
325 )));
326 }
327
328 Ok(MemoryStorage(storage))
329 }
330
331 pub(crate) fn create_lazy(&self, ty: MemoryType, initial_len: usize) -> Result<MemoryStorage> {
332 Ok(MemoryStorage(Box::new(LazyLinearMemory::new_with_initial_len(ty, initial_len, self.clone()))))
333 }
334}
335
336#[cfg(feature = "debug")]
337impl core::fmt::Debug for MemoryBackend {
338 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
339 match &self.kind {
340 MemoryBackendKind::Vec => f.debug_tuple("MemoryBackend::Vec").finish(),
341 MemoryBackendKind::Paged { chunk_size } => {
342 f.debug_struct("MemoryBackend::Paged").field("chunk_size", chunk_size).finish()
343 }
344 MemoryBackendKind::Custom(_) => f.debug_tuple("MemoryBackend::Custom").finish(),
345 }
346 }
347}
348
349pub(crate) struct MemoryStorage(Box<dyn LinearMemory>);
350
351impl Deref for MemoryStorage {
352 type Target = dyn LinearMemory;
353
354 #[inline(always)]
355 fn deref(&self) -> &Self::Target {
356 &*self.0
357 }
358}
359
360impl DerefMut for MemoryStorage {
361 #[inline(always)]
362 fn deref_mut(&mut self) -> &mut Self::Target {
363 &mut *self.0
364 }
365}
366
367#[cfg(feature = "debug")]
368impl core::fmt::Debug for MemoryStorage {
369 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
370 f.debug_tuple("MemoryStorage").field(&format!("{} bytes", self.len())).finish()
371 }
372}
373
374pub(crate) trait MemValue<const N: usize>: Copy + Default {
376 fn to_mem_bytes(self) -> [u8; N];
378
379 fn from_mem_bytes(bytes: [u8; N]) -> Self;
381
382 fn load(mem: &dyn LinearMemory, base: u64, offset: u64) -> core::result::Result<Self, crate::Trap>;
383}
384
385macro_rules! impl_mem_traits {
386 ($($ty:ty, $size:expr, $read:ident),* $(,)?) => {
387 $(
388 impl MemValue<$size> for $ty {
389 #[inline(always)]
390 fn from_mem_bytes(bytes: [u8; $size]) -> Self {
391 <$ty>::from_le_bytes(bytes)
392 }
393
394 #[inline(always)]
395 fn to_mem_bytes(self) -> [u8; $size] {
396 self.to_le_bytes()
397 }
398
399 #[inline(always)]
400 fn load(
401 mem: &dyn LinearMemory,
402 base: u64,
403 offset: u64,
404 ) -> core::result::Result<Self, crate::Trap> {
405 Ok(Self::from_mem_bytes(mem.$read(base, offset)?))
406 }
407 }
408 )*
409 };
410}
411
412impl MemValue<1> for u8 {
413 #[inline(always)]
414 fn from_mem_bytes(bytes: [u8; 1]) -> Self {
415 bytes[0]
416 }
417
418 #[inline(always)]
419 fn to_mem_bytes(self) -> [u8; 1] {
420 [self]
421 }
422
423 #[inline(always)]
424 fn load(mem: &dyn LinearMemory, base: u64, offset: u64) -> core::result::Result<Self, crate::Trap> {
425 mem.read_8(base, offset)
426 }
427}
428
429impl MemValue<1> for i8 {
430 #[inline(always)]
431 fn from_mem_bytes(bytes: [u8; 1]) -> Self {
432 i8::from_le_bytes(bytes)
433 }
434
435 #[inline(always)]
436 fn to_mem_bytes(self) -> [u8; 1] {
437 self.to_le_bytes()
438 }
439
440 #[inline(always)]
441 fn load(mem: &dyn LinearMemory, base: u64, offset: u64) -> core::result::Result<Self, crate::Trap> {
442 Ok(mem.read_8(base, offset)? as i8)
443 }
444}
445
446impl_mem_traits!(
447 u16, 2, read_16, i16, 2, read_16, u32, 4, read_32, i32, 4, read_32, f32, 4, read_32, u64, 8, read_64, i64, 8,
448 read_64, f64, 8, read_64, Value128, 16, read_128
449);
450
451fn memory_oob(offset: usize, len: usize, max: usize) -> crate::Trap {
452 crate::Trap::MemoryOutOfBounds { offset, len, max }
453}
454
455fn checked_effective_addr<const LEN: usize>(
456 max: usize,
457 base: u64,
458 offset: u64,
459) -> core::result::Result<usize, crate::Trap> {
460 let Some(max_addr) = max.checked_sub(LEN).map(|max_addr| max_addr as u64) else {
461 cold_path();
462 return Err(memory_oob(usize::try_from(base).unwrap_or(usize::MAX), LEN, max));
463 };
464
465 let addr = base.wrapping_add(offset);
466 if addr < base || addr > max_addr {
467 cold_path();
468 return Err(memory_oob(usize::try_from(addr).unwrap_or(usize::MAX), LEN, max));
469 }
470
471 Ok(addr as usize)
472}
473
474#[cfg(test)]
475mod tests {
476 use super::*;
477 use tinywasm_types::MemoryArch;
478
479 fn create_test_memory(kind: MemoryType, backend: MemoryBackend) -> MemoryInstance {
480 MemoryInstance::new(kind, &backend).unwrap()
481 }
482
483 fn test_backends() -> [MemoryBackend; 2] {
484 [MemoryBackend::vec(), MemoryBackend::paged(4)]
485 }
486
487 #[test]
488 fn memory_copy_from_slice_and_read_vec_work() {
489 for backend in test_backends() {
490 let kind = MemoryType::new(MemoryArch::I32, 1, Some(2), None);
491 let mut memory = create_test_memory(kind, backend);
492 let data = [1, 2, 3, 4];
493 assert!(memory.inner.write_all(0, &data).is_some());
494 assert_eq!(memory.inner.read_vec(0, data.len()).unwrap(), data);
495 }
496 }
497
498 #[test]
499 fn memory_read_returns_partial_count() {
500 for backend in test_backends() {
501 let kind = MemoryType::new(MemoryArch::I32, 1, Some(1), Some(4));
502 let memory = create_test_memory(kind, backend);
503 let mut dst = [9; 8];
504 assert_eq!(memory.inner.read(2, &mut dst), 2);
505 assert_eq!(&dst[..2], &[0, 0]);
506 assert_eq!(&dst[2..], &[9; 6]);
507 }
508 }
509
510 #[test]
511 fn memory_copy_from_slice_out_of_bounds_fails() {
512 for backend in test_backends() {
513 let kind = MemoryType::new(MemoryArch::I32, 1, Some(2), None);
514 let mut memory = create_test_memory(kind, backend);
515 let data = [1, 2, 3, 4];
516 let len = memory.inner.len();
517 assert!(memory.inner.write_all(len, &data).is_none());
518 }
519 }
520
521 #[test]
522 fn memory_fill_works() {
523 for backend in test_backends() {
524 let kind = MemoryType::new(MemoryArch::I32, 1, Some(2), None);
525 let mut memory = create_test_memory(kind, backend);
526 assert!(memory.inner.fill(0, 10, 42).is_some());
527 assert_eq!(memory.inner.read_vec(0, 10).unwrap(), vec![42; 10]);
528 }
529 }
530
531 #[test]
532 fn memory_fill_out_of_bounds_fails() {
533 for backend in test_backends() {
534 let kind = MemoryType::new(MemoryArch::I32, 1, Some(2), None);
535 let mut memory = create_test_memory(kind, backend);
536 let len = memory.inner.len();
537 assert!(memory.inner.fill(len, 10, 42).is_none());
538 }
539 }
540
541 #[test]
542 fn memory_copy_within_works() {
543 for backend in test_backends() {
544 let kind = MemoryType::new(MemoryArch::I32, 1, Some(2), None);
545 let mut memory = create_test_memory(kind, backend);
546 memory.inner.fill(0, 10, 1).unwrap();
547 assert!(memory.copy_within(10, 0, 10).is_ok());
548 assert_eq!(memory.inner.read_vec(10, 10).unwrap(), vec![1; 10]);
549 }
550 }
551
552 #[test]
553 fn memory_copy_within_out_of_bounds_fails() {
554 for backend in test_backends() {
555 let kind = MemoryType::new(MemoryArch::I32, 1, Some(2), None);
556 let mut memory = create_test_memory(kind, backend);
557 assert!(memory.copy_within(memory.inner.len(), 0, 10).is_err());
558 }
559 }
560
561 #[test]
562 fn memory_grow_works() {
563 for backend in test_backends() {
564 let kind = MemoryType::new(MemoryArch::I32, 1, Some(2), None);
565 let mut memory = create_test_memory(kind, backend);
566 let original_pages = memory.page_count;
567 assert_eq!(memory.grow(1, false).unwrap(), Some(original_pages as i64));
568 assert_eq!(memory.page_count, original_pages + 1);
569 }
570 }
571
572 #[test]
573 fn memory_grow_out_of_bounds_fails() {
574 for backend in test_backends() {
575 let kind = MemoryType::new(MemoryArch::I32, 1, Some(2), None);
576 let mut memory = create_test_memory(kind, backend);
577 assert_eq!(memory.grow(memory.kind.max_size() as i64 + 1, false).unwrap(), None);
578 }
579 }
580
581 #[test]
582 fn memory_grow_respects_max_pages() {
583 for backend in test_backends() {
584 let kind = MemoryType::new(MemoryArch::I32, 1, Some(2), None);
585 let mut memory = create_test_memory(kind, backend);
586 assert_eq!(memory.grow(1, false).unwrap(), Some(1));
587 assert_eq!(memory.grow(1, false).unwrap(), None);
588 }
589 }
590
591 #[test]
592 fn memory_grow_negative_delta_fails() {
593 for backend in test_backends() {
594 let kind = MemoryType::new(MemoryArch::I32, 1, Some(2), None);
595 let mut memory = create_test_memory(kind, backend);
596 let original_pages = memory.page_count;
597 assert_eq!(memory.grow(-1, false).unwrap(), None);
598 assert_eq!(memory.page_count, original_pages);
599 }
600 }
601
602 #[test]
603 fn memory_custom_page_size_out_of_bounds_fails() {
604 for backend in test_backends() {
605 let kind = MemoryType::new(MemoryArch::I32, 1, Some(2), Some(1));
606 let mut memory = create_test_memory(kind, backend);
607 let data = [1, 2];
608 assert!(memory.inner.write_all(0, &data).is_none());
609 }
610 }
611
612 #[test]
613 fn memory_custom_page_size_grow_works() {
614 for backend in test_backends() {
615 let kind = MemoryType::new(MemoryArch::I32, 1, Some(2), Some(1));
616 let mut memory = create_test_memory(kind, backend);
617 assert_eq!(memory.grow(1, false).unwrap(), Some(1));
618 let data = [1, 2];
619 assert!(memory.inner.write_all(0, &data).is_some());
620 assert_eq!(memory.inner.read_vec(0, data.len()).unwrap(), data);
621 }
622 }
623}