makepad_stitch/
mem.rs

1use {
2    crate::{
3        data::{Data, DataEntity},
4        decode::{Decode, DecodeError, Decoder},
5        limits::Limits,
6        stack::Stack,
7        store::{Handle, HandlePair, Store, StoreId, UnguardedHandle},
8        trap::Trap,
9    },
10    std::{error::Error, fmt},
11};
12
13/// A Wasm memory.
14#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
15#[repr(transparent)]
16pub struct Mem(pub(crate) Handle<MemEntity>);
17
18impl Mem {
19    /// Creates a new [`Mem`] with the given [`MemType`].
20    ///
21    /// # Panics
22    ///
23    /// If the given [`MemType`] is invalid.
24    pub fn new(store: &mut Store, type_: MemType) -> Self {
25        assert!(type_.is_valid(), "invalid memory type");
26        Self(store.insert_mem(MemEntity::new(type_)))
27    }
28
29    /// Returns the [`MemType`] of this [`Mem`].
30    pub fn type_(self, store: &Store) -> MemType {
31        MemType {
32            limits: self.0.as_ref(store).limits(),
33        }
34    }
35
36    /// Returns the bytes of this [`Mem`] as a slice.
37    pub fn bytes(self, store: &Store) -> &[u8] {
38        self.0.as_ref(store).bytes()
39    }
40
41    /// Returns the bytes of this [`Mem`] as a mutable slice.
42    pub fn bytes_mut(self, store: &mut Store) -> &mut [u8] {
43        self.0.as_mut(store).bytes_mut()
44    }
45
46    /// Returns the size of this [`Mem`] in number of pages.
47    pub fn size(&self, store: &Store) -> u32 {
48        self.0.as_ref(store).size()
49    }
50
51    /// Grows this [`Mem`] by the given number of pages.
52    ///
53    /// Returns the previous size of this [`Mem`] in number of pages.
54    ///
55    /// # Errors
56    ///
57    /// If this [`Mem`] failed to grow.
58    pub fn grow(self, store: &mut Store, count: u32) -> Result<u32, MemError> {
59        self.0.as_mut(store).grow(count)
60    }
61
62    pub(crate) fn init(
63        self,
64        store: &mut Store,
65        dst_offset: u32,
66        src_data: Data,
67        src_offset: u32,
68        count: u32,
69    ) -> Result<(), Trap> {
70        let (dst_table, src_data) = HandlePair(self.0, src_data.0).as_mut_pair(store);
71        dst_table.init(dst_offset, src_data, src_offset, count)
72    }
73
74    /// Converts the given [`UnguardedMem`] to a [`Mem`].
75    ///
76    /// # Safety
77    ///
78    /// The given [`UnguardedMem`] must be owned by the [`Store`] with the given [`StoreId`].
79    pub(crate) unsafe fn from_unguarded(memory: UnguardedMem, store_id: StoreId) -> Self {
80        Self(Handle::from_unguarded(memory, store_id))
81    }
82
83    /// Converts this [`Mem`] to an [`UnguardedMem`].
84    ///
85    /// # Panics
86    ///
87    /// This [`Mem`] is not owned by the [`Store`] with the given [`StoreId`].
88    pub(crate) fn to_unguarded(self, store_id: StoreId) -> UnguardedMem {
89        self.0.to_unguarded(store_id)
90    }
91}
92
93/// An unguarded version of [`Mem`].
94pub(crate) type UnguardedMem = UnguardedHandle<MemEntity>;
95
96/// The type of a [`Mem`].
97#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
98pub struct MemType {
99    /// The [`Limits`] of this [`Mem`].
100    pub limits: Limits,
101}
102
103impl MemType {
104    /// Returns `true` if this [`MemType`] is valid.
105    ///
106    /// A [`MemType`] is valid if its [`Limits`] are valid within range 65_536.
107    pub fn is_valid(&self) -> bool {
108        self.limits.is_valid(65_536)
109    }
110
111    /// Returns `true` if this [`MemType`] is a subtype of the given [`MemType`].
112    ///
113    /// A [`MemType`] is a subtype of another [`MemType`] if its [`Limits`] are a sublimit of the
114    /// other's.
115    pub fn is_subtype_of(self, other: Self) -> bool {
116        self.limits.is_sublimit_of(other.limits)
117    }
118}
119
120impl Decode for MemType {
121    fn decode(decoder: &mut Decoder<'_>) -> Result<Self, DecodeError> {
122        Ok(Self {
123            limits: Limits::decode(decoder)?,
124        })
125    }
126}
127
128/// An error that can occur when operating on a [`Mem`].
129#[derive(Clone, Copy, Debug)]
130#[non_exhaustive]
131pub enum MemError {
132    FailedToGrow,
133}
134
135impl fmt::Display for MemError {
136    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137        match self {
138            Self::FailedToGrow => write!(f, "memory failed to grow"),
139        }
140    }
141}
142
143impl Error for MemError {}
144
145/// The representation of a [`Mem`] in a [`Store`].
146#[derive(Debug)]
147pub(crate) struct MemEntity {
148    max: Option<u32>,
149    bytes: Vec<u8>,
150}
151
152impl MemEntity {
153    /// Creates a new [`MemEntity`] with the given [`MemType`].
154    fn new(type_: MemType) -> Self {
155        Self {
156            max: type_.limits.max,
157            bytes: vec![0; (type_.limits.min as usize).checked_mul(PAGE_SIZE).unwrap()],
158        }
159    }
160
161    /// Returns the [`Limits`] of this [`MemEntity`].
162    fn limits(&self) -> Limits {
163        Limits {
164            min: self.size(),
165            max: self.max,
166        }
167    }
168
169    /// Returns the bytes of this [`MemEntity`] as a slice.
170    pub(crate) fn bytes(&self) -> &[u8] {
171        &self.bytes
172    }
173
174    /// Returns the bytes of this [`MemEntity`] as a mutable slice.
175    pub(crate) fn bytes_mut(&mut self) -> &mut [u8] {
176        &mut self.bytes
177    }
178
179    /// Returns the size of this [`MemEntity`] in number of pages.
180    pub(crate) fn size(&self) -> u32 {
181        u32::try_from(self.bytes.len() / PAGE_SIZE).unwrap()
182    }
183
184    /// Grows this [`MemEntity`] by the given number of pages.
185    ///
186    /// Returns the previous size of this [`MemEntity`] in number of pages.
187    ///
188    /// # Errors
189    ///
190    /// If this [`MemEntity`] failed to grow.
191    pub(crate) fn grow(&mut self, count: u32) -> Result<u32, MemError> {
192        let mut stack = Stack::lock();
193        unsafe { self.grow_with_stack(count, &mut stack) }
194    }
195
196    pub(crate) unsafe fn grow_with_stack(
197        &mut self,
198        count: u32,
199        stack: &mut Stack,
200    ) -> Result<u32, MemError> {
201        if count > self.max.unwrap_or(65_536) - self.size() {
202            return Err(MemError::FailedToGrow);
203        }
204        let old_data = self.bytes.as_mut_ptr();
205        let old_size = self.size();
206        let new_size = self.size() + count;
207        self.bytes
208            .resize((new_size as usize).checked_mul(PAGE_SIZE).unwrap(), 0);
209        let new_data = self.bytes.as_mut_ptr();
210
211        // Each call frame on the stack stores the value of the `md` and `ms` register. Growing
212        // this [`Memory`] invalidates all call frames for which `md` and `ms` store a pointer to
213        // the old data and size of this [`Memory`]. To fix this, we need to iterate over the call
214        // frames on the stack, and update the value of the `md` and `ms` register to store
215        // a pointer to the new data and size of this [`Memory`] instead.
216        let mut ptr = stack.ptr();
217        while ptr != stack.base_ptr() {
218            ptr = *ptr.offset(-3).cast();
219            if *ptr.offset(-2).cast::<*mut u8>() == old_data {
220                *ptr.offset(-2).cast() = new_data;
221                *ptr.offset(-1).cast() = new_size;
222            }
223        }
224
225        Ok(old_size)
226    }
227
228    pub(crate) fn fill(&mut self, idx: u32, val: u8, count: u32) -> Result<(), Trap> {
229        let idx = idx as usize;
230        let count = count as usize;
231        let bytes = self
232            .bytes
233            .get_mut(idx..)
234            .and_then(|bytes| bytes.get_mut(..count))
235            .ok_or(Trap::MemAccessOutOfBounds)?;
236        bytes.fill(val);
237        Ok(())
238    }
239
240    pub(crate) fn copy_within(
241        &mut self,
242        dst_idx: u32,
243        src_idx: u32,
244        count: u32,
245    ) -> Result<(), Trap> {
246        let dst_idx = dst_idx as usize;
247        let src_idx = src_idx as usize;
248        let count = count as usize;
249        if count > self.bytes.len()
250            || dst_idx > self.bytes.len() - count
251            || src_idx > self.bytes.len() - count
252        {
253            return Err(Trap::MemAccessOutOfBounds);
254        }
255        self.bytes.copy_within(src_idx..src_idx + count, dst_idx);
256        Ok(())
257    }
258
259    pub(crate) fn init(
260        &mut self,
261        dst_idx: u32,
262        src_data: &DataEntity,
263        src_idx: u32,
264        count: u32,
265    ) -> Result<(), Trap> {
266        let dst_idx = dst_idx as usize;
267        let src_idx = src_idx as usize;
268        let count = count as usize;
269        let dst_bytes = self
270            .bytes
271            .get_mut(dst_idx..)
272            .and_then(|bytes| bytes.get_mut(..count))
273            .ok_or(Trap::MemAccessOutOfBounds)?;
274        let src_bytes = src_data
275            .bytes()
276            .get(src_idx..)
277            .and_then(|bytes| bytes.get(..count))
278            .ok_or(Trap::MemAccessOutOfBounds)?;
279        dst_bytes.copy_from_slice(src_bytes);
280        Ok(())
281    }
282}
283
284const PAGE_SIZE: usize = 65_536;