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#[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 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 &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 &mut T::list_mut(self)[index.index()]
136 }
137}
138
139impl<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
152impl<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
165impl<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#[derive(Debug, Copy, Clone, PartialEq)]
195pub struct StoreId(NonZeroU64);
196
197impl StoreId {
198 fn allocate() -> StoreId {
201 static NEXT_ID: AtomicU64 = AtomicU64::new(0);
202
203 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)] pub 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}