wasmtime/runtime/store/
data.rs

1use crate::runtime::vm::{self, VMStore};
2use crate::store::StoreOpaque;
3use crate::{StoreContext, StoreContextMut};
4use core::num::NonZeroU64;
5use core::ops::{Index, IndexMut};
6
7// This is defined here, in a private submodule, so we can explicitly reexport
8// it only as `pub(crate)`. This avoids a ton of
9// crate-private-type-in-public-interface errors that aren't really too
10// interesting to deal with.
11#[derive(Copy, Clone, Debug, PartialEq, Eq)]
12pub struct InstanceId(u32);
13wasmtime_environ::entity_impl!(InstanceId);
14
15pub struct StoreData {
16    id: StoreId,
17    #[cfg(feature = "component-model")]
18    pub(crate) components: crate::component::ComponentStoreData,
19}
20
21impl StoreData {
22    pub fn new() -> StoreData {
23        StoreData {
24            id: StoreId::allocate(),
25            #[cfg(feature = "component-model")]
26            components: Default::default(),
27        }
28    }
29
30    pub fn id(&self) -> StoreId {
31        self.id
32    }
33}
34
35// forward StoreOpaque => StoreData
36impl<I> Index<I> for StoreOpaque
37where
38    StoreData: Index<I>,
39{
40    type Output = <StoreData as Index<I>>::Output;
41
42    #[inline]
43    fn index(&self, index: I) -> &Self::Output {
44        self.store_data.index(index)
45    }
46}
47
48impl<I> IndexMut<I> for StoreOpaque
49where
50    StoreData: IndexMut<I>,
51{
52    #[inline]
53    fn index_mut(&mut self, index: I) -> &mut Self::Output {
54        self.store_data.index_mut(index)
55    }
56}
57
58// forward StoreContext => StoreOpaque
59impl<I, T> Index<I> for StoreContext<'_, T>
60where
61    StoreOpaque: Index<I>,
62{
63    type Output = <StoreOpaque as Index<I>>::Output;
64
65    #[inline]
66    fn index(&self, index: I) -> &Self::Output {
67        self.0.index(index)
68    }
69}
70
71// forward StoreContextMut => StoreOpaque
72impl<I, T> Index<I> for StoreContextMut<'_, T>
73where
74    StoreOpaque: Index<I>,
75{
76    type Output = <StoreOpaque as Index<I>>::Output;
77
78    #[inline]
79    fn index(&self, index: I) -> &Self::Output {
80        self.0.index(index)
81    }
82}
83
84impl<I, T> IndexMut<I> for StoreContextMut<'_, T>
85where
86    StoreOpaque: IndexMut<I>,
87{
88    #[inline]
89    fn index_mut(&mut self, index: I) -> &mut Self::Output {
90        self.0.index_mut(index)
91    }
92}
93
94// forward dyn VMStore => StoreOpaque
95impl<I> Index<I> for dyn VMStore + '_
96where
97    StoreOpaque: Index<I>,
98{
99    type Output = <StoreOpaque as Index<I>>::Output;
100
101    fn index(&self, index: I) -> &Self::Output {
102        self.store_opaque().index(index)
103    }
104}
105
106impl<I> IndexMut<I> for dyn VMStore + '_
107where
108    StoreOpaque: IndexMut<I>,
109{
110    fn index_mut(&mut self, index: I) -> &mut Self::Output {
111        self.store_opaque_mut().index_mut(index)
112    }
113}
114
115/// A unique identifier to get attached to a store.
116///
117/// This identifier is embedded into the `Stored<T>` structure and is used to
118/// identify the original store that items come from. For example a `Memory` is
119/// owned by a `Store` and will embed a `StoreId` internally to say which store
120/// it came from. Comparisons with this value are how panics are generated for
121/// mismatching the item that a store belongs to.
122#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
123#[repr(transparent)] // NB: relied on in the C API
124pub struct StoreId(NonZeroU64);
125
126impl StoreId {
127    /// Allocates a new unique identifier for a store that has never before been
128    /// used in this process.
129    pub fn allocate() -> StoreId {
130        // When 64-bit atomics are allowed then allow 2^63 stores at which point
131        // we start panicking to prevent overflow.
132        //
133        // If a store is created once per microsecond then this will last the
134        // current process for 584,540 years before overflowing.
135        const OVERFLOW_THRESHOLD: u64 = 1 << 63;
136
137        #[cfg(target_has_atomic = "64")]
138        let id = {
139            use core::sync::atomic::{AtomicU64, Ordering::Relaxed};
140
141            // Note the usage of `Relaxed` ordering here which should be ok
142            // since we're only looking for atomicity on this counter and this
143            // otherwise isn't used to synchronize memory stored anywhere else.
144            static NEXT_ID: AtomicU64 = AtomicU64::new(0);
145            let id = NEXT_ID.fetch_add(1, Relaxed);
146            if id > OVERFLOW_THRESHOLD {
147                NEXT_ID.store(OVERFLOW_THRESHOLD, Relaxed);
148                panic!("store id allocator overflow");
149            }
150            id
151        };
152
153        // When 64-bit atomics are not allowed use a `RwLock<u64>`. This is
154        // already used elsewhere in Wasmtime and currently has the
155        // implementation of panic-on-contention, but it's at least no worse
156        // than what wasmtime had before and is at least correct and UB-free.
157        #[cfg(not(target_has_atomic = "64"))]
158        let id = {
159            use crate::sync::RwLock;
160            static NEXT_ID: RwLock<u64> = RwLock::new(0);
161
162            let mut lock = NEXT_ID.write();
163            if *lock > OVERFLOW_THRESHOLD {
164                panic!("store id allocator overflow");
165            }
166            let ret = *lock;
167            *lock += 1;
168            ret
169        };
170
171        StoreId(NonZeroU64::new(id + 1).unwrap())
172    }
173
174    #[inline]
175    pub fn assert_belongs_to(&self, store: StoreId) {
176        if *self == store {
177            return;
178        }
179        store_id_mismatch();
180    }
181
182    /// Raw accessor for the C API.
183    pub fn as_raw(&self) -> NonZeroU64 {
184        self.0
185    }
186
187    /// Raw constructor for the C API.
188    pub fn from_raw(id: NonZeroU64) -> StoreId {
189        StoreId(id)
190    }
191}
192
193#[cold]
194fn store_id_mismatch() {
195    panic!("object used with the wrong store");
196}
197
198/// A type used to represent an allocated `vm::Instance` located within a store.
199///
200/// This type is held in various locations as a "safe index" into a store. This
201/// encapsulates a `StoreId` which owns the instance as well as the index within
202/// the store's list of which instance it's pointing to.
203///
204/// This type can notably be used to index into a `StoreOpaque` to project out
205/// the `vm::Instance` that is associated with this id.
206#[repr(C)] // used by reference in the C API
207#[derive(Copy, Clone, Debug, PartialEq, Eq)]
208pub struct StoreInstanceId {
209    store_id: StoreId,
210    instance: InstanceId,
211}
212
213impl StoreInstanceId {
214    pub(crate) fn new(store_id: StoreId, instance: InstanceId) -> StoreInstanceId {
215        StoreInstanceId { store_id, instance }
216    }
217
218    #[inline]
219    pub fn assert_belongs_to(&self, store: StoreId) {
220        self.store_id.assert_belongs_to(store)
221    }
222
223    #[inline]
224    pub fn store_id(&self) -> StoreId {
225        self.store_id
226    }
227
228    #[inline]
229    pub(crate) fn instance(&self) -> InstanceId {
230        self.instance
231    }
232}
233
234impl Index<StoreInstanceId> for StoreOpaque {
235    type Output = vm::Instance;
236
237    #[inline]
238    fn index(&self, id: StoreInstanceId) -> &Self::Output {
239        id.assert_belongs_to(self.id());
240        self.instance(id.instance).instance()
241    }
242}
243
244impl IndexMut<StoreInstanceId> for StoreOpaque {
245    #[inline]
246    fn index_mut(&mut self, id: StoreInstanceId) -> &mut Self::Output {
247        id.assert_belongs_to(self.id());
248        self.instance_mut(id.instance).instance_mut()
249    }
250}