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