/build/source/src/execution/runtime_structure/addresses.rs
Line | Count | Source |
1 | | //! Type definitions for addr types |
2 | | //! |
3 | | //! An addr (short for: address) is a dynamic index only known at runtime into a |
4 | | //! store. There are addr types for different index spaces, such as memories, |
5 | | //! globals or functions [`FuncAddr`]. |
6 | | //! |
7 | | //! |
8 | | //! # A Note About Accessor Methods on Store Address Spaces |
9 | | //! At first, we stored a [`Vec`] directly in the [`Store`](crate::Store) for |
10 | | //! function instances, table instances, etc. However, implementing accessor |
11 | | //! methods on the [`Store`](crate::Store) causes problems, because either the |
12 | | //! entire [`Store`](crate::Store) has to be passed as an argument (preventing |
13 | | //! partial borrows) or a specific [`Vec`] has to be passed as an argument |
14 | | //! (exposing [`Store`](crate::Store) implementation details through a pretty |
15 | | //! unergonomic API). |
16 | | //! |
17 | | //! Because both of these solutions were not sufficient, a choice was made for |
18 | | //! newtype wrappers around every address space. This way, partial borrows of |
19 | | //! the [`Store`](crate::Store) are possible, while providing a nice API, even |
20 | | //! if it is just used internally. |
21 | | |
22 | | use alloc::vec::Vec; |
23 | | use core::{cmp::Ordering, marker::PhantomData}; |
24 | | |
25 | | /// A trait for all address types. |
26 | | pub(crate) trait Addr: Copy + core::fmt::Debug + core::fmt::Display + Eq { |
27 | | fn new(inner: usize) -> Self; |
28 | | |
29 | | fn into_inner(self) -> usize; |
30 | | } |
31 | | |
32 | | pub(crate) struct AddrVec<A: Addr, Inst> { |
33 | | inner: Vec<Inst>, |
34 | | _phantom: PhantomData<A>, |
35 | | } |
36 | | |
37 | | impl<A: Addr, Inst> Default for AddrVec<A, Inst> { |
38 | 3.43k | fn default() -> Self { |
39 | 3.43k | Self { |
40 | 3.43k | inner: Vec::default(), |
41 | 3.43k | _phantom: PhantomData, |
42 | 3.43k | } |
43 | 3.43k | } |
44 | | } |
45 | | |
46 | | impl<A: Addr, Inst> AddrVec<A, Inst> { |
47 | | /// Returns an instance by its address `addr`. |
48 | | /// |
49 | | /// # Safety |
50 | | /// |
51 | | /// The caller must ensure that the given address is valid in this vector. |
52 | 1.96M | pub unsafe fn get(&self, addr: A) -> &Inst { |
53 | 1.96M | let addr = addr.into_inner(); |
54 | | |
55 | 1.96M | debug_assert!(self.inner.get(addr).is_some()); |
56 | | // SAFETY: The caller ensures that the given address is valid in this vector. Because this |
57 | | // vector cannot shrink the address must point to an existing element. |
58 | 1.96M | unsafe { self.inner.get_unchecked(addr) } |
59 | 1.96M | } |
60 | | |
61 | | /// Returns a mutable reference to some instance by its address `addr`. |
62 | | /// |
63 | | /// # Safety |
64 | | /// |
65 | | /// The caller must ensure that the given address is valid in this vector. |
66 | 942k | pub unsafe fn get_mut(&mut self, addr: A) -> &mut Inst { |
67 | 942k | let addr = addr.into_inner(); |
68 | | |
69 | 942k | debug_assert!(self.inner.get_mut(addr).is_some()); |
70 | | // SAFETY: The caller ensures that the given address is valid in this vector. Because this |
71 | | // vector cannot shrink, the address must still be valid. |
72 | 942k | unsafe { self.inner.get_unchecked_mut(addr) } |
73 | 942k | } |
74 | | |
75 | | /// Inserts a new instance into the current [`Store`](crate::Store) and returns its address. |
76 | | /// |
77 | | /// This method should always be used to insert new instances, as it is the only safe way of creating addrs. |
78 | 12.5k | pub fn insert(&mut self, instance: Inst) -> A { |
79 | 12.5k | let new_addr = self.inner.len(); |
80 | 12.5k | self.inner.push(instance); |
81 | 12.5k | A::new(new_addr) |
82 | 12.5k | } |
83 | | |
84 | | /// Mutably borrows two instances by their addresses and returns those |
85 | | /// references. In the case where both given addresses are equal, `None` is |
86 | | /// returned instead. |
87 | | /// |
88 | | /// # Safety |
89 | | /// |
90 | | /// The caller must ensure that both given addresses are valid in this |
91 | | /// vector. |
92 | 6 | pub unsafe fn get_two_mut( |
93 | 6 | &mut self, |
94 | 6 | addr_one: A, |
95 | 6 | addr_two: A, |
96 | 6 | ) -> Option<(&mut Inst, &mut Inst)> { |
97 | 6 | let addr_one = addr_one.into_inner(); |
98 | 6 | let addr_two = addr_two.into_inner(); |
99 | | |
100 | 6 | match addr_one.cmp(&addr_two) { |
101 | | Ordering::Greater => { |
102 | 1 | debug_assert!(self.inner.get(addr_one).is_some()); |
103 | | // SAFETY: The caller ensures that the given address is valid in this vector. |
104 | | // Because this vector cannot shrink, the address must still point to an existing |
105 | | // element. |
106 | 1 | let (left, right) = unsafe { self.inner.split_at_mut_unchecked(addr_one) }; |
107 | | |
108 | 1 | debug_assert!(!right.is_empty()); |
109 | | // SAFETY: `right` starts with the element pointed to by `addr_one`, which was valid |
110 | | // in this vector. Therefore, `right` must contain at least one element. |
111 | 1 | let one = unsafe { right.get_unchecked_mut(0) }; |
112 | | |
113 | 1 | debug_assert!(left.get(addr_two).is_some()); |
114 | | // SAFETY: `left` contains the first `addr_one` elements from this vector. Because |
115 | | // `addr_one` is greater than `addr_two`, `addr_two` must be a valid index in |
116 | | // `left`. |
117 | 1 | let two = unsafe { left.get_unchecked_mut(addr_two) }; |
118 | | |
119 | 1 | Some((one, two)) |
120 | | } |
121 | | Ordering::Less => { |
122 | 5 | debug_assert!(self.inner.get(addr_two).is_some()); |
123 | | // SAFETY: The caller ensures that the given address is valid in this vector. |
124 | | // Because this vector cannot shrink, the address must still point to an existing |
125 | | // element. |
126 | 5 | let (left, right) = unsafe { self.inner.split_at_mut_unchecked(addr_two) }; |
127 | | |
128 | 5 | debug_assert!(left.get(addr_one).is_some()); |
129 | | // SAFETY: `left` contains the first `addr_two` elements from this vector. Because |
130 | | // `addr_one` is less than `addr_two`, `addr_one` must be a valid index in `left`. |
131 | 5 | let one = unsafe { left.get_unchecked_mut(addr_one) }; |
132 | | |
133 | 5 | debug_assert!(!right.is_empty()); |
134 | | // SAFETY: `right` starts with the element points to by `addr_two`, which was valid |
135 | | // in this vector. Therefore, `right` must contain at least one element. |
136 | 5 | let two = unsafe { right.get_unchecked_mut(0) }; |
137 | | |
138 | 5 | Some((one, two)) |
139 | | } |
140 | 0 | Ordering::Equal => None, |
141 | | } |
142 | 6 | } |
143 | | } |
144 | | |
145 | | /// An address to a function instance that lives in a specific [`Store`](crate::Store). |
146 | | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
147 | | pub struct FuncAddr(usize); |
148 | | |
149 | | impl core::fmt::Display for FuncAddr { |
150 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
151 | 0 | write!(f, "function address {}", self.0) |
152 | 0 | } |
153 | | } |
154 | | |
155 | | impl Addr for FuncAddr { |
156 | 7.59k | fn new(inner: usize) -> Self { |
157 | 7.59k | Self(inner) |
158 | 7.59k | } |
159 | | |
160 | 412k | fn into_inner(self) -> usize { |
161 | 412k | self.0 |
162 | 412k | } |
163 | | } |
164 | | |
165 | | /// An address to a table instance that lives in a specific [`Store`](crate::Store). |
166 | | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
167 | | pub struct TableAddr(usize); |
168 | | |
169 | | impl core::fmt::Display for TableAddr { |
170 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
171 | 0 | write!(f, "table address {}", self.0) |
172 | 0 | } |
173 | | } |
174 | | |
175 | | impl Addr for TableAddr { |
176 | 504 | fn new(inner: usize) -> Self { |
177 | 504 | Self(inner) |
178 | 504 | } |
179 | | |
180 | 101k | fn into_inner(self) -> usize { |
181 | 101k | self.0 |
182 | 101k | } |
183 | | } |
184 | | |
185 | | /// An address to a memory instance that lives in a specific [`Store`](crate::Store). |
186 | | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
187 | | pub struct MemAddr(usize); |
188 | | |
189 | | impl core::fmt::Display for MemAddr { |
190 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
191 | 0 | write!(f, "memory address {}", self.0) |
192 | 0 | } |
193 | | } |
194 | | |
195 | | impl Addr for MemAddr { |
196 | 546 | fn new(inner: usize) -> Self { |
197 | 546 | Self(inner) |
198 | 546 | } |
199 | | |
200 | 937k | fn into_inner(self) -> usize { |
201 | 937k | self.0 |
202 | 937k | } |
203 | | } |
204 | | |
205 | | /// An address to a global instance that lives in a specific [`Store`](crate::Store). |
206 | | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
207 | | pub struct GlobalAddr(usize); |
208 | | |
209 | | impl core::fmt::Display for GlobalAddr { |
210 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
211 | 0 | write!(f, "global address {}", self.0) |
212 | 0 | } |
213 | | } |
214 | | |
215 | | impl Addr for GlobalAddr { |
216 | 681 | fn new(inner: usize) -> Self { |
217 | 681 | Self(inner) |
218 | 681 | } |
219 | | |
220 | | /// Returns the inner integer represented by this [`GlobalAddr`]. |
221 | 463 | fn into_inner(self) -> usize { |
222 | 463 | self.0 |
223 | 463 | } |
224 | | } |
225 | | |
226 | | /// An address to an element instance that lives in a specific [`Store`](crate::Store). |
227 | | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
228 | | pub struct ElemAddr(usize); |
229 | | |
230 | | impl core::fmt::Display for ElemAddr { |
231 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
232 | 0 | write!(f, "element segment address {}", self.0) |
233 | 0 | } |
234 | | } |
235 | | |
236 | | impl Addr for ElemAddr { |
237 | 815 | fn new(inner: usize) -> Self { |
238 | 815 | Self(inner) |
239 | 815 | } |
240 | | |
241 | 882 | fn into_inner(self) -> usize { |
242 | 882 | self.0 |
243 | 882 | } |
244 | | } |
245 | | |
246 | | /// An address to a data instance that lives in a specific [`Store`](crate::Store). |
247 | | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
248 | | pub struct DataAddr(usize); |
249 | | |
250 | | impl core::fmt::Display for DataAddr { |
251 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
252 | 0 | write!(f, "data segment address {}", self.0) |
253 | 0 | } |
254 | | } |
255 | | |
256 | | impl Addr for DataAddr { |
257 | 449 | fn new(inner: usize) -> Self { |
258 | 449 | Self(inner) |
259 | 449 | } |
260 | | |
261 | 554 | fn into_inner(self) -> usize { |
262 | 554 | self.0 |
263 | 554 | } |
264 | | } |
265 | | |
266 | | /// An address to a module instance that lives in a specific [`Store`](crate::Store). |
267 | | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
268 | | pub struct ModuleAddr(usize); |
269 | | |
270 | | impl core::fmt::Display for ModuleAddr { |
271 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
272 | 0 | write!(f, "module address {}", self.0) |
273 | 0 | } |
274 | | } |
275 | | |
276 | | impl Addr for ModuleAddr { |
277 | 1.96k | fn new(inner: usize) -> Self { |
278 | 1.96k | Self(inner) |
279 | 1.96k | } |
280 | | |
281 | 1.45M | fn into_inner(self) -> usize { |
282 | 1.45M | self.0 |
283 | 1.45M | } |
284 | | } |