1 use crate::module::ModuleRegistry;
2 use crate::runtime::vm::{self, GcStore, VMStore};
3 use crate::store::StoreOpaque;
4 use crate::{Engine, StoreContext, StoreContextMut};
5 use core::num::NonZeroU64;
6 use core::ops::{Index, IndexMut};
7 use core::pin::Pin;
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, Debug, PartialEq, Eq)]
14 pub struct InstanceId(u32);
15 wasmtime_environ::entity_impl!(InstanceId);
16
17 pub struct StoreData {
18 id: StoreId,
19 #[cfg(feature = "component-model")]
20 pub(crate) components: crate::component::ComponentStoreData,
21 }
22
23 impl StoreData {
new(engine: &Engine) -> StoreData24 pub fn new(engine: &Engine) -> StoreData {
25 #[cfg(not(feature = "component-model"))]
26 let _ = engine;
27 StoreData {
28 id: StoreId::allocate(),
29 #[cfg(feature = "component-model")]
30 components: crate::component::ComponentStoreData::new(engine),
31 }
32 }
33
id(&self) -> StoreId34 pub fn id(&self) -> StoreId {
35 self.id
36 }
37
run_manual_drop_routines<T>(store: StoreContextMut<T>)38 pub fn run_manual_drop_routines<T>(store: StoreContextMut<T>) {
39 #[cfg(feature = "component-model")]
40 crate::component::ComponentStoreData::run_manual_drop_routines(store);
41 #[cfg(not(feature = "component-model"))]
42 let _ = store;
43 }
44
decrement_allocator_resources(&mut self, allocator: &dyn vm::InstanceAllocator)45 pub fn decrement_allocator_resources(&mut self, allocator: &dyn vm::InstanceAllocator) {
46 #[cfg(feature = "component-model")]
47 self.components.decrement_allocator_resources(allocator);
48 #[cfg(not(feature = "component-model"))]
49 let _ = allocator;
50 }
51 }
52
53 // forward StoreOpaque => StoreData
54 impl<I> Index<I> for StoreOpaque
55 where
56 StoreData: Index<I>,
57 {
58 type Output = <StoreData as Index<I>>::Output;
59
60 #[inline]
index(&self, index: I) -> &Self::Output61 fn index(&self, index: I) -> &Self::Output {
62 self.store_data.index(index)
63 }
64 }
65
66 impl<I> IndexMut<I> for StoreOpaque
67 where
68 StoreData: IndexMut<I>,
69 {
70 #[inline]
index_mut(&mut self, index: I) -> &mut Self::Output71 fn index_mut(&mut self, index: I) -> &mut Self::Output {
72 self.store_data.index_mut(index)
73 }
74 }
75
76 // forward StoreContext => StoreOpaque
77 impl<I, T> Index<I> for StoreContext<'_, T>
78 where
79 StoreOpaque: Index<I>,
80 {
81 type Output = <StoreOpaque as Index<I>>::Output;
82
83 #[inline]
index(&self, index: I) -> &Self::Output84 fn index(&self, index: I) -> &Self::Output {
85 self.0.index(index)
86 }
87 }
88
89 // forward StoreContextMut => StoreOpaque
90 impl<I, T> Index<I> for StoreContextMut<'_, T>
91 where
92 StoreOpaque: Index<I>,
93 {
94 type Output = <StoreOpaque as Index<I>>::Output;
95
96 #[inline]
index(&self, index: I) -> &Self::Output97 fn index(&self, index: I) -> &Self::Output {
98 self.0.index(index)
99 }
100 }
101
102 impl<I, T> IndexMut<I> for StoreContextMut<'_, T>
103 where
104 StoreOpaque: IndexMut<I>,
105 {
106 #[inline]
index_mut(&mut self, index: I) -> &mut Self::Output107 fn index_mut(&mut self, index: I) -> &mut Self::Output {
108 self.0.index_mut(index)
109 }
110 }
111
112 // forward dyn VMStore => StoreOpaque
113 impl<I> Index<I> for dyn VMStore + '_
114 where
115 StoreOpaque: Index<I>,
116 {
117 type Output = <StoreOpaque as Index<I>>::Output;
118
index(&self, index: I) -> &Self::Output119 fn index(&self, index: I) -> &Self::Output {
120 self.store_opaque().index(index)
121 }
122 }
123
124 impl<I> IndexMut<I> for dyn VMStore + '_
125 where
126 StoreOpaque: IndexMut<I>,
127 {
index_mut(&mut self, index: I) -> &mut Self::Output128 fn index_mut(&mut self, index: I) -> &mut Self::Output {
129 self.store_opaque_mut().index_mut(index)
130 }
131 }
132
133 /// A unique identifier to get attached to a store.
134 ///
135 /// This identifier is embedded into the `Stored<T>` structure and is used to
136 /// identify the original store that items come from. For example a `Memory` is
137 /// owned by a `Store` and will embed a `StoreId` internally to say which store
138 /// it came from. Comparisons with this value are how panics are generated for
139 /// mismatching the item that a store belongs to.
140 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
141 #[repr(transparent)] // NB: relied on in the C API
142 pub struct StoreId(NonZeroU64);
143
144 impl StoreId {
145 /// Allocates a new unique identifier for a store that has never before been
146 /// used in this process.
allocate() -> StoreId147 pub fn allocate() -> StoreId {
148 // When 64-bit atomics are allowed then allow 2^63 stores at which point
149 // we start panicking to prevent overflow.
150 //
151 // If a store is created once per microsecond then this will last the
152 // current process for 584,540 years before overflowing.
153 const OVERFLOW_THRESHOLD: u64 = 1 << 63;
154
155 #[cfg(target_has_atomic = "64")]
156 let id = {
157 use core::sync::atomic::{AtomicU64, Ordering::Relaxed};
158
159 // Note the usage of `Relaxed` ordering here which should be ok
160 // since we're only looking for atomicity on this counter and this
161 // otherwise isn't used to synchronize memory stored anywhere else.
162 static NEXT_ID: AtomicU64 = AtomicU64::new(0);
163 let id = NEXT_ID.fetch_add(1, Relaxed);
164 if id > OVERFLOW_THRESHOLD {
165 NEXT_ID.store(OVERFLOW_THRESHOLD, Relaxed);
166 panic!("store id allocator overflow");
167 }
168 id
169 };
170
171 // When 64-bit atomics are not allowed use a `RwLock<u64>`. This is
172 // already used elsewhere in Wasmtime and currently has the
173 // implementation of panic-on-contention, but it's at least no worse
174 // than what wasmtime had before and is at least correct and UB-free.
175 #[cfg(not(target_has_atomic = "64"))]
176 let id = {
177 use crate::sync::RwLock;
178 static NEXT_ID: RwLock<u64> = RwLock::new(0);
179
180 let mut lock = NEXT_ID.write();
181 if *lock > OVERFLOW_THRESHOLD {
182 panic!("store id allocator overflow");
183 }
184 let ret = *lock;
185 *lock += 1;
186 ret
187 };
188
189 StoreId(NonZeroU64::new(id + 1).unwrap())
190 }
191
192 #[inline]
assert_belongs_to(&self, store: StoreId)193 pub fn assert_belongs_to(&self, store: StoreId) {
194 if *self == store {
195 return;
196 }
197 store_id_mismatch();
198 }
199
200 /// Raw accessor for the C API.
as_raw(&self) -> NonZeroU64201 pub fn as_raw(&self) -> NonZeroU64 {
202 self.0
203 }
204
205 /// Raw constructor for the C API.
from_raw(id: NonZeroU64) -> StoreId206 pub fn from_raw(id: NonZeroU64) -> StoreId {
207 StoreId(id)
208 }
209 }
210
211 #[cold]
store_id_mismatch()212 fn store_id_mismatch() {
213 panic!("object used with the wrong store");
214 }
215
216 /// A type used to represent an allocated `vm::Instance` located within a store.
217 ///
218 /// This type is held in various locations as a "safe index" into a store. This
219 /// encapsulates a `StoreId` which owns the instance as well as the index within
220 /// the store's list of which instance it's pointing to.
221 ///
222 /// This type can notably be used to index into a `StoreOpaque` to project out
223 /// the `vm::Instance` that is associated with this id.
224 #[repr(C)] // used by reference in the C API
225 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
226 pub struct StoreInstanceId {
227 store_id: StoreId,
228 instance: InstanceId,
229 }
230
231 impl StoreInstanceId {
new(store_id: StoreId, instance: InstanceId) -> StoreInstanceId232 pub(crate) fn new(store_id: StoreId, instance: InstanceId) -> StoreInstanceId {
233 StoreInstanceId { store_id, instance }
234 }
235
236 #[inline]
assert_belongs_to(&self, store: StoreId)237 pub fn assert_belongs_to(&self, store: StoreId) {
238 self.store_id.assert_belongs_to(store)
239 }
240
241 #[inline]
store_id(&self) -> StoreId242 pub fn store_id(&self) -> StoreId {
243 self.store_id
244 }
245
246 #[inline]
instance(&self) -> InstanceId247 pub(crate) fn instance(&self) -> InstanceId {
248 self.instance
249 }
250
251 /// Looks up the `vm::Instance` within `store` that this id points to.
252 ///
253 /// # Panics
254 ///
255 /// Panics if `self` does not belong to `store`.
256 #[inline]
get<'a>(&self, store: &'a StoreOpaque) -> &'a vm::Instance257 pub(crate) fn get<'a>(&self, store: &'a StoreOpaque) -> &'a vm::Instance {
258 self.assert_belongs_to(store.id());
259 store.instance(self.instance)
260 }
261
262 /// Mutable version of `get` above.
263 ///
264 /// # Panics
265 ///
266 /// Panics if `self` does not belong to `store`.
267 #[inline]
get_mut<'a>(&self, store: &'a mut StoreOpaque) -> Pin<&'a mut vm::Instance>268 pub(crate) fn get_mut<'a>(&self, store: &'a mut StoreOpaque) -> Pin<&'a mut vm::Instance> {
269 self.assert_belongs_to(store.id());
270 store.instance_mut(self.instance)
271 }
272
273 /// Get both an instance handle and a borrow to the module
274 /// registry in the store.
275 ///
276 /// # Panics
277 ///
278 /// Panics if `self` does not belong to `store`.
279 #[inline]
get_mut_and_module_registry<'a>( &self, store: &'a mut StoreOpaque, ) -> (Pin<&'a mut vm::Instance>, &'a ModuleRegistry)280 pub(crate) fn get_mut_and_module_registry<'a>(
281 &self,
282 store: &'a mut StoreOpaque,
283 ) -> (Pin<&'a mut vm::Instance>, &'a ModuleRegistry) {
284 self.assert_belongs_to(store.id());
285 store.instance_and_module_registry_mut(self.instance)
286 }
287
288 /// Same as [`Self::get_mut`], but also returns the `GcStore`.
289 #[inline]
get_with_gc_store_mut<'a>( &self, store: &'a mut StoreOpaque, ) -> (Option<&'a mut GcStore>, Pin<&'a mut vm::Instance>)290 pub(crate) fn get_with_gc_store_mut<'a>(
291 &self,
292 store: &'a mut StoreOpaque,
293 ) -> (Option<&'a mut GcStore>, Pin<&'a mut vm::Instance>) {
294 self.assert_belongs_to(store.id());
295 store.optional_gc_store_and_instance_mut(self.instance)
296 }
297 }
298
299 impl Index<StoreInstanceId> for StoreOpaque {
300 type Output = vm::Instance;
301
302 #[inline]
index(&self, id: StoreInstanceId) -> &Self::Output303 fn index(&self, id: StoreInstanceId) -> &Self::Output {
304 id.get(self)
305 }
306 }
307