uptown_funk/types/
pointers.rs

1use std::{cell::Cell, marker::PhantomData, mem};
2
3use crate::{memory::Memory, Executor, FromWasm, Trap};
4
5// TODO maybe writing to memory should always return Result<(), Trap>?
6
7pub trait WasmType: Sized {
8    type Value;
9    fn copy_to(&self, mem: &mut [u8]);
10    fn len() -> usize;
11    fn value_from_memory(mem: &[u8]) -> Self::Value;
12
13    fn move_to(self, mem: &mut [u8]) {
14        self.copy_to(mem);
15    }
16}
17
18pub trait CReprWasmType: Sized {}
19
20impl WasmType for u8 {
21    type Value = u8;
22
23    fn copy_to(&self, mem: &mut [u8]) {
24        mem[..1].copy_from_slice(&self.to_le_bytes());
25    }
26
27    #[inline]
28    fn len() -> usize {
29        1
30    }
31
32    fn value_from_memory(mem: &[u8]) -> Self::Value {
33        mem[0]
34    }
35}
36
37impl CReprWasmType for u16 {}
38impl CReprWasmType for u32 {}
39impl CReprWasmType for u64 {}
40impl CReprWasmType for f64 {}
41impl CReprWasmType for f32 {}
42
43pub struct Pointer<T: WasmType> {
44    loc: usize,
45    mem: Memory,
46    _type: PhantomData<T>,
47}
48
49impl<T: WasmType> core::fmt::Debug for Pointer<T> {
50    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51        f.write_str(&self.loc.to_string())?;
52        Ok(())
53    }
54}
55
56impl<T: WasmType> WasmType for Pointer<T> {
57    type Value = T::Value;
58
59    fn copy_to(&self, mem: &mut [u8]) {
60        mem[..4].copy_from_slice(&(self.loc as u32).to_le_bytes());
61    }
62
63    #[inline]
64    fn len() -> usize {
65        4
66    }
67
68    fn value_from_memory(mem: &[u8]) -> Self::Value {
69        T::value_from_memory(mem)
70    }
71}
72
73impl<T: WasmType> Pointer<T> {
74    pub fn copy(&mut self, val: &T) {
75        val.copy_to(&mut self.mem.as_mut_slice()[(self.loc as usize)..]);
76    }
77
78    pub fn set(&mut self, val: T) {
79        val.move_to(&mut self.mem.as_mut_slice()[(self.loc as usize)..]);
80    }
81
82    pub fn value(&self) -> T::Value {
83        T::value_from_memory(&self.mem.as_mut_slice()[self.loc..])
84    }
85
86    pub fn next(self) -> Option<Self> {
87        let loc = self.loc + T::len();
88        if loc >= self.mem.as_mut_slice().len() {
89            None
90        } else {
91            Some(Self { loc, ..self })
92        }
93    }
94
95    pub fn u8_pointer(self) -> Pointer<u8> {
96        return Pointer {
97            loc: self.loc,
98            mem: self.mem,
99            _type: PhantomData::default(),
100        };
101    }
102}
103
104impl Pointer<u8> {
105    pub fn copy_slice(self, slice: &[u8]) -> Result<Option<Self>, Trap> {
106        let loc = self.loc + slice.len();
107        if loc > self.mem.as_mut_slice().len() {
108            Err(Trap::new("Tried to copy slice over memory bounds"))
109        } else {
110            self.mem.as_mut_slice()[self.loc..self.loc + slice.len()].copy_from_slice(slice);
111
112            if loc == self.mem.as_mut_slice().len() {
113                return Ok(None);
114            }
115
116            Ok(Some(Self { loc, ..self }))
117        }
118    }
119
120    pub fn mut_slice<'a>(&'a self, n: usize) -> &'a mut [u8] {
121        let slice = &mut self.mem.as_mut_slice()[self.loc..self.loc + n];
122        slice
123    }
124
125    pub fn cast<T: WasmType>(self) -> Option<Pointer<T>> {
126        if T::len() + self.loc <= self.mem.as_mut_slice().len() {
127            Some(Pointer {
128                loc: self.loc,
129                mem: self.mem,
130                _type: PhantomData::default(),
131            })
132        } else {
133            None
134        }
135    }
136
137    pub fn set_cast<T: WasmType>(self, val: T) -> Result<Option<Self>, Trap> {
138        let loc = self.loc + T::len();
139        if loc > self.mem.as_mut_slice().len() {
140            Err(Trap::new("Tried to copy slice over memory bounds"))
141        } else {
142            let mut ptr = self.cast::<T>().unwrap();
143            ptr.set(val);
144            Ok(ptr.next().map(|p| p.u8_pointer()))
145        }
146    }
147}
148
149impl<T: WasmType> FromWasm for Pointer<T> {
150    type From = u32;
151    type State = ();
152
153    fn from(
154        _state: &mut Self::State,
155        executor: &impl Executor,
156        wasm_u32: u32,
157    ) -> Result<Self, crate::Trap> {
158        Ok(Pointer {
159            loc: wasm_u32 as usize,
160            mem: executor.memory(),
161            _type: PhantomData::default(),
162        })
163    }
164}
165
166fn align_pointer(ptr: usize, align: usize) -> usize {
167    // clears bits below aligment amount (assumes power of 2) to align pointer
168    ptr & !(align - 1)
169}
170
171fn deref<T: Sized>(offset: u32, memory: &[u8], index: u32, length: u32) -> Option<&[Cell<T>]> {
172    // gets the size of the item in the array with padding added such that
173    // for any index, we will always result an aligned memory access
174    let item_size = mem::size_of::<T>() + (mem::size_of::<T>() % mem::align_of::<T>());
175    let slice_full_len = index as usize + length as usize;
176    let memory_size = memory.len();
177
178    if (offset as usize) + (item_size * slice_full_len) > memory_size
179        || offset as usize >= memory_size
180        || mem::size_of::<T>() == 0
181    {
182        return None;
183    }
184
185    unsafe {
186        let cell_ptr = align_pointer(
187            memory.as_ptr().add(offset as usize) as usize,
188            mem::align_of::<T>(),
189        ) as *const Cell<T>;
190        let cell_ptrs =
191            &std::slice::from_raw_parts(cell_ptr, slice_full_len)[index as usize..slice_full_len];
192        Some(cell_ptrs)
193    }
194}
195
196impl<T: CReprWasmType + Copy + Clone> WasmType for T {
197    type Value = T;
198
199    fn copy_to(&self, mem: &mut [u8]) {
200        self.clone().move_to(mem);
201    }
202
203    fn move_to(self, mem: &mut [u8]) {
204        // TODO what if it fails?
205        if let Some(cells) = deref::<T>(0, mem, 0, 1) {
206            cells[0].set(self);
207        }
208    }
209
210    fn len() -> usize {
211        mem::size_of::<T>()
212    }
213
214    fn value_from_memory(mem: &[u8]) -> Self::Value {
215        // TODO unwrap
216        let cells = deref::<T>(0, mem, 0, 1).unwrap();
217        cells[0].get()
218    }
219}
220
221//impl<S, T : CReprWasmType> Pointer<S, T> {
222//    pub fn set_c_repr_type(&self, val: T) {
223//    }
224//}