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