1 //! A very simple, uniformly-typed slab arena that supports deallocation and 2 //! reusing deallocated entries' space. 3 //! 4 //! > **⚠️ Warning ⚠️**: this crate is an internal-only crate for the Wasmtime 5 //! > project and is not intended for general use. APIs are not strictly 6 //! > reviewed for safety and usage outside of Wasmtime may have bugs. If 7 //! > you're interested in using this feel free to file an issue on the 8 //! > Wasmtime repository to start a discussion about doing so, but otherwise 9 //! > be aware that your usage of this crate is not supported. 10 //! 11 //! The free list of vacant entries in the slab are stored inline in the slab's 12 //! existing storage. 13 //! 14 //! # Example 15 //! 16 //! ``` 17 //! # fn foo() -> wasmtime_internal_core::error::Result<()> { 18 //! use wasmtime_internal_core::slab::Slab; 19 //! 20 //! let mut slab = Slab::new(); 21 //! 22 //! // Insert some values into the slab. 23 //! let rza = slab.alloc("Robert Fitzgerald Diggs")?; 24 //! let gza = slab.alloc("Gary Grice")?; 25 //! let bill = slab.alloc("Bill Gates")?; 26 //! 27 //! // Allocated elements can be accessed infallibly via indexing (and missing and 28 //! // deallocated entries will panic). 29 //! assert_eq!(slab[rza], "Robert Fitzgerald Diggs"); 30 //! 31 //! // Alternatively, the `get` and `get_mut` methods provide fallible lookup. 32 //! if let Some(genius) = slab.get(gza) { 33 //! println!("The gza gza genius: {}", genius); 34 //! } 35 //! if let Some(val) = slab.get_mut(bill) { 36 //! *val = "Bill Gates doesn't belong in this set..."; 37 //! } 38 //! 39 //! // We can remove values from the slab. 40 //! slab.dealloc(bill); 41 //! 42 //! // Allocate a new entry. 43 //! let bill = slab.alloc("Bill Murray")?; 44 //! # Ok(()) 45 //! # } 46 //! # foo().unwrap(); 47 //! ``` 48 //! 49 //! # Using `Id`s with the Wrong `Slab` 50 //! 51 //! `Slab` does NOT check that `Id`s used to access previously-allocated values 52 //! came from the current `Slab` instance (as opposed to a different `Slab` 53 //! instance). Using `Id`s from a different `Slab` is safe, but will yield an 54 //! unrelated value, if any at all. 55 //! 56 //! If you desire checking that an `Id` came from the correct `Slab` instance, 57 //! it should be easy to layer that functionality on top of this crate by 58 //! wrapping `Slab` and `Id` in types that additionally maintain a slab instance 59 //! identifier. 60 //! 61 //! # The ABA Problem 62 //! 63 //! This `Slab` type does NOT protect against ABA bugs, such as the following 64 //! sequence: 65 //! 66 //! * Value `A` is allocated into the slab, yielding id `i`. 67 //! 68 //! * `A` is deallocated, and so `i`'s associated entry is added to the slab's 69 //! free list. 70 //! 71 //! * Value `B` is allocated into the slab, reusing `i`'s associated entry, 72 //! yielding id `i`. 73 //! 74 //! * The "original" id `i` is used to access the arena, expecting the 75 //! deallocated value `A`, but getting the new value `B`. 76 //! 77 //! That is, it does not detect and prevent against the memory-safe version of 78 //! use-after-free bugs. 79 //! 80 //! If you need to protect against ABA bugs, it should be easy to layer that 81 //! functionality on top of this crate by wrapping `Slab` with something like 82 //! the following: 83 //! 84 //! ```rust 85 //! use wasmtime_internal_core::error::OutOfMemory; 86 //! 87 //! pub struct GenerationalId { 88 //! id: wasmtime_internal_core::slab::Id, 89 //! generation: u32, 90 //! } 91 //! 92 //! struct GenerationalEntry<T> { 93 //! value: T, 94 //! generation: u32, 95 //! } 96 //! 97 //! pub struct GenerationalSlab<T> { 98 //! slab: wasmtime_internal_core::slab::Slab<GenerationalEntry<T>>, 99 //! generation: u32, 100 //! } 101 //! 102 //! impl<T> GenerationalSlab<T> { 103 //! pub fn alloc(&mut self, value: T) -> Result<GenerationalId, OutOfMemory> { 104 //! let generation = self.generation; 105 //! let id = self.slab.alloc(GenerationalEntry { value, generation })?; 106 //! Ok(GenerationalId { id, generation }) 107 //! } 108 //! 109 //! pub fn get(&self, id: GenerationalId) -> Option<&T> { 110 //! let entry = self.slab.get(id.id)?; 111 //! 112 //! // Check that the entry's generation matches the id's generation, 113 //! // else we have an ABA bug. (Alternatively, return `None` instead 114 //! // of panicking.) 115 //! assert_eq!(id.generation, entry.generation); 116 //! 117 //! Some(&entry.value) 118 //! } 119 //! 120 //! pub fn dealloc(&mut self, id: GenerationalId) { 121 //! // Check that the entry's generation matches the id's generation, 122 //! // else we have an ABA bug. (Alternatively, silently return on 123 //! // double-free instead of panicking.) 124 //! assert_eq!(id.generation, self.slab[id.id].generation); 125 //! 126 //! self.slab.dealloc(id.id); 127 //! 128 //! // Increment our generation whenever we deallocate so that any new 129 //! // value placed in this same entry will have a different generation 130 //! // and we can detect ABA bugs. 131 //! self.generation += 1; 132 //! } 133 //! } 134 //! ``` 135 136 use crate::alloc::TryVec; 137 use crate::error::OutOfMemory; 138 use core::fmt; 139 use core::num::NonZeroU32; 140 141 /// An identifier for an allocated value inside a `slab`. 142 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 143 #[repr(transparent)] 144 pub struct Id(EntryIndex); 145 146 impl fmt::Debug for Id { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result147 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 148 f.debug_tuple("Id").field(&self.0.index()).finish() 149 } 150 } 151 152 impl Id { 153 /// Get the raw underlying representation of this `Id`. 154 #[inline] into_raw(self) -> u32155 pub fn into_raw(self) -> u32 { 156 u32::try_from(self.0.index()).unwrap() 157 } 158 159 /// Construct an `Id` from its raw underlying representation. 160 /// 161 /// `raw` should be a value that was previously created via 162 /// `Id::into_raw`. May panic if given arbitrary values. 163 #[inline] from_raw(raw: u32) -> Self164 pub fn from_raw(raw: u32) -> Self { 165 let raw = usize::try_from(raw).unwrap(); 166 Self(EntryIndex::new(raw)) 167 } 168 } 169 170 /// A simple, uni-typed slab arena. 171 pub struct Slab<T> { 172 /// The slab's entries, each is either occupied and holding a `T` or vacant 173 /// and is a link the free list. 174 entries: TryVec<Entry<T>>, 175 176 /// The index of the first free entry in the free list. 177 free: Option<EntryIndex>, 178 179 /// The number of occupied entries is this slab. 180 len: u32, 181 } 182 183 impl<T> fmt::Debug for Slab<T> 184 where 185 T: fmt::Debug, 186 { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 188 f.debug_map().entries(self.iter()).finish() 189 } 190 } 191 192 enum Entry<T> { 193 /// An occupied entry holding a `T`. 194 Occupied(T), 195 196 /// A vacant entry. 197 Free { 198 /// A link in the slab's free list, pointing to the next free entry, if 199 /// any. 200 next_free: Option<EntryIndex>, 201 }, 202 } 203 204 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 205 #[repr(transparent)] 206 struct EntryIndex(NonZeroU32); 207 208 impl EntryIndex { 209 #[inline] new(index: usize) -> Self210 fn new(index: usize) -> Self { 211 assert!(index <= Slab::<()>::MAX_CAPACITY); 212 let x = u32::try_from(index + 1).unwrap(); 213 Self(NonZeroU32::new(x).unwrap()) 214 } 215 216 #[inline] index(&self) -> usize217 fn index(&self) -> usize { 218 let index = self.0.get() - 1; 219 usize::try_from(index).unwrap() 220 } 221 } 222 223 impl<T> Default for Slab<T> { 224 #[inline] default() -> Self225 fn default() -> Self { 226 Self { 227 entries: TryVec::default(), 228 free: None, 229 len: 0, 230 } 231 } 232 } 233 234 impl<T> core::ops::Index<Id> for Slab<T> { 235 type Output = T; 236 237 #[inline] index(&self, id: Id) -> &Self::Output238 fn index(&self, id: Id) -> &Self::Output { 239 self.get(id) 240 .expect("id from different slab or value was deallocated") 241 } 242 } 243 244 impl<T> core::ops::IndexMut<Id> for Slab<T> { 245 #[inline] index_mut(&mut self, id: Id) -> &mut Self::Output246 fn index_mut(&mut self, id: Id) -> &mut Self::Output { 247 self.get_mut(id) 248 .expect("id from different slab or value was deallocated") 249 } 250 } 251 252 impl<T> Slab<T> { 253 /// The maximum capacity any `Slab` can have: `u32::MAX - 1`. 254 pub const MAX_CAPACITY: usize = (u32::MAX - 1) as usize; 255 256 /// Construct a new, empty slab. 257 #[inline] new() -> Self258 pub fn new() -> Self { 259 Slab::default() 260 } 261 262 /// Construct a new, empty slab, pre-reserving space for at least `capacity` 263 /// elements. 264 #[inline] with_capacity(capacity: usize) -> Result<Self, OutOfMemory>265 pub fn with_capacity(capacity: usize) -> Result<Self, OutOfMemory> { 266 let mut slab = Self::new(); 267 slab.reserve(capacity)?; 268 Ok(slab) 269 } 270 271 /// Ensure that there is space for at least `additional` elements in this 272 /// slab. 273 /// 274 /// # Panics 275 /// 276 /// Panics if the new capacity exceeds `Self::MAX_CAPACITY`. reserve(&mut self, additional: usize) -> Result<(), OutOfMemory>277 pub fn reserve(&mut self, additional: usize) -> Result<(), OutOfMemory> { 278 let cap = self.capacity(); 279 let len = self.len(); 280 assert!(cap >= len); 281 if cap - len >= additional { 282 // Already have `additional` capacity available. 283 return Ok(()); 284 } 285 286 self.entries.reserve(additional)?; 287 288 // Maintain the invariant that `i <= MAX_CAPACITY` for all indices `i` 289 // in `self.entries`. 290 assert!(self.entries.capacity() <= Self::MAX_CAPACITY); 291 292 Ok(()) 293 } 294 double_capacity(&mut self) -> Result<(), OutOfMemory>295 fn double_capacity(&mut self) -> Result<(), OutOfMemory> { 296 // Double our capacity to amortize the cost of resizing. But make sure 297 // we add some amount of minimum additional capacity, since doubling 298 // zero capacity isn't useful. 299 const MIN_CAPACITY: usize = 16; 300 let additional = core::cmp::max(self.entries.capacity(), MIN_CAPACITY); 301 self.reserve(additional) 302 } 303 304 /// What is the capacity of this slab? That is, how many entries can it 305 /// contain within its current underlying storage? 306 #[inline] capacity(&self) -> usize307 pub fn capacity(&self) -> usize { 308 self.entries.capacity() 309 } 310 311 /// How many values are currently allocated within this slab? 312 #[inline] len(&self) -> usize313 pub fn len(&self) -> usize { 314 usize::try_from(self.len).unwrap() 315 } 316 317 /// Are there zero allocated values within this slab? 318 #[inline] is_empty(&self) -> bool319 pub fn is_empty(&self) -> bool { 320 self.len() == 0 321 } 322 323 /// Try to allocate a `T` value within this slab. 324 /// 325 /// If there is no available capacity, ownership of the given value is 326 /// returned via `Err(value)`. 327 #[inline] try_alloc(&mut self, value: T) -> Result<Id, T>328 pub fn try_alloc(&mut self, value: T) -> Result<Id, T> { 329 if let Some(index) = self.try_alloc_index() { 330 let next_free = match self.entries[index.index()] { 331 Entry::Free { next_free } => next_free, 332 Entry::Occupied { .. } => unreachable!(), 333 }; 334 self.free = next_free; 335 self.entries[index.index()] = Entry::Occupied(value); 336 self.len += 1; 337 Ok(Id(index)) 338 } else { 339 Err(value) 340 } 341 } 342 343 #[inline] try_alloc_index(&mut self) -> Option<EntryIndex>344 fn try_alloc_index(&mut self) -> Option<EntryIndex> { 345 self.free.take().or_else(|| { 346 if self.entries.len() < self.entries.capacity() { 347 let index = EntryIndex::new(self.entries.len()); 348 self.entries 349 .push(Entry::Free { next_free: None }) 350 .expect("have capacity"); 351 Some(index) 352 } else { 353 None 354 } 355 }) 356 } 357 358 /// Allocate a `T` value within this slab, allocating additional underlying 359 /// storage if there is no available capacity. 360 /// 361 /// # Panics 362 /// 363 /// Panics if allocating this value requires reallocating the underlying 364 /// storage, and the new capacity exceeds `Slab::MAX_CAPACITY`. 365 #[inline] alloc(&mut self, value: T) -> Result<Id, OutOfMemory>366 pub fn alloc(&mut self, value: T) -> Result<Id, OutOfMemory> { 367 self.try_alloc(value) 368 .or_else(|value| self.alloc_slow(value)) 369 } 370 371 /// Get the `Id` that will be returned for the next allocation in this slab. 372 #[inline] next_id(&self) -> Id373 pub fn next_id(&self) -> Id { 374 let index = self.free.unwrap_or_else(|| EntryIndex::new(self.len())); 375 Id(index) 376 } 377 378 #[inline(never)] 379 #[cold] alloc_slow(&mut self, value: T) -> Result<Id, OutOfMemory>380 fn alloc_slow(&mut self, value: T) -> Result<Id, OutOfMemory> { 381 // Reserve additional capacity, since we didn't have space for the 382 // allocation. 383 self.double_capacity()?; 384 // After which the allocation will succeed. 385 let id = self.try_alloc(value).ok().unwrap(); 386 Ok(id) 387 } 388 389 /// Get a shared borrow of the value associated with `id`. 390 /// 391 /// Returns `None` if the value has since been deallocated. 392 /// 393 /// If `id` comes from a different `Slab` instance, this method may panic, 394 /// return `None`, or return an arbitrary value. 395 #[inline] get(&self, id: Id) -> Option<&T>396 pub fn get(&self, id: Id) -> Option<&T> { 397 match self 398 .entries 399 .get(id.0.index()) 400 .expect("id from different slab") 401 { 402 Entry::Occupied(x) => Some(x), 403 Entry::Free { .. } => None, 404 } 405 } 406 407 /// Get an exclusive borrow of the value associated with `id`. 408 /// 409 /// Returns `None` if the value has since been deallocated. 410 /// 411 /// If `id` comes from a different `Slab` instance, this method may panic, 412 /// return `None`, or return an arbitrary value. 413 #[inline] get_mut(&mut self, id: Id) -> Option<&mut T>414 pub fn get_mut(&mut self, id: Id) -> Option<&mut T> { 415 match self 416 .entries 417 .get_mut(id.0.index()) 418 .expect("id from different slab") 419 { 420 Entry::Occupied(x) => Some(x), 421 Entry::Free { .. } => None, 422 } 423 } 424 425 /// Does this slab contain an allocated value for `id`? 426 #[inline] contains(&self, id: Id) -> bool427 pub fn contains(&self, id: Id) -> bool { 428 match self.entries.get(id.0.index()) { 429 Some(Entry::Occupied(_)) => true, 430 None | Some(Entry::Free { .. }) => false, 431 } 432 } 433 434 /// Deallocate the value associated with the given `id`. 435 /// 436 /// If `id` comes from a different `Slab` instance, this method may panic or 437 /// deallocate an arbitrary value. 438 #[inline] dealloc(&mut self, id: Id) -> T439 pub fn dealloc(&mut self, id: Id) -> T { 440 let entry = core::mem::replace( 441 self.entries 442 .get_mut(id.0.index()) 443 .expect("id from a different slab"), 444 Entry::Free { next_free: None }, 445 ); 446 match entry { 447 Entry::Free { .. } => panic!("attempt to deallocate an entry that is already vacant"), 448 Entry::Occupied(value) => { 449 let next_free = core::mem::replace(&mut self.free, Some(id.0)); 450 self.entries[id.0.index()] = Entry::Free { next_free }; 451 self.len -= 1; 452 value 453 } 454 } 455 } 456 457 /// Iterate over all values currently allocated within this `Slab`. 458 /// 459 /// Yields pairs of an `Id` and the `Id`'s associated value. 460 /// 461 /// Iteration order is undefined. 462 #[inline] iter(&self) -> impl Iterator<Item = (Id, &T)> + '_463 pub fn iter(&self) -> impl Iterator<Item = (Id, &T)> + '_ { 464 assert!(self.entries.len() <= Self::MAX_CAPACITY); 465 self.entries 466 .iter() 467 .enumerate() 468 .filter_map(|(i, e)| match e { 469 Entry::Occupied(x) => Some((Id(EntryIndex::new(i)), x)), 470 Entry::Free { .. } => None, 471 }) 472 } 473 474 /// Mutably iterate over all values currently allocated within this `Slab`. 475 /// 476 /// Yields pairs of an `Id` and the `Id`'s associated value. 477 /// 478 /// Iteration order is undefined. 479 #[inline] iter_mut(&mut self) -> impl Iterator<Item = (Id, &mut T)> + '_480 pub fn iter_mut(&mut self) -> impl Iterator<Item = (Id, &mut T)> + '_ { 481 assert!(self.entries.len() <= Self::MAX_CAPACITY); 482 self.entries 483 .iter_mut() 484 .enumerate() 485 .filter_map(|(i, e)| match e { 486 Entry::Occupied(x) => Some((Id(EntryIndex::new(i)), x)), 487 Entry::Free { .. } => None, 488 }) 489 } 490 491 /// Iterate over and remove all entries in this slab. 492 /// 493 /// The slab will be empty after calling this method. 494 /// 495 /// Yields pairs of an `Id` and the `Id`'s associated value. 496 /// 497 /// Iteration order is undefined. 498 #[inline] drain(&mut self) -> impl Iterator<Item = (Id, T)> + '_499 pub fn drain(&mut self) -> impl Iterator<Item = (Id, T)> + '_ { 500 assert!(self.entries.len() <= Self::MAX_CAPACITY); 501 self.len = 0; 502 self.free = None; 503 self.entries 504 .drain(..) 505 .enumerate() 506 .filter_map(|(i, e)| match e { 507 Entry::Occupied(x) => Some((Id(EntryIndex::new(i)), x)), 508 Entry::Free { .. } => None, 509 }) 510 } 511 512 /// Clear all of the values from inside this slab. 513 /// 514 /// Does not deallocate internal storage. 515 #[inline] clear(&mut self)516 pub fn clear(&mut self) { 517 self.len = 0; 518 self.free = None; 519 self.entries.clear(); 520 } 521 } 522