wasmtime/runtime/store/
data.rs

1use crate::prelude::*;
2use crate::store::StoreOpaque;
3use crate::{StoreContext, StoreContextMut};
4use core::fmt;
5use core::marker;
6use core::num::NonZeroU64;
7use core::ops::{Index, IndexMut};
8use core::sync::atomic::{AtomicU64, Ordering::Relaxed};
9
10// This is defined here, in a private submodule, so we can explicitly reexport
11// it only as `pub(crate)`. This avoids a ton of
12// crate-private-type-in-public-interface errors that aren't really too
13// interesting to deal with.
14#[derive(Copy, Clone)]
15pub struct InstanceId(pub(super) usize);
16
17impl InstanceId {
18    pub fn from_index(idx: usize) -> InstanceId {
19        InstanceId(idx)
20    }
21}
22
23pub struct StoreData {
24    id: StoreId,
25    funcs: Vec<crate::func::FuncData>,
26    tables: Vec<crate::runtime::vm::ExportTable>,
27    globals: Vec<crate::runtime::vm::ExportGlobal>,
28    instances: Vec<crate::instance::InstanceData>,
29    memories: Vec<crate::runtime::vm::ExportMemory>,
30    #[cfg(feature = "component-model")]
31    pub(crate) components: crate::component::ComponentStoreData,
32}
33
34pub trait StoredData: Sized {
35    fn list(data: &StoreData) -> &Vec<Self>;
36    fn list_mut(data: &mut StoreData) -> &mut Vec<Self>;
37}
38
39macro_rules! impl_store_data {
40    ($($field:ident => $t:ty,)*) => ($(
41        impl StoredData for $t {
42            #[inline]
43            fn list(data: &StoreData) -> &Vec<Self> { &data.$field }
44            #[inline]
45            fn list_mut(data: &mut StoreData) -> &mut Vec<Self> { &mut data.$field }
46        }
47    )*)
48}
49
50impl_store_data! {
51    funcs => crate::func::FuncData,
52    tables => crate::runtime::vm::ExportTable,
53    globals => crate::runtime::vm::ExportGlobal,
54    instances => crate::instance::InstanceData,
55    memories => crate::runtime::vm::ExportMemory,
56}
57
58impl StoreData {
59    pub fn new() -> StoreData {
60        StoreData {
61            id: StoreId::allocate(),
62            funcs: Vec::new(),
63            tables: Vec::new(),
64            globals: Vec::new(),
65            instances: Vec::new(),
66            memories: Vec::new(),
67            #[cfg(feature = "component-model")]
68            components: Default::default(),
69        }
70    }
71
72    pub fn id(&self) -> StoreId {
73        self.id
74    }
75
76    pub fn insert<T>(&mut self, data: T) -> Stored<T>
77    where
78        T: StoredData,
79    {
80        let list = T::list_mut(self);
81        let index = list.len();
82        list.push(data);
83        Stored::new(self.id, index)
84    }
85
86    pub fn next_id<T>(&self) -> Stored<T>
87    where
88        T: StoredData,
89    {
90        Stored::new(self.id, T::list(self).len())
91    }
92
93    pub fn contains<T>(&self, id: Stored<T>) -> bool
94    where
95        T: StoredData,
96    {
97        if id.store_id != self.id {
98            return false;
99        }
100        // This should be true as an invariant of our API, but double-check with
101        // debug assertions enabled.
102        debug_assert!(id.index() < T::list(self).len());
103        true
104    }
105
106    pub fn iter<T>(&self) -> impl ExactSizeIterator<Item = Stored<T>>
107    where
108        T: StoredData,
109    {
110        let id = self.id;
111        (0..T::list(self).len()).map(move |i| Stored::new(id, i))
112    }
113
114    pub(crate) fn reserve_funcs(&mut self, count: usize) {
115        self.funcs.reserve(count);
116    }
117}
118
119impl<T> Index<Stored<T>> for StoreData
120where
121    T: StoredData,
122{
123    type Output = T;
124
125    #[inline]
126    fn index(&self, index: Stored<T>) -> &Self::Output {
127        index.assert_belongs_to(self.id);
128        // Note that if this is ever a performance bottleneck it should be safe
129        // to use unchecked indexing here because presence of a `Stored<T>` is
130        // proof of an item having been inserted into a store and lists in
131        // stores are never shrunk. After the store check above the actual index
132        // should always be valid.
133        &T::list(self)[index.index()]
134    }
135}
136
137impl<T> IndexMut<Stored<T>> for StoreData
138where
139    T: StoredData,
140{
141    #[inline]
142    fn index_mut(&mut self, index: Stored<T>) -> &mut Self::Output {
143        index.assert_belongs_to(self.id);
144        // Note that this could be unchecked indexing, see the note in `Index`
145        // above.
146        &mut T::list_mut(self)[index.index()]
147    }
148}
149
150// forward StoreContext => StoreData
151impl<I, T> Index<I> for StoreContext<'_, T>
152where
153    StoreData: Index<I>,
154{
155    type Output = <StoreData as Index<I>>::Output;
156
157    #[inline]
158    fn index(&self, index: I) -> &Self::Output {
159        self.0.store_data.index(index)
160    }
161}
162
163// forward StoreContextMut => StoreData
164impl<I, T> Index<I> for StoreContextMut<'_, T>
165where
166    StoreData: Index<I>,
167{
168    type Output = <StoreData as Index<I>>::Output;
169
170    #[inline]
171    fn index(&self, index: I) -> &Self::Output {
172        self.0.store_data.index(index)
173    }
174}
175
176// forward StoreOpaque => StoreData
177impl<I> Index<I> for StoreOpaque
178where
179    StoreData: Index<I>,
180{
181    type Output = <StoreData as Index<I>>::Output;
182
183    #[inline]
184    fn index(&self, index: I) -> &Self::Output {
185        self.store_data().index(index)
186    }
187}
188impl<I> IndexMut<I> for StoreOpaque
189where
190    StoreData: IndexMut<I>,
191{
192    #[inline]
193    fn index_mut(&mut self, index: I) -> &mut Self::Output {
194        self.store_data_mut().index_mut(index)
195    }
196}
197
198/// A unique identifier to get attached to a store.
199///
200/// This identifier is embedded into the `Stored<T>` structure and is used to
201/// identify the original store that items come from. For example a `Memory` is
202/// owned by a `Store` and will embed a `StoreId` internally to say which store
203/// it came from. Comparisons with this value are how panics are generated for
204/// mismatching the item that a store belongs to.
205#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
206#[repr(transparent)] // NB: relied on in the C API
207pub struct StoreId(NonZeroU64);
208
209impl StoreId {
210    /// Allocates a new unique identifier for a store that has never before been
211    /// used in this process.
212    pub fn allocate() -> StoreId {
213        static NEXT_ID: AtomicU64 = AtomicU64::new(0);
214
215        // Only allow 2^63 stores at which point we start panicking to prevent
216        // overflow.
217        //
218        // If a store is created once per microsecond then this will last the
219        // current process for 584,540 years before overflowing.
220        //
221        // Also note the usage of `Relaxed` ordering here which should be ok
222        // since we're only looking for atomicity on this counter and this
223        // otherwise isn't used to synchronize memory stored anywhere else.
224        let id = NEXT_ID.fetch_add(1, Relaxed);
225        if id & (1 << 63) != 0 {
226            NEXT_ID.store(1 << 63, Relaxed);
227            panic!("store id allocator overflow");
228        }
229
230        StoreId(NonZeroU64::new(id + 1).unwrap())
231    }
232
233    #[inline]
234    pub fn assert_belongs_to(&self, store: StoreId) {
235        if *self == store {
236            return;
237        }
238        store_id_mismatch();
239    }
240
241    /// Raw accessor for the C API.
242    pub fn as_raw(&self) -> NonZeroU64 {
243        self.0
244    }
245
246    /// Raw constructor for the C API.
247    pub fn from_raw(id: NonZeroU64) -> StoreId {
248        StoreId(id)
249    }
250}
251
252#[repr(C)] // used by reference in the C API, also in `wasmtime_func_t`.
253pub struct Stored<T> {
254    store_id: StoreId,
255    index: usize,
256    _marker: marker::PhantomData<fn() -> T>,
257}
258
259impl<T> Stored<T> {
260    fn new(store_id: StoreId, index: usize) -> Stored<T> {
261        Stored {
262            store_id,
263            index,
264            _marker: marker::PhantomData,
265        }
266    }
267
268    #[inline]
269    pub fn assert_belongs_to(&self, store: StoreId) {
270        self.store_id.assert_belongs_to(store)
271    }
272
273    fn index(&self) -> usize {
274        self.index
275    }
276}
277
278#[cold]
279fn store_id_mismatch() {
280    panic!("object used with the wrong store");
281}
282
283impl<T> PartialEq for Stored<T> {
284    fn eq(&self, other: &Stored<T>) -> bool {
285        self.store_id == other.store_id && self.index == other.index
286    }
287}
288
289impl<T> Copy for Stored<T> {}
290
291impl<T> Clone for Stored<T> {
292    fn clone(&self) -> Self {
293        *self
294    }
295}
296
297impl<T> fmt::Debug for Stored<T> {
298    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
299        write!(f, "store={}, index={}", self.store_id.0, self.index())
300    }
301}