wasmtime/store/
data.rs

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