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 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)] 14 pub struct InstanceId(pub(super) usize); 15 16 impl InstanceId { 17 pub fn from_index(idx: usize) -> InstanceId { 18 InstanceId(idx) 19 } 20 } 21 22 pub struct StoreData { 23 id: StoreId, 24 funcs: Vec<crate::func::FuncData>, 25 tables: Vec<crate::runtime::vm::ExportTable>, 26 globals: Vec<crate::runtime::vm::ExportGlobal>, 27 instances: Vec<crate::instance::InstanceData>, 28 memories: Vec<crate::runtime::vm::ExportMemory>, 29 tags: Vec<crate::runtime::vm::ExportTag>, 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 tags => crate::runtime::vm::ExportTag, 57 } 58 59 impl StoreData { 60 pub fn new() -> StoreData { 61 StoreData { 62 id: StoreId::allocate(), 63 funcs: Vec::new(), 64 tables: Vec::new(), 65 globals: Vec::new(), 66 instances: Vec::new(), 67 memories: Vec::new(), 68 tags: Vec::new(), 69 #[cfg(feature = "component-model")] 70 components: Default::default(), 71 } 72 } 73 74 pub fn id(&self) -> StoreId { 75 self.id 76 } 77 78 pub fn insert<T>(&mut self, data: T) -> Stored<T> 79 where 80 T: StoredData, 81 { 82 let list = T::list_mut(self); 83 let index = list.len(); 84 list.push(data); 85 Stored::new(self.id, index) 86 } 87 88 pub fn next_id<T>(&self) -> Stored<T> 89 where 90 T: StoredData, 91 { 92 Stored::new(self.id, T::list(self).len()) 93 } 94 95 pub fn contains<T>(&self, id: Stored<T>) -> bool 96 where 97 T: StoredData, 98 { 99 if id.store_id != self.id { 100 return false; 101 } 102 // This should be true as an invariant of our API, but double-check with 103 // debug assertions enabled. 104 debug_assert!(id.index() < T::list(self).len()); 105 true 106 } 107 108 pub fn iter<T>(&self) -> impl ExactSizeIterator<Item = Stored<T>> + use<T> 109 where 110 T: StoredData, 111 { 112 let id = self.id; 113 (0..T::list(self).len()).map(move |i| Stored::new(id, i)) 114 } 115 116 pub(crate) fn reserve_funcs(&mut self, count: usize) { 117 self.funcs.reserve(count); 118 } 119 } 120 121 impl<T> Index<Stored<T>> for StoreData 122 where 123 T: StoredData, 124 { 125 type Output = T; 126 127 #[inline] 128 fn index(&self, index: Stored<T>) -> &Self::Output { 129 index.assert_belongs_to(self.id); 130 // Note that if this is ever a performance bottleneck it should be safe 131 // to use unchecked indexing here because presence of a `Stored<T>` is 132 // proof of an item having been inserted into a store and lists in 133 // stores are never shrunk. After the store check above the actual index 134 // should always be valid. 135 &T::list(self)[index.index()] 136 } 137 } 138 139 impl<T> IndexMut<Stored<T>> for StoreData 140 where 141 T: StoredData, 142 { 143 #[inline] 144 fn index_mut(&mut self, index: Stored<T>) -> &mut Self::Output { 145 index.assert_belongs_to(self.id); 146 // Note that this could be unchecked indexing, see the note in `Index` 147 // above. 148 &mut T::list_mut(self)[index.index()] 149 } 150 } 151 152 // forward StoreContext => StoreData 153 impl<I, T> Index<I> for StoreContext<'_, T> 154 where 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 165 // forward StoreContextMut => StoreData 166 impl<I, T> Index<I> for StoreContextMut<'_, T> 167 where 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.0.store_data.index(index) 175 } 176 } 177 178 // forward StoreOpaque => StoreData 179 impl<I> Index<I> for StoreOpaque 180 where 181 StoreData: Index<I>, 182 { 183 type Output = <StoreData as Index<I>>::Output; 184 185 #[inline] 186 fn index(&self, index: I) -> &Self::Output { 187 self.store_data().index(index) 188 } 189 } 190 impl<I> IndexMut<I> for StoreOpaque 191 where 192 StoreData: IndexMut<I>, 193 { 194 #[inline] 195 fn index_mut(&mut self, index: I) -> &mut Self::Output { 196 self.store_data_mut().index_mut(index) 197 } 198 } 199 200 /// A unique identifier to get attached to a store. 201 /// 202 /// This identifier is embedded into the `Stored<T>` structure and is used to 203 /// identify the original store that items come from. For example a `Memory` is 204 /// owned by a `Store` and will embed a `StoreId` internally to say which store 205 /// it came from. Comparisons with this value are how panics are generated for 206 /// mismatching the item that a store belongs to. 207 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 208 #[repr(transparent)] // NB: relied on in the C API 209 pub struct StoreId(NonZeroU64); 210 211 impl StoreId { 212 /// Allocates a new unique identifier for a store that has never before been 213 /// used in this process. 214 pub fn allocate() -> StoreId { 215 // When 64-bit atomics are allowed then allow 2^63 stores at which point 216 // we start panicking to prevent 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 const OVERFLOW_THRESHOLD: u64 = 1 << 63; 221 222 #[cfg(target_has_atomic = "64")] 223 let id = { 224 use core::sync::atomic::{AtomicU64, Ordering::Relaxed}; 225 226 // Note the usage of `Relaxed` ordering here which should be ok 227 // since we're only looking for atomicity on this counter and this 228 // otherwise isn't used to synchronize memory stored anywhere else. 229 static NEXT_ID: AtomicU64 = AtomicU64::new(0); 230 let id = NEXT_ID.fetch_add(1, Relaxed); 231 if id > OVERFLOW_THRESHOLD { 232 NEXT_ID.store(OVERFLOW_THRESHOLD, Relaxed); 233 panic!("store id allocator overflow"); 234 } 235 id 236 }; 237 238 // When 64-bit atomics are not allowed use a `RwLock<u64>`. This is 239 // already used elsewhere in Wasmtime and currently has the 240 // implementation of panic-on-contention, but it's at least no worse 241 // than what wasmtime had before and is at least correct and UB-free. 242 #[cfg(not(target_has_atomic = "64"))] 243 let id = { 244 use crate::sync::RwLock; 245 static NEXT_ID: RwLock<u64> = RwLock::new(0); 246 247 let mut lock = NEXT_ID.write(); 248 if *lock > OVERFLOW_THRESHOLD { 249 panic!("store id allocator overflow"); 250 } 251 let ret = *lock; 252 *lock += 1; 253 ret 254 }; 255 256 StoreId(NonZeroU64::new(id + 1).unwrap()) 257 } 258 259 #[inline] 260 pub fn assert_belongs_to(&self, store: StoreId) { 261 if *self == store { 262 return; 263 } 264 store_id_mismatch(); 265 } 266 267 /// Raw accessor for the C API. 268 pub fn as_raw(&self) -> NonZeroU64 { 269 self.0 270 } 271 272 /// Raw constructor for the C API. 273 pub fn from_raw(id: NonZeroU64) -> StoreId { 274 StoreId(id) 275 } 276 } 277 278 #[repr(C)] // used by reference in the C API, also in `wasmtime_func_t`. 279 pub struct Stored<T> { 280 store_id: StoreId, 281 index: usize, 282 _marker: marker::PhantomData<fn() -> T>, 283 } 284 285 impl<T> Stored<T> { 286 fn new(store_id: StoreId, index: usize) -> Stored<T> { 287 Stored { 288 store_id, 289 index, 290 _marker: marker::PhantomData, 291 } 292 } 293 294 #[inline] 295 pub fn assert_belongs_to(&self, store: StoreId) { 296 self.store_id.assert_belongs_to(store) 297 } 298 299 fn index(&self) -> usize { 300 self.index 301 } 302 } 303 304 #[cold] 305 fn store_id_mismatch() { 306 panic!("object used with the wrong store"); 307 } 308 309 impl<T> PartialEq for Stored<T> { 310 fn eq(&self, other: &Stored<T>) -> bool { 311 self.store_id == other.store_id && self.index == other.index 312 } 313 } 314 315 impl<T> Copy for Stored<T> {} 316 317 impl<T> Clone for Stored<T> { 318 fn clone(&self) -> Self { 319 *self 320 } 321 } 322 323 impl<T> fmt::Debug for Stored<T> { 324 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 325 write!(f, "store={}, index={}", self.store_id.0, self.index()) 326 } 327 } 328