1 use crate::prelude::*;
2 use crate::store::StoreOpaque;
3 use crate::{StoreContext, StoreContextMut};
4 use core::fmt;
5 use core::marker;
6 use core::num::NonZeroU64;
7 use core::ops::{Index, IndexMut};
8 use 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)]
15 pub struct InstanceId(pub(super) usize);
16 
17 impl InstanceId {
18     pub fn from_index(idx: usize) -> InstanceId {
19         InstanceId(idx)
20     }
21 }
22 
23 pub 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 
34 pub trait StoredData: Sized {
35     fn list(data: &StoreData) -> &Vec<Self>;
36     fn list_mut(data: &mut StoreData) -> &mut Vec<Self>;
37 }
38 
39 macro_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 
50 impl_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 
58 impl 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 
119 impl<T> Index<Stored<T>> for StoreData
120 where
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 
137 impl<T> IndexMut<Stored<T>> for StoreData
138 where
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
151 impl<I, T> Index<I> for StoreContext<'_, T>
152 where
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
164 impl<I, T> Index<I> for StoreContextMut<'_, T>
165 where
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
177 impl<I> Index<I> for StoreOpaque
178 where
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 }
188 impl<I> IndexMut<I> for StoreOpaque
189 where
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
207 pub struct StoreId(NonZeroU64);
208 
209 impl 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`.
253 pub struct Stored<T> {
254     store_id: StoreId,
255     index: usize,
256     _marker: marker::PhantomData<fn() -> T>,
257 }
258 
259 impl<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]
279 fn store_id_mismatch() {
280     panic!("object used with the wrong store");
281 }
282 
283 impl<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 
289 impl<T> Copy for Stored<T> {}
290 
291 impl<T> Clone for Stored<T> {
292     fn clone(&self) -> Self {
293         *self
294     }
295 }
296 
297 impl<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 }
302