Skip to main content

tinywasm/store/memory/
vec.rs

1use alloc::vec::Vec;
2use core::hint::cold_path;
3
4use super::{LinearMemory, checked_effective_addr};
5
6/// A contiguous `Vec<u8>`-backed linear memory.
7///
8/// This is the simplest backend and typically gives the best read and write throughput because
9/// the whole memory lives in one contiguous allocation.
10///
11/// The tradeoff is growth cost: large grows may need to reallocate and copy the full buffer,
12/// which can get expensive for large memories.
13#[cfg_attr(feature = "debug", derive(Debug))]
14pub struct VecMemory {
15    data: Vec<u8>,
16}
17
18impl VecMemory {
19    /// Tries to create a new memory with `len` zero-initialized bytes.
20    ///
21    /// Prefer this backend when contiguous access is more important than grow performance.
22    pub fn try_new(len: usize) -> Result<Self, crate::Trap> {
23        let mut data = Vec::new();
24        match data.try_reserve_exact(len) {
25            Ok(()) => {}
26            Err(_) => {
27                cold_path();
28                return Err(crate::Trap::OutOfMemory);
29            }
30        }
31        data.resize(len, 0);
32        Ok(Self { data })
33    }
34}
35
36impl LinearMemory for VecMemory {
37    #[inline(always)]
38    fn len(&self) -> usize {
39        self.data.len()
40    }
41
42    #[inline(always)]
43    fn grow_to(&mut self, new_len: usize) -> Result<(), crate::Trap> {
44        if new_len < self.data.len() {
45            return Err(crate::Trap::MemoryOutOfBounds { offset: new_len, len: 0, max: self.data.len() });
46        }
47        match self.data.try_reserve_exact(new_len.saturating_sub(self.data.len())) {
48            Ok(()) => {}
49            Err(_) => {
50                cold_path();
51                return Err(crate::Trap::OutOfMemory);
52            }
53        }
54        self.data.resize(new_len, 0);
55        Ok(())
56    }
57
58    #[inline(always)]
59    fn read(&self, addr: usize, dst: &mut [u8]) -> usize {
60        if addr >= self.data.len() {
61            return 0;
62        }
63        let read_len = dst.len().min(self.data.len() - addr);
64        dst[..read_len].copy_from_slice(&self.data[addr..addr + read_len]);
65        read_len
66    }
67
68    #[inline(always)]
69    fn read_exact(&self, addr: usize, dst: &mut [u8]) -> Option<()> {
70        dst.copy_from_slice(self.data.get(addr..addr.checked_add(dst.len())?)?);
71        Some(())
72    }
73
74    #[inline(always)]
75    fn read_vec(&self, addr: usize, len: usize) -> Option<Vec<u8>> {
76        Some(self.data.get(addr..addr.checked_add(len)?)?.to_vec())
77    }
78
79    #[inline(always)]
80    fn write(&mut self, addr: usize, src: &[u8]) -> usize {
81        if addr >= self.data.len() {
82            return 0;
83        }
84
85        let write_len = src.len().min(self.data.len() - addr);
86        self.data[addr..addr + write_len].copy_from_slice(&src[..write_len]);
87        write_len
88    }
89
90    #[inline(always)]
91    fn write_all(&mut self, addr: usize, src: &[u8]) -> Option<()> {
92        let dst = self.data.get_mut(addr..addr.checked_add(src.len())?)?;
93        dst.copy_from_slice(src);
94        Some(())
95    }
96
97    #[inline(always)]
98    fn fill(&mut self, addr: usize, len: usize, val: u8) -> Option<()> {
99        self.data.get_mut(addr..addr.checked_add(len)?)?.fill(val);
100        Some(())
101    }
102
103    #[inline(always)]
104    fn copy_within(&mut self, dst: usize, src: usize, len: usize) -> Option<()> {
105        let src_end = src.checked_add(len)?;
106        let dst_end = dst.checked_add(len)?;
107        if src_end > self.data.len() || dst_end > self.data.len() {
108            return None;
109        }
110
111        self.data.copy_within(src..src_end, dst);
112        Some(())
113    }
114
115    #[inline(always)]
116    fn read_8(&self, base: u64, offset: u64) -> core::result::Result<u8, crate::Trap> {
117        Ok(self.data[checked_effective_addr::<1>(self.data.len(), base, offset)?])
118    }
119
120    #[inline(always)]
121    fn read_16(&self, base: u64, offset: u64) -> core::result::Result<[u8; 2], crate::Trap> {
122        let addr = checked_effective_addr::<2>(self.data.len(), base, offset)?;
123        match self.data[addr..addr + 2].try_into() {
124            Ok(bytes) => Ok(bytes),
125            Err(_) => {
126                cold_path();
127                unreachable!();
128            }
129        }
130    }
131
132    #[inline(always)]
133    fn read_32(&self, base: u64, offset: u64) -> core::result::Result<[u8; 4], crate::Trap> {
134        let addr = checked_effective_addr::<4>(self.data.len(), base, offset)?;
135        match self.data[addr..addr + 4].try_into() {
136            Ok(bytes) => Ok(bytes),
137            Err(_) => {
138                cold_path();
139                unreachable!();
140            }
141        }
142    }
143
144    #[inline(always)]
145    fn read_64(&self, base: u64, offset: u64) -> core::result::Result<[u8; 8], crate::Trap> {
146        let addr = checked_effective_addr::<8>(self.data.len(), base, offset)?;
147        match self.data[addr..addr + 8].try_into() {
148            Ok(bytes) => Ok(bytes),
149            Err(_) => {
150                cold_path();
151                unreachable!();
152            }
153        }
154    }
155
156    #[inline(always)]
157    fn read_128(&self, base: u64, offset: u64) -> core::result::Result<[u8; 16], crate::Trap> {
158        let addr = checked_effective_addr::<16>(self.data.len(), base, offset)?;
159        match self.data[addr..addr + 16].try_into() {
160            Ok(bytes) => Ok(bytes),
161            Err(_) => {
162                cold_path();
163                unreachable!();
164            }
165        }
166    }
167
168    #[inline(always)]
169    fn write_8(&mut self, base: u64, offset: u64, byte: u8) -> core::result::Result<(), crate::Trap> {
170        let addr = checked_effective_addr::<1>(self.data.len(), base, offset)?;
171        self.data[addr] = byte;
172        Ok(())
173    }
174
175    #[inline(always)]
176    fn write_16(&mut self, base: u64, offset: u64, bytes: [u8; 2]) -> core::result::Result<(), crate::Trap> {
177        let addr = checked_effective_addr::<2>(self.data.len(), base, offset)?;
178        self.data[addr..addr + 2].copy_from_slice(&bytes);
179        Ok(())
180    }
181
182    #[inline(always)]
183    fn write_32(&mut self, base: u64, offset: u64, bytes: [u8; 4]) -> core::result::Result<(), crate::Trap> {
184        let addr = checked_effective_addr::<4>(self.data.len(), base, offset)?;
185        self.data[addr..addr + 4].copy_from_slice(&bytes);
186        Ok(())
187    }
188
189    #[inline(always)]
190    fn write_64(&mut self, base: u64, offset: u64, bytes: [u8; 8]) -> core::result::Result<(), crate::Trap> {
191        let addr = checked_effective_addr::<8>(self.data.len(), base, offset)?;
192        self.data[addr..addr + 8].copy_from_slice(&bytes);
193        Ok(())
194    }
195
196    #[inline(always)]
197    fn write_128(&mut self, base: u64, offset: u64, bytes: [u8; 16]) -> core::result::Result<(), crate::Trap> {
198        let addr = checked_effective_addr::<16>(self.data.len(), base, offset)?;
199        self.data[addr..addr + 16].copy_from_slice(&bytes);
200        Ok(())
201    }
202}