wasm/execution/store/
addrs.rs

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
22use core::{cmp::Ordering, marker::PhantomData};
23
24use alloc::vec::Vec;
25
26/// A trait for all address types.
27///
28/// This is used by [`AddrVec`] to create and read address types.
29pub(crate) trait Addr: Copy + core::fmt::Debug + core::fmt::Display + Eq {
30    fn new_unchecked(inner: usize) -> Self;
31
32    fn into_inner(self) -> usize;
33}
34
35pub(crate) struct AddrVec<A: Addr, Inst> {
36    inner: Vec<Inst>,
37    _phantom: PhantomData<A>,
38}
39
40impl<A: Addr, Inst> Default for AddrVec<A, Inst> {
41    fn default() -> Self {
42        Self {
43            inner: Vec::default(),
44            _phantom: PhantomData,
45        }
46    }
47}
48
49impl<A: Addr, Inst> AddrVec<A, Inst> {
50    /// Returns an instance by its address `addr`.
51    pub fn get(&self, addr: A) -> &Inst {
52        self.inner
53            .get(addr.into_inner())
54            .expect("addrs to always be valid")
55    }
56
57    /// Returns a mutable reference to some instance by its address `addr`.
58    pub fn get_mut(&mut self, addr: A) -> &mut Inst {
59        self.inner
60            .get_mut(addr.into_inner())
61            .expect("addrs to always be valid")
62    }
63
64    /// Inserts a new instance into the current [`Store`](crate::Store) and returns its address.
65    ///
66    /// This method should always be used to insert new instances, as it is the only safe way of creating addrs.
67    pub(crate) fn insert(&mut self, instance: Inst) -> A {
68        let new_addr = self.inner.len();
69        self.inner.push(instance);
70        A::new_unchecked(new_addr)
71    }
72
73    /// Mutably borrows two instances by their addresses and returns those
74    /// references. In the case where both given addresses are equal, `None` is
75    /// returned instead.
76    pub(crate) fn get_two_mut(
77        &mut self,
78        addr_one: A,
79        addr_two: A,
80    ) -> Option<(&mut Inst, &mut Inst)> {
81        let addr_one = addr_one.into_inner();
82        let addr_two = addr_two.into_inner();
83
84        match addr_one.cmp(&addr_two) {
85            Ordering::Greater => {
86                let (left, right) = self.inner.split_at_mut(addr_one);
87                let one = right.get_mut(0).expect(
88                    "this to be exactly the same as addr_one and addresses to always be valid",
89                );
90                let two = left
91                    .get_mut(addr_two)
92                    .expect("addresses to always be valid");
93
94                Some((one, two))
95            }
96            Ordering::Less => {
97                let (left, right) = self.inner.split_at_mut(addr_two);
98                let one = left
99                    .get_mut(addr_one)
100                    .expect("addresses to always be valid");
101                let two = right.get_mut(0).expect(
102                    "this to be exactly the same as addr_two and addresses to always be valid",
103                );
104
105                Some((one, two))
106            }
107            Ordering::Equal => None,
108        }
109    }
110}
111
112/// An address to a function instance that lives in a specific [`Store`](crate::execution::store::Store).
113#[derive(Copy, Clone, Debug, PartialEq, Eq)]
114pub struct FuncAddr(usize);
115
116impl FuncAddr {
117    // This is unfortunately needed as a default value for the base `CallFrame` in every call stack.
118    pub(crate) const INVALID: Self = FuncAddr(usize::MAX);
119}
120
121impl core::fmt::Display for FuncAddr {
122    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
123        write!(f, "function address {}", self.0)
124    }
125}
126
127impl Addr for FuncAddr {
128    fn new_unchecked(inner: usize) -> Self {
129        Self(inner)
130    }
131
132    fn into_inner(self) -> usize {
133        self.0
134    }
135}
136
137/// An address to a table instance that lives in a specific [`Store`](crate::Store).
138#[derive(Copy, Clone, Debug, PartialEq, Eq)]
139pub struct TableAddr(usize);
140
141impl core::fmt::Display for TableAddr {
142    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
143        write!(f, "table address {}", self.0)
144    }
145}
146
147impl Addr for TableAddr {
148    fn new_unchecked(inner: usize) -> Self {
149        Self(inner)
150    }
151
152    fn into_inner(self) -> usize {
153        self.0
154    }
155}
156
157/// An address to a memory instance that lives in a specific [`Store`](crate::Store).
158#[derive(Copy, Clone, Debug, PartialEq, Eq)]
159pub struct MemAddr(usize);
160
161impl core::fmt::Display for MemAddr {
162    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
163        write!(f, "memory address {}", self.0)
164    }
165}
166
167impl Addr for MemAddr {
168    fn new_unchecked(inner: usize) -> Self {
169        Self(inner)
170    }
171
172    fn into_inner(self) -> usize {
173        self.0
174    }
175}
176
177/// An address to a global instance that lives in a specific [`Store`](crate::Store).
178#[derive(Copy, Clone, Debug, PartialEq, Eq)]
179pub struct GlobalAddr(usize);
180
181impl core::fmt::Display for GlobalAddr {
182    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
183        write!(f, "global address {}", self.0)
184    }
185}
186
187impl Addr for GlobalAddr {
188    fn new_unchecked(inner: usize) -> Self {
189        Self(inner)
190    }
191
192    /// Returns the inner integer represented by this [`GlobalAddr`].
193    fn into_inner(self) -> usize {
194        self.0
195    }
196}
197
198/// An address to an element instance that lives in a specific [`Store`](crate::Store).
199#[derive(Copy, Clone, Debug, PartialEq, Eq)]
200pub struct ElemAddr(usize);
201
202impl core::fmt::Display for ElemAddr {
203    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
204        write!(f, "element segment address {}", self.0)
205    }
206}
207
208impl Addr for ElemAddr {
209    fn new_unchecked(inner: usize) -> Self {
210        Self(inner)
211    }
212
213    fn into_inner(self) -> usize {
214        self.0
215    }
216}
217
218/// An address to a data instance that lives in a specific [`Store`](crate::Store).
219#[derive(Copy, Clone, Debug, PartialEq, Eq)]
220pub struct DataAddr(usize);
221
222impl core::fmt::Display for DataAddr {
223    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
224        write!(f, "data segment address {}", self.0)
225    }
226}
227
228impl Addr for DataAddr {
229    fn new_unchecked(inner: usize) -> Self {
230        Self(inner)
231    }
232
233    fn into_inner(self) -> usize {
234        self.0
235    }
236}
237
238/// An address to a module instance that lives in a specific [`Store`](crate::Store).
239#[derive(Copy, Clone, Debug, PartialEq, Eq)]
240pub struct ModuleAddr(usize);
241
242impl core::fmt::Display for ModuleAddr {
243    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
244        write!(f, "module address {}", self.0)
245    }
246}
247
248impl Addr for ModuleAddr {
249    fn new_unchecked(inner: usize) -> Self {
250        Self(inner)
251    }
252
253    fn into_inner(self) -> usize {
254        self.0
255    }
256}