wasmtime/runtime/gc/enabled/rooting.rs
1//! Garbage collection rooting APIs.
2//!
3//! Rooting prevents GC objects from being collected while they are actively
4//! being used.
5//!
6//! ## Goals
7//!
8//! We have a few sometimes-conflicting goals with our GC rooting APIs:
9//!
10//! 1. Safety: It should never be possible to get a use-after-free bug because
11//! the user misused the rooting APIs, the collector "mistakenly" determined
12//! an object was unreachable and collected it, and then the user tried to
13//! access the object. This is our highest priority.
14//!
15//! 2. Moving GC: Our rooting APIs should moving collectors (such as
16//! generational and compacting collectors) where an object might get
17//! relocated after a collection and we need to update the GC root's pointer
18//! to the moved object. This means we either need cooperation and internal
19//! mutability from individual GC roots as well as the ability to enumerate
20//! all GC roots on the native Rust stack, or we need a level of indirection.
21//!
22//! 3. Performance: Our rooting APIs should generally be as low-overhead as
23//! possible. They definitely shouldn't require synchronization and locking
24//! to create, access, and drop GC roots.
25//!
26//! 4. Ergonomics: Our rooting APIs should be, if not a pleasure, then at least
27//! not a burden for users. Additionally, the API's types should be `Sync`
28//! and `Send` so that they work well with async Rust.
29//!
30//! The two main design axes that trade off the above goals are:
31//!
32//! - Where the GC reference itself is held. A root object could
33//! directly hold the underlying GC reference (offset into the GC
34//! storage area), which would allow more efficient dereferencing
35//! and access to the referred-to GC object. However, goal (2)
36//! requires that the GC is able to update references when objects
37//! move during a GC. Thus, such "direct roots" would need to be
38//! registered somehow in a global root registry, and would need to
39//! unregister themselves when dropped.
40//!
41//! The alternative is to hold some indirect kind of reference to a
42//! GC reference, with the latter stored directly in the `Store` so
43//! the GC can update it freely. This adds one pointer-chasing hop
44//! to accesses, but works much more nicely with ownership
45//! semantics. Logically, the `Store` "owns" the actual pointers;
46//! and rooting types own the slots that they are stored in.
47//!
48//! For the above reasons, all of our rooting types below use
49//! indirection. This avoids the need for an unsafe
50//! intrusive-linked-list for global registration, or a shared
51//! reference to a mutex-protected registry, or some other
52//! error-prone technique.
53//!
54//! - How unrooting occurs. Ideally, a rooting type would implement
55//! the Rust `Drop` trait and unroot itself when the Rust value is
56//! dropped. However, because the rooting state is held in the
57//! `Store`, this direct approach would imply keeping a shared,
58//! mutex-protected handle to the registry in every rooting
59//! object. This would add synchronization overhead to the common
60//! case, and in general would be a bad tradeoff.
61//!
62//! However, there are several other approaches:
63//!
64//! - The user could use an RAII wrapper that *does* own the `Store`,
65//! and defines a "scope" in which roots are created and then
66//! bulk-unrooted at the close of the scope.
67//! - The rooting type could hold a shared reference to some state
68//! *other* than the full registry, and update a flag in that
69//! state indicating it has been dropped; the `Store` could then
70//! later observe that flag and remove the root. This would have
71//! some allocation cost, but the shared state would be
72//! independent of the `Store` and specific to each root, so would
73//! impose no synchronization overhead between different roots or
74//! the GC itself.
75//! - The rooting type could provide a fully manual `unroot` method,
76//! allowing the user to make use of their own knowledge of their
77//! application's lifetimes and semantics and remove roots when
78//! appropriate.
79//!
80//! We provide an implementation of the first two of these
81//! strategies below in `Rooted` and `OwnedRooted`. The last, fully
82//! manual, approach is too difficult to use correctly (it cannot
83//! implement Rust's `Drop` trait, but there is no way in Rust to
84//! enforce that a value must be consumed rather than dropped) so it
85//! is not implemented.
86//!
87//! ## Two Flavors of Rooting API
88//!
89//! Okay, with that out of the way, this module provides two flavors
90//! of rooting API. One for the common, scoped lifetime case, and one that
91//! carries ownership until dropped, and can work as an RAII handle
92//! that interacts well with Rust ownership semantics (but at a minor
93//! performance cost):
94//!
95//! 1. `RootScope` and `Rooted<T>`: These are used for temporarily rooting GC
96//! objects for the duration of a scope. The internal implementation takes
97//! advantage of the LIFO property inherent in scopes, making creating and
98//! dropping `Rooted<T>`s and `RootScope`s super fast and roughly equivalent
99//! to bump allocation.
100//!
101//! This type is vaguely similar to V8's [`HandleScope`].
102//!
103//! [`HandleScope`]: https://v8.github.io/api/head/classv8_1_1HandleScope.html
104//!
105//! Note that `Rooted<T>` can't be statically tied to its context scope via a
106//! lifetime parameter, unfortunately, as that would allow the creation of
107//! only one `Rooted<T>` at a time, since the `Rooted<T>` would take a borrow
108//! of the whole context.
109//!
110//! This supports the common use case for rooting and provides good
111//! ergonomics.
112//!
113//! 2. `OwnedRooted<T>`: This is a root that manages rooting and
114//! unrooting automatically with its lifetime as a Rust value. In
115//! other words, the continued existence of the Rust value ensures
116//! the rooting of the underlying GC reference; and when the Rust
117//! value is dropped, the underlying GC reference is no longer
118//! rooted.
119//!
120//! Internally, this root holds a shared reference to a
121//! *root-specific* bit of state that is also tracked and observed
122//! by the `Store`. This means that there is minor memory
123//! allocation overhead (an `Arc<()>`) for each such root; this
124//! memory is shared over all clones of this root. The rooted GC
125//! reference is *logically* unrooted as soon as the last clone of
126//! this root is dropped. Internally the root may still exist until
127//! the next GC, or "root trim" when another `OwnedRooted` is
128//! created, but that is unobservable externally, and will not
129//! result in any additional GC object lifetime because it is
130//! always cleaned up before a gc.
131//!
132//! This type is roughly similar to SpiderMonkey's [`PersistentRooted<T>`],
133//! although they register roots on a per-thread `JSContext`, avoiding
134//! mutation costs in a way that is not viable for Wasmtime (which needs
135//! `Store`s to be `Send`).
136//!
137//! [`PersistentRooted<T>`]: http://devdoc.net/web/developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_reference/JS::PersistentRooted.html
138//!
139//! At the end of the day, all of the above root types are just tagged
140//! indices into the store's `RootSet`. This indirection allows
141//! working with Rust's borrowing discipline (we use `&mut Store` to
142//! represent mutable access to the GC heap) while still allowing
143//! rooted references to be moved around without tying up the whole
144//! store in borrows. Additionally, and crucially, this indirection
145//! allows us to update the *actual* GC pointers in the `RootSet` and
146//! support moving GCs (again, as mentioned above).
147//!
148//! ## Unrooted References
149//!
150//! We generally don't expose *unrooted* GC references in the Wasmtime API at
151//! this time -- and I expect it will be a very long time before we do, but in
152//! the limit we may want to let users define their own GC-managed types that
153//! participate in GC tracing and all that -- so we don't have to worry about
154//! failure to root an object causing use-after-free bugs or failing to update a
155//! GC root pointer after a moving GC as long as users stick to our safe rooting
156//! APIs. (The one exception is `ValRaw`, which does hold raw GC references. But
157//! with `ValRaw` all bets are off and safety is 100% up to the user.)
158//!
159//! We do, however, have to worry about these things internally. So first of
160//! all, try to avoid ever working with unrooted GC references if you
161//! can. However, if you really must, consider also using an `AutoAssertNoGc`
162//! across the block of code that is manipulating raw GC references.
163
164use crate::runtime::vm::{GcRootsList, GcStore, VMGcRef};
165use crate::{
166 AsContext, AsContextMut, GcRef, Result, RootedGcRef,
167 error::OutOfMemory,
168 store::{AsStoreOpaque, AutoAssertNoGc, StoreId, StoreOpaque},
169};
170use crate::{ValRaw, prelude::*};
171use alloc::sync::{Arc, Weak};
172use core::any;
173use core::marker;
174use core::mem::{self, MaybeUninit};
175use core::num::{NonZeroU32, NonZeroU64, NonZeroUsize};
176use core::{
177 fmt::{self, Debug},
178 hash::{Hash, Hasher},
179 ops::{Deref, DerefMut},
180};
181use wasmtime_core::slab::{Id as SlabId, Slab};
182
183mod sealed {
184 use super::*;
185
186 /// Sealed, `wasmtime`-internal trait for GC references.
187 ///
188 /// # Safety
189 ///
190 /// All types implementing this trait must:
191 ///
192 /// * Be a newtype of a `GcRootIndex`
193 ///
194 /// * Not implement `Copy` or `Clone`
195 ///
196 /// * Only have `&self` methods.
197 pub unsafe trait GcRefImpl: Sized {
198 /// Transmute a `&GcRootIndex` into an `&Self`.
199 fn transmute_ref(index: &GcRootIndex) -> &Self;
200 }
201
202 /// Sealed, `wasmtime`-internal trait for the common methods on rooted GC
203 /// references.
204 pub trait RootedGcRefImpl<T: GcRef> {
205 /// Get this rooted GC reference's raw `VMGcRef` out of the store's GC
206 /// root set.
207 ///
208 /// Returns `None` for objects that have since been unrooted (eg because
209 /// its associated `RootedScope` was dropped).
210 ///
211 /// Panics if this root is not associated with the given store.
212 fn get_gc_ref<'a>(&self, store: &'a StoreOpaque) -> Option<&'a VMGcRef>;
213
214 /// Same as `get_gc_ref` but returns an error instead of `None` for
215 /// objects that have been unrooted.
216 fn try_gc_ref<'a>(&self, store: &'a StoreOpaque) -> Result<&'a VMGcRef> {
217 self.get_gc_ref(store).ok_or_else(|| {
218 format_err!("attempted to use a garbage-collected object that has been unrooted")
219 })
220 }
221
222 /// Get a clone of this rooted GC reference's raw `VMGcRef` out of the
223 /// store's GC root set.
224 ///
225 /// Returns `None` for objects that have since been unrooted (eg because
226 /// its associated `RootedScope` was dropped).
227 ///
228 /// Panics if this root is not associated with the given store.
229 fn clone_gc_ref(&self, store: &mut AutoAssertNoGc<'_>) -> Option<VMGcRef> {
230 let gc_ref = self.get_gc_ref(store)?.unchecked_copy();
231 Some(store.clone_gc_ref(&gc_ref))
232 }
233
234 /// Same as `clone_gc_ref` but returns an error instead of `None` for
235 /// objects that have been unrooted.
236 fn try_clone_gc_ref(&self, store: &mut AutoAssertNoGc<'_>) -> Result<VMGcRef> {
237 let gc_ref = self.try_gc_ref(store)?.unchecked_copy();
238 Ok(store.clone_gc_ref(&gc_ref))
239 }
240 }
241}
242pub(crate) use sealed::*;
243
244/// The index of a GC root inside a particular store's GC root set.
245///
246/// Can be either a LIFO- or owned-rooted object, depending on the
247/// `PackedIndex`.
248///
249/// Every `T` such that `T: GcRef` must be a newtype over this `GcRootIndex`.
250#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
251// Just `pub` to avoid `warn(private_interfaces)` in public APIs, which we can't
252// `allow(...)` on our MSRV yet.
253#[doc(hidden)]
254#[repr(C)] // NB: if this layout changes be sure to change the C API as well
255pub struct GcRootIndex {
256 store_id: StoreId,
257 generation: u32,
258 index: PackedIndex,
259}
260
261const _: () = {
262 // NB: these match the C API which should also be updated if this changes
263 assert!(mem::size_of::<GcRootIndex>() == 16);
264 assert!(mem::align_of::<GcRootIndex>() == mem::align_of::<u64>());
265};
266
267impl GcRootIndex {
268 #[inline]
269 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
270 self.store_id == store.id()
271 }
272
273 /// Same as `RootedGcRefImpl::get_gc_ref` but not associated with any
274 /// particular `T: GcRef`.
275 ///
276 /// We must avoid triggering a GC while holding onto the resulting raw
277 /// `VMGcRef` to avoid use-after-free bugs and similar. The `'a` lifetime
278 /// threaded from the `store` to the result will normally prevent GCs
279 /// statically, at compile time, since performing a GC requires a mutable
280 /// borrow of the store. However, if you call `VMGcRef::unchecked_copy` on
281 /// the resulting GC reference, then all bets are off and this invariant is
282 /// up to you to manually uphold. Failure to uphold this invariant is memory
283 /// safe but will lead to general incorrectness such as panics and wrong
284 /// results.
285 ///
286 /// # Panics
287 ///
288 /// Panics if `self` is not associated with the given store.
289 pub(crate) fn get_gc_ref<'a>(&self, store: &'a StoreOpaque) -> Option<&'a VMGcRef> {
290 assert!(
291 self.comes_from_same_store(store),
292 "object used with wrong store"
293 );
294 if let Some(index) = self.index.as_lifo() {
295 let entry = store.gc_roots().lifo_roots.get(index)?;
296 if entry.generation == self.generation {
297 Some(&entry.gc_ref)
298 } else {
299 None
300 }
301 } else if let Some(id) = self.index.as_owned() {
302 let gc_ref = store.gc_roots().owned_rooted.get(id);
303 debug_assert!(gc_ref.is_some());
304 gc_ref
305 } else {
306 unreachable!()
307 }
308 }
309
310 /// Same as `get_gc_ref` but returns an error instead of `None` if
311 /// the GC reference has been unrooted.
312 ///
313 /// # Panics
314 ///
315 /// Panics if `self` is not associated with the given store.
316 pub(crate) fn try_gc_ref<'a>(&self, store: &'a StoreOpaque) -> Result<&'a VMGcRef> {
317 self.get_gc_ref(store).ok_or_else(|| {
318 format_err!("attempted to use a garbage-collected object that has been unrooted")
319 })
320 }
321
322 /// Same as `RootedGcRefImpl::clone_gc_ref` but not associated with any
323 /// particular `T: GcRef`.
324 pub(crate) fn try_clone_gc_ref(&self, store: &mut AutoAssertNoGc<'_>) -> Result<VMGcRef> {
325 let gc_ref = self.try_gc_ref(store)?.unchecked_copy();
326 Ok(store.clone_gc_ref(&gc_ref))
327 }
328
329 /// Exposes this value's raw `VMGcRef` to wasm as a `u32`.
330 pub(crate) fn expose_gc_ref_to_wasm(
331 &self,
332 store: &mut AutoAssertNoGc<'_>,
333 ) -> Result<NonZeroU32> {
334 let gc_ref = self.try_clone_gc_ref(store)?;
335
336 let raw = match store.optional_gc_store_mut() {
337 Some(s) => s.expose_gc_ref_to_wasm(gc_ref)?,
338 None => {
339 // NB: do not force the allocation of a GC heap just because the
340 // program is using `i31ref`s.
341 debug_assert!(gc_ref.is_i31());
342 gc_ref.as_raw_non_zero_u32()
343 }
344 };
345
346 Ok(raw)
347 }
348}
349
350/// This is a bit-packed version of
351///
352/// ```ignore
353/// enum {
354/// Lifo(usize),
355/// Owned(SlabId),
356/// }
357/// ```
358///
359/// where the high bit is the discriminant and the lower 31 bits are the
360/// payload.
361#[derive(Clone, Copy, PartialEq, Eq, Hash)]
362#[repr(transparent)]
363struct PackedIndex(u32);
364
365impl Debug for PackedIndex {
366 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
367 if let Some(index) = self.as_lifo() {
368 f.debug_tuple("PackedIndex::Lifo").field(&index).finish()
369 } else if let Some(id) = self.as_owned() {
370 f.debug_tuple("PackedIndex::Owned").field(&id).finish()
371 } else {
372 unreachable!()
373 }
374 }
375}
376
377impl PackedIndex {
378 const DISCRIMINANT_MASK: u32 = 0b1 << 31;
379 const LIFO_DISCRIMINANT: u32 = 0b0 << 31;
380 const OWNED_DISCRIMINANT: u32 = 0b1 << 31;
381 const PAYLOAD_MASK: u32 = !Self::DISCRIMINANT_MASK;
382
383 fn new_lifo(index: usize) -> PackedIndex {
384 let index32 = u32::try_from(index).unwrap();
385 assert_eq!(index32 & Self::DISCRIMINANT_MASK, 0);
386 let packed = PackedIndex(Self::LIFO_DISCRIMINANT | index32);
387 debug_assert!(packed.is_lifo());
388 debug_assert_eq!(packed.as_lifo(), Some(index));
389 debug_assert!(!packed.is_owned());
390 debug_assert!(packed.as_owned().is_none());
391 packed
392 }
393
394 fn new_owned(id: SlabId) -> PackedIndex {
395 let raw = id.into_raw();
396 assert_eq!(raw & Self::DISCRIMINANT_MASK, 0);
397 let packed = PackedIndex(Self::OWNED_DISCRIMINANT | raw);
398 debug_assert!(packed.is_owned());
399 debug_assert_eq!(packed.as_owned(), Some(id));
400 debug_assert!(!packed.is_lifo());
401 debug_assert!(packed.as_lifo().is_none());
402 packed
403 }
404
405 fn discriminant(&self) -> u32 {
406 self.0 & Self::DISCRIMINANT_MASK
407 }
408
409 fn is_lifo(&self) -> bool {
410 self.discriminant() == Self::LIFO_DISCRIMINANT
411 }
412
413 fn is_owned(&self) -> bool {
414 self.discriminant() == Self::OWNED_DISCRIMINANT
415 }
416
417 fn payload(&self) -> u32 {
418 self.0 & Self::PAYLOAD_MASK
419 }
420
421 fn as_lifo(&self) -> Option<usize> {
422 if self.is_lifo() {
423 Some(usize::try_from(self.payload()).unwrap())
424 } else {
425 None
426 }
427 }
428
429 fn as_owned(&self) -> Option<SlabId> {
430 if self.is_owned() {
431 Some(SlabId::try_from_raw(self.payload()).unwrap())
432 } else {
433 None
434 }
435 }
436}
437
438/// The set of all embedder-API GC roots in a single store/heap.
439#[derive(Debug, Default)]
440pub(crate) struct RootSet {
441 /// GC roots with arbitrary lifetime that are unrooted when
442 /// liveness flags are cleared (seen during a trimming pass), for
443 /// use with `OwnedRooted<T>`.
444 owned_rooted: Slab<VMGcRef>,
445
446 /// List of liveness flags and corresponding `SlabId`s into the
447 /// `owned_rooted` slab.
448 liveness_flags: Vec<(Weak<()>, SlabId)>,
449
450 /// High-water mark for liveness flag trimming. We use this to
451 /// ensure we have amortized constant-time behavior on adding
452 /// roots. See note below on `trim_liveness_flags()`.
453 liveness_trim_high_water: Option<NonZeroUsize>,
454
455 /// Strictly LIFO-ordered GC roots, for use with `RootScope` and
456 /// `Rooted<T>`.
457 lifo_roots: Vec<LifoRoot>,
458
459 /// Generation counter for entries to prevent ABA bugs with `RootScope` and
460 /// `Rooted<T>`.
461 lifo_generation: u32,
462}
463
464#[derive(Debug)]
465struct LifoRoot {
466 generation: u32,
467 gc_ref: VMGcRef,
468}
469
470impl RootSet {
471 pub(crate) fn trace_roots(&mut self, gc_roots_list: &mut GcRootsList) {
472 log::trace!("Begin trace user LIFO roots");
473 for root in &mut self.lifo_roots {
474 unsafe {
475 gc_roots_list.add_vmgcref_root((&mut root.gc_ref).into(), "user LIFO root");
476 }
477 }
478 log::trace!("End trace user LIFO roots");
479
480 log::trace!("Begin trace user owned roots");
481 for (_id, root) in self.owned_rooted.iter_mut() {
482 unsafe {
483 gc_roots_list.add_vmgcref_root(root.into(), "user owned root");
484 }
485 }
486 log::trace!("End trace user owned roots");
487 }
488
489 /// Enter a LIFO rooting scope.
490 ///
491 /// Returns an integer that should be passed unmodified to `exit_lifo_scope`
492 /// when the scope is finished.
493 ///
494 /// Calls to `{enter,exit}_lifo_scope` must happen in a strict LIFO order.
495 #[inline]
496 pub(crate) fn enter_lifo_scope(&self) -> usize {
497 self.lifo_roots.len()
498 }
499
500 /// Exit a LIFO rooting scope.
501 ///
502 /// The `scope` argument must be the result of the corresponding
503 /// `enter_lifo_scope` call.
504 ///
505 /// Calls to `{enter,exit}_lifo_scope` must happen in a strict LIFO order.
506 #[inline]
507 pub(crate) fn exit_lifo_scope(&mut self, gc_store: Option<&mut GcStore>, scope: usize) {
508 debug_assert!(self.lifo_roots.len() >= scope);
509
510 // If we actually have roots to unroot, call an out-of-line slow path.
511 if self.lifo_roots.len() > scope {
512 self.exit_lifo_scope_slow(gc_store, scope);
513 }
514 }
515
516 #[inline(never)]
517 #[cold]
518 fn exit_lifo_scope_slow(&mut self, mut gc_store: Option<&mut GcStore>, scope: usize) {
519 // Note that this explicitly uses `wrapping_add` to avoid panicking on
520 // overflow. This is intended to assist with the lifetime issues on the
521 // host but is not required for memory safety, so in the event of a
522 // wraparound it may mean that preexisting issues on the host go
523 // undetected.
524 self.lifo_generation = self.lifo_generation.wrapping_add(1);
525
526 // TODO: In the case where we have a tracing GC that doesn't need to
527 // drop barriers, this should really be:
528 //
529 // self.lifo_roots.truncate(scope);
530
531 let mut lifo_roots = mem::take(&mut self.lifo_roots);
532 for root in lifo_roots.drain(scope..) {
533 // Only drop the GC reference if we actually have a GC store. How
534 // can we have a GC reference but not a GC store? If we've only
535 // created `i31refs`, we never force a GC store's allocation. This
536 // is fine because `i31ref`s never need drop barriers.
537 if let Some(gc_store) = &mut gc_store {
538 gc_store.drop_gc_ref(root.gc_ref);
539 }
540 }
541 self.lifo_roots = lifo_roots;
542 }
543
544 pub(crate) fn with_lifo_scope<S, T>(store: &mut S, f: impl FnOnce(&mut S) -> T) -> T
545 where
546 S: ?Sized + DerefMut<Target = StoreOpaque>,
547 {
548 let scope = store.gc_roots().enter_lifo_scope();
549 let ret = f(store);
550 store.exit_gc_lifo_scope(scope);
551 ret
552 }
553
554 pub(crate) fn push_lifo_root(&mut self, store_id: StoreId, gc_ref: VMGcRef) -> GcRootIndex {
555 let generation = self.lifo_generation;
556 let index = self.lifo_roots.len();
557 let index = PackedIndex::new_lifo(index);
558 self.lifo_roots.push(LifoRoot { generation, gc_ref });
559 GcRootIndex {
560 store_id,
561 generation,
562 index,
563 }
564 }
565
566 /// Trim any stale (dropped) owned roots.
567 ///
568 /// `OwnedRooted` is implemented in a way that avoids the need to
569 /// have or keep a reference to the store (and thus this struct)
570 /// during its drop operation: to allow it to be independent, it
571 /// holds a shared reference to some other memory and sets that
572 /// "liveness flag" appropriately, then we later observe dead
573 /// liveness flags during a periodic scan and actually deallocate
574 /// the roots. We use an `Arc<()>` for this: it permits cheap
575 /// cloning, and it has minimal memory overhead. We hold a weak
576 /// ref in a list alongside the actual `GcRootIndex`, and we free
577 /// that index in the slab of owned roots when we observe that
578 /// only our weak ref remains.
579 ///
580 /// This trim step is logically separate from a full GC, though it
581 /// would not be very productive to do a GC without doing a
582 /// root-trim first: the root-trim should be quite a lot cheaper,
583 /// and it will allow for more garbage to exist.
584 ///
585 /// There is, additionally, nothing stopping us from doing trims
586 /// more often than just before each GC, and there are reasons
587 /// this could be a good idea: for example, a user program that
588 /// creates and removes many roots (perhaps as it accesses the GC
589 /// object graph) but ultimately is dealing with a static graph,
590 /// without further allocation, may need the "root set" to be GC'd
591 /// independently from the actual heap. Thus, we could trim before
592 /// adding a new root to ensure we don't grow that unboundedly (or
593 /// force an otherwise unneeded GC).
594 ///
595 /// The first case, just before GC, wants a "full trim": there's
596 /// no reason not to unroot as much as possible before we do the
597 /// expensive work of tracing the whole heap.
598 ///
599 /// On the other hand, the second case, adding a new root, wants a
600 /// kind of trim that is amortized constant time. Consider: if we
601 /// have some threshold for the trim, say N roots, and the user
602 /// program continually adds and removes one root such that it
603 /// goes just over the threshold, we might scan all N liveness
604 /// flags for each step, resulting in quadratic behavior overall.
605 ///
606 /// Thus, we implement a "high water mark" algorithm to guard
607 /// against this latter case: on the add-a-new-root case, we trim
608 /// only if the list is longer than the high water mark, and we
609 /// set the high water mark each time based on the after-trim
610 /// size. See below for details on this algorithm.
611 ///
612 /// `eager` chooses whether we eagerly trim roots or pre-filter
613 /// using the high-water mark.
614 ///
615 /// # Growth Algorithm
616 ///
617 /// We want to balance two factors: we must ensure that the
618 /// algorithmic complexity of creating a new root is amortized
619 /// O(1), and we must ensure that repeated creation and deletion
620 /// of roots without any GC must result in a root-set that has a
621 /// size linear in the actual live-root-set size. Stated formally:
622 ///
623 /// 1. Root creation must be O(1), amortized
624 /// 2. liveness_flags.len() must be O(|max live owned roots|),
625 /// i.e., must not grow to larger than a constant multiple of
626 /// the maximum working-root-set size of the program.
627 ///
628 /// Note that a naive exponential-growth-of-threshold algorithm,
629 /// where we trim when the root set reaches 1, 2, 4, 8, 16, 32,
630 /// ... elements, provides the first but *not* the second
631 /// property. A workload that has a constant live root set but
632 /// creates and drops roots constantly (say, as it's traversing a
633 /// static graph and moving "fingers" through it) will cause the
634 /// `liveness_flags` array to grow unboundedly.
635 ///
636 /// Instead, it turns out that we can achieve both of these goals
637 /// with a simple rule: we trim when the root list length reaches
638 /// a high-water mark; and then *after* trimming, we set the
639 /// high-water mark equal to the resulting live-root count
640 /// multiplied by a factor (e.g., 2).
641 ///
642 /// ## Proof
643 ///
644 /// - Root creation is O(1)
645 ///
646 /// Assume a sequence of root creation and drop events (and no
647 /// GCs, with a static GC graph, in the worst case -- only roots
648 /// are changing). We want to show that after N root creations,
649 /// we have incurred only only O(N) cost scanning the
650 /// `liveness_flags` list over the whole sequence.
651 ///
652 /// Assume a default high-water mark of D (e.g., 8) at
653 /// initialization with an empty root list.
654 ///
655 /// Consider "epochs" in the sequence split by trim events where
656 /// we scan the root list. Proceed by induction over epochs to
657 /// show: after each epoch, we will have scanned at most 2N
658 /// roots after N root creations.
659 ///
660 /// (These epochs don't exist in the algorithm: this is just a
661 /// mechanism to analyze the behavior.)
662 ///
663 /// Base case: after the first epoch, with D root creations, we
664 /// will scan D roots.
665 ///
666 /// Induction step: we have created N roots and scanned at most
667 /// 2N roots. After previous scan, L roots are still live; then
668 /// we set the high-water mark for next scan at 2L. The list
669 /// already has L, so after another L root creations, the epoch
670 /// ends. We will then incur a scan cost of 2L (the full
671 /// list). At that point we have thus seen N + L root creations,
672 /// with 2N + 2L scan cost; the invariant holds.
673 ///
674 /// (It's counter-intuitive that *not* raising the high-water
675 /// mark exponentially can still result in a constant amortized
676 /// cost! One intuition to understand this is that each root
677 /// that remains alive after a scan pushes the next high-water
678 /// mark up by one, so requires a new root creation to "pay for"
679 /// its next scan. So any given root may be scanned many times,
680 /// but each such root ensures other root creations happen to
681 /// maintain the amortized cost.)
682 ///
683 /// - `liveness_flags.len()` is always O(|max live roots|)
684 ///
685 /// Before the first trim, we have between 0 and D live roots,
686 /// which is O(1) (`D` is a compile-time constant).
687 ///
688 /// Just after a trim, the `liveness_flags` list has only live
689 /// roots, and the max live-root count is at least the count at
690 /// this time, so the property holds.
691 ///
692 /// The instantaneous maximum number of live roots is greater
693 /// than or equal to the maximum number of live roots observed
694 /// during a trim. (The trim is just some point in time, and the
695 /// max at some point in time is at most the overall max.)
696 ///
697 /// The high-water mark is set at 2 * `liveness_flags.len()`
698 /// after a trim, i.e., the number of live roots at that
699 /// time. We trim when we reach the high-water mark. So the
700 /// length of the array cannot exceed 2 *
701 /// `liveness_flags.len()`, which is less than or equal to the
702 /// overall max. So transitively, the list length at any time is
703 /// always O(|max live roots|).
704 ///
705 /// We thus have tight bounds (deterministic, not randomized) for
706 /// all possible sequences of root creation/dropping, ensuring
707 /// robustness.
708 pub(crate) fn trim_liveness_flags(&mut self, gc_store: &mut GcStore, eager: bool) {
709 const DEFAULT_HIGH_WATER: usize = 8;
710 const GROWTH_FACTOR: usize = 2;
711 let high_water_mark = self
712 .liveness_trim_high_water
713 .map(|x| x.get())
714 .unwrap_or(DEFAULT_HIGH_WATER);
715 if !eager && self.liveness_flags.len() < high_water_mark {
716 return;
717 }
718
719 self.liveness_flags.retain(|(flag, index)| {
720 if flag.strong_count() == 0 {
721 // No more `OwnedRooted` instances are holding onto
722 // this; dealloc the index and drop our Weak.
723 let gc_ref = self.owned_rooted.dealloc(*index);
724 gc_store.drop_gc_ref(gc_ref);
725 // Don't retain in the list.
726 false
727 } else {
728 // Retain in the list.
729 true
730 }
731 });
732
733 let post_trim_len = self.liveness_flags.len();
734 let high_water_mark = core::cmp::max(
735 DEFAULT_HIGH_WATER,
736 post_trim_len.saturating_mul(GROWTH_FACTOR),
737 );
738 self.liveness_trim_high_water = Some(NonZeroUsize::new(high_water_mark).unwrap());
739 }
740}
741
742/// A scoped, rooted reference to a garbage-collected `T`.
743///
744/// A `Rooted<T>` is a strong handle to a garbage-collected `T`, preventing its
745/// referent (and anything else transitively referenced) from being collected by
746/// the GC during the scope within which this `Rooted<T>` was created.
747///
748/// When the context exits this `Rooted<T>`'s scope, the underlying GC object is
749/// automatically unrooted and any further attempts to use access the underlying
750/// object will return errors or otherwise fail.
751///
752/// `Rooted<T>` dereferences to its underlying `T`, allowing you to call `T`'s
753/// methods.
754///
755/// # Example
756///
757/// ```
758/// # use wasmtime::*;
759/// # fn _foo() -> Result<()> {
760/// let mut store = Store::<()>::default();
761///
762/// // Allocating a GC object returns a `Rooted<T>`.
763/// let hello: Rooted<ExternRef> = ExternRef::new(&mut store, "hello")?;
764///
765/// // Because `Rooted<T>` derefs to `T`, we can call `T` methods on a
766/// // `Rooted<T>`. For example, we can call the `ExternRef::data` method when we
767/// // have a `Rooted<ExternRef>`.
768/// let data = hello
769/// .data(&store)?
770/// .ok_or_else(|| Error::msg("externref has no host data"))?
771/// .downcast_ref::<&str>()
772/// .ok_or_else(|| Error::msg("not a str"))?;
773/// assert_eq!(*data, "hello");
774///
775/// // A `Rooted<T>` roots its underlying GC object for the duration of the
776/// // scope of the store/caller/context that was passed to the method that created
777/// // it. If we only want to keep a GC reference rooted and alive temporarily, we
778/// // can introduce new scopes with `RootScope`.
779/// {
780/// let mut scope = RootScope::new(&mut store);
781///
782/// // This `Rooted<T>` is automatically unrooted after `scope` is dropped,
783/// // allowing the collector to reclaim its GC object in the next GC.
784/// let scoped_ref = ExternRef::new(&mut scope, "goodbye");
785/// }
786///
787/// let module = Module::new(store.engine(), r#"
788/// (module
789/// (global (export "global") (mut externref) (ref.null extern))
790/// (table (export "table") 10 externref)
791/// (func (export "func") (param externref) (result externref)
792/// local.get 0
793/// )
794/// )
795/// "#)?;
796/// let instance = Instance::new(&mut store, &module, &[])?;
797///
798/// // GC references returned from calls into Wasm also return (optional, if the
799/// // Wasm type is nullable) `Rooted<T>`s.
800/// let result: Option<Rooted<_>> = instance
801/// .get_typed_func::<Option<Rooted<ExternRef>>, Option<Rooted<ExternRef>>>(&mut store, "func")?
802/// .call(&mut store, Some(hello))?;
803///
804/// // Similarly, getting a GC reference from a Wasm instance's exported global
805/// // or table yields a `Rooted<T>`.
806///
807/// let global = instance
808/// .get_global(&mut store, "global")
809/// .ok_or_else(|| Error::msg("missing `global` export"))?;
810/// let global_val = global.get(&mut store);
811/// let global_ref: Option<&Rooted<_>> = global_val
812/// .externref()
813/// .ok_or_else(|| Error::msg("not an externref"))?;
814///
815/// let table = instance.get_table(&mut store, "table").unwrap();
816/// let table_elem = table
817/// .get(&mut store, 3)
818/// .ok_or_else(|| Error::msg("table out of bounds"))?;
819/// let table_elem_ref: Option<&Rooted<_>> = table_elem
820/// .as_extern()
821/// .ok_or_else(|| Error::msg("not an externref"))?;
822/// # Ok(())
823/// # }
824/// ```
825///
826/// # Differences Between `Rooted<T>` and `OwnedRooted<T>`
827///
828/// While `Rooted<T>` is automatically unrooted when its scope is
829/// exited, this means that `Rooted<T>` is only valid for strictly
830/// last-in-first-out (LIFO, aka stack order) lifetimes. This is in
831/// contrast to [`OwnedRooted<T>`][crate::OwnedRooted], which supports
832/// rooting GC objects for arbitrary lifetimes.
833///
834/// | Type | Supported Lifetimes | Unrooting | Cost |
835/// |----------------------------------------------|-----------------------------|-----------|----------------------------------|
836/// | [`Rooted<T>`][crate::Rooted] | Strictly LIFO / stack order | Automatic | very low (LIFO array) |
837/// | [`OwnedRooted<T>`][crate::OwnedRooted] | Arbitrary | Automatic | medium (separate `Arc` to track) |
838///
839/// `Rooted<T>` should suffice for most use cases, and provides decent
840/// ergonomics. In cases where LIFO scopes are difficult to reason
841/// about, e.g. heap-managed data structures, or when they may cause
842/// erroneous behavior, e.g. in errors that are propagated up the call
843/// stack, `OwnedRooted<T>` provides very safe ergonomics but at a
844/// small dynamic cost for the separate tracking allocation.
845///
846/// # Scopes
847///
848/// Wasmtime automatically creates two kinds of scopes:
849///
850/// 1. A [`Store`][crate::Store] is the outermost rooting scope. Creating a
851/// `Root<T>` directly inside a `Store` permanently roots the underlying
852/// object.
853///
854/// 2. A [`Caller`][crate::Caller] provides a rooting scope for the duration of
855/// a call from Wasm into a host function. Any objects rooted in a `Caller`
856/// will be unrooted after the host function returns. Note that there can be
857/// nested `Caller` scopes in the case where Wasm calls a host function,
858/// creating the first `Caller` and its rooting scope , and then the host
859/// function calls a Wasm function which then calls another host function,
860/// creating a second `Caller` and a second rooting scope. This nesting can
861/// be arbitrarily deep.
862///
863/// Additionally, if you would like to define finer-grained rooting scopes,
864/// Wasmtime provides the [`RootScope`][crate::RootScope] type.
865///
866/// Scopes are always nested in a last-in-first-out (LIFO) order. An outer scope
867/// is never exited (and the `Rooted<T>`s defined within it are never
868/// automatically unrooted) while an inner scope is still active. All inner
869/// scopes are exited before their outer scopes.
870///
871/// The following diagram illustrates various rooting scopes over time, how they
872/// nest, and when their `Rooted<T>`s are automatically unrooted:
873///
874/// ```text
875/// ----- new Store
876/// |
877/// |
878/// | let a: Rooted<T> = ...;
879/// |
880/// |
881/// | ----- call into Wasm
882/// | |
883/// | |
884/// | | ----- Wasm calls host function F
885/// | | |
886/// | | |
887/// | | | let b: Rooted<T> = ...;
888/// | | |
889/// | | |
890/// | | | ----- F calls into Wasm
891/// | | | |
892/// | | | |
893/// | | | | ----- Wasm call host function G
894/// | | | | |
895/// | | | | |
896/// | | | | | let c: Rooted<T> = ...;
897/// | | | | |
898/// | | | | |
899/// | | | | ----- return to Wasm from host function G (unroots `c`)
900/// | | | |
901/// | | | |
902/// | | | ----- Wasm returns to F
903/// | | |
904/// | | |
905/// | | ----- return from host function F (unroots `b`)
906/// | |
907/// | |
908/// | ----- return from Wasm
909/// |
910/// |
911/// | ----- let scope1 = RootScope::new(...);
912/// | |
913/// | |
914/// | | let d: Rooted<T> = ...;
915/// | |
916/// | |
917/// | | ----- let scope2 = RootScope::new(...);
918/// | | |
919/// | | |
920/// | | | let e: Rooted<T> = ...;
921/// | | |
922/// | | |
923/// | | ----- drop `scope2` (unroots `e`)
924/// | |
925/// | |
926/// | ----- drop `scope1` (unroots `d`)
927/// |
928/// |
929/// ----- drop Store (unroots `a`)
930/// ```
931///
932/// A `Rooted<T>` can be used successfully as long as it is still rooted so, in
933/// the above diagram, `d` is valid inside `scope2` because `scope2` is wholly
934/// contained within the scope `d` was rooted within (`scope1`).
935///
936/// See also the documentation for [`RootScope`][crate::RootScope].
937#[repr(transparent)]
938pub struct Rooted<T: GcRef> {
939 inner: GcRootIndex,
940 _phantom: marker::PhantomData<T>,
941}
942
943impl<T: GcRef> Clone for Rooted<T> {
944 fn clone(&self) -> Self {
945 Rooted {
946 inner: self.inner,
947 _phantom: marker::PhantomData,
948 }
949 }
950}
951
952impl<T: GcRef> Copy for Rooted<T> {}
953
954impl<T: GcRef> Debug for Rooted<T> {
955 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
956 let name = format!("Rooted<{}>", any::type_name::<T>());
957 f.debug_struct(&name).field("inner", &self.inner).finish()
958 }
959}
960
961impl<T: GcRef> RootedGcRefImpl<T> for Rooted<T> {
962 fn get_gc_ref<'a>(&self, store: &'a StoreOpaque) -> Option<&'a VMGcRef> {
963 assert!(
964 self.comes_from_same_store(store),
965 "object used with wrong store"
966 );
967 let index = self.inner.index.as_lifo().unwrap();
968 let entry = store.gc_roots().lifo_roots.get(index)?;
969 if entry.generation == self.inner.generation {
970 Some(&entry.gc_ref)
971 } else {
972 None
973 }
974 }
975}
976
977impl<T: GcRef> Deref for Rooted<T> {
978 type Target = T;
979
980 fn deref(&self) -> &Self::Target {
981 T::transmute_ref(&self.inner)
982 }
983}
984
985impl<T: GcRef> Rooted<T> {
986 /// Push the given `VMGcRef` onto our LIFO root set.
987 ///
988 /// `gc_ref` should belong to `store`'s heap; failure to uphold this is
989 /// memory safe but will result in general failures down the line such as
990 /// panics or incorrect results.
991 ///
992 /// `gc_ref` should be a GC reference pointing to an instance of the GC type
993 /// that `T` represents. Failure to uphold this invariant is memory safe but
994 /// will result in general incorrectness such as panics and wrong results.
995 pub(crate) fn new(store: &mut AutoAssertNoGc<'_>, gc_ref: VMGcRef) -> Rooted<T> {
996 let id = store.id();
997 let roots = store.gc_roots_mut();
998 let inner = roots.push_lifo_root(id, gc_ref);
999 Rooted {
1000 inner,
1001 _phantom: marker::PhantomData,
1002 }
1003 }
1004
1005 /// Create a new `Rooted<T>` from a `GcRootIndex`.
1006 ///
1007 /// Note that `Rooted::from_gc_root_index(my_rooted.index)` is not
1008 /// necessarily an identity function, as it allows changing the `T` type
1009 /// parameter.
1010 ///
1011 /// The given index should be a LIFO index of a GC reference pointing to an
1012 /// instance of the GC type that `T` represents. Failure to uphold this
1013 /// invariant is memory safe but will result in general incorrectness such
1014 /// as panics and wrong results.
1015 pub(crate) fn from_gc_root_index(inner: GcRootIndex) -> Rooted<T> {
1016 debug_assert!(inner.index.is_lifo());
1017 Rooted {
1018 inner,
1019 _phantom: marker::PhantomData,
1020 }
1021 }
1022
1023 #[inline]
1024 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
1025 debug_assert!(self.inner.index.is_lifo());
1026 self.inner.comes_from_same_store(store)
1027 }
1028
1029 /// Create an [`OwnedRooted<T>`][crate::OwnedRooted] holding onto the
1030 /// same GC object as `self`.
1031 ///
1032 /// Returns `None` if `self` is used outside of its scope and has therefore
1033 /// been unrooted.
1034 ///
1035 /// This does not unroot `self`, and `self` remains valid until its
1036 /// associated scope is exited.
1037 ///
1038 /// # Panics
1039 ///
1040 /// Panics if this object is not associate with the given store.
1041 ///
1042 /// # Example
1043 ///
1044 /// ```
1045 /// # use wasmtime::*;
1046 /// # fn _foo() -> Result<()> {
1047 /// let mut store = Store::<()>::default();
1048 ///
1049 /// let y: OwnedRooted<_> = {
1050 /// // Create a nested rooting scope.
1051 /// let mut scope = RootScope::new(&mut store);
1052 ///
1053 /// // `x` is only rooted within this nested scope.
1054 /// let x: Rooted<_> = ExternRef::new(&mut scope, "hello!")?;
1055 ///
1056 /// // Extend `x`'s rooting past its scope's lifetime by converting it
1057 /// // to an `OwnedRooted`.
1058 /// x.to_owned_rooted(&mut scope)?
1059 /// };
1060 ///
1061 /// // Now we can still access the reference outside the scope it was
1062 /// // originally defined within.
1063 /// let data = y.data(&store)?.expect("should have host data");
1064 /// let data = data.downcast_ref::<&str>().expect("host data should be str");
1065 /// assert_eq!(*data, "hello!");
1066 /// # Ok(())
1067 /// # }
1068 /// ```
1069 pub fn to_owned_rooted(&self, mut store: impl AsContextMut) -> Result<OwnedRooted<T>> {
1070 self._to_owned_rooted(store.as_context_mut().0)
1071 }
1072
1073 pub(crate) fn _to_owned_rooted(&self, store: &mut StoreOpaque) -> Result<OwnedRooted<T>> {
1074 let mut store = AutoAssertNoGc::new(store);
1075 let gc_ref = self.try_clone_gc_ref(&mut store)?;
1076 Ok(OwnedRooted::new(&mut store, gc_ref)?)
1077 }
1078
1079 /// Are these two `Rooted<T>`s the same GC root?
1080 ///
1081 /// Note that this function can return `false` even when `a` and `b` are
1082 /// rooting the same underlying GC object, but the object was rooted
1083 /// multiple times (for example in different scopes). Use
1084 /// [`Rooted::ref_eq`][crate::Rooted::ref_eq] to test whether these are
1085 /// references to the same underlying GC object or not.
1086 ///
1087 /// # Example
1088 ///
1089 /// ```
1090 /// # use wasmtime::*;
1091 /// # fn foo() -> Result<()> {
1092 /// let mut store = Store::<()>::default();
1093 ///
1094 /// let a = ExternRef::new(&mut store, "hello")?;
1095 /// let b = a;
1096 ///
1097 /// // `a` and `b` are the same GC root.
1098 /// assert!(Rooted::rooted_eq(a, b));
1099 ///
1100 /// {
1101 /// let mut scope = RootScope::new(&mut store);
1102 ///
1103 /// // `c` is a different GC root, in a different scope, even though it
1104 /// // is rooting the same object.
1105 /// let c = a.to_owned_rooted(&mut scope)?.to_rooted(&mut scope);
1106 /// assert!(!Rooted::rooted_eq(a, c));
1107 /// }
1108 ///
1109 /// let x = ExternRef::new(&mut store, "goodbye")?;
1110 ///
1111 /// // `a` and `x` are different GC roots, rooting different objects.
1112 /// assert!(!Rooted::rooted_eq(a, x));
1113 /// # Ok(())
1114 /// # }
1115 /// ```
1116 pub fn rooted_eq(a: Self, b: Self) -> bool {
1117 a.inner == b.inner
1118 }
1119
1120 /// Are these two GC roots referencing the same underlying GC object?
1121 ///
1122 /// This function will return `true` even when `a` and `b` are different GC
1123 /// roots (for example because they were rooted in different scopes) if they
1124 /// are rooting the same underlying GC object. To only test whether they are
1125 /// the same GC root, and not whether they are rooting the same GC object,
1126 /// use [`Rooted::rooted_eq`][crate::Rooted::rooted_eq].
1127 ///
1128 /// Returns an error if either `a` or `b` has been unrooted, for example
1129 /// because the scope it was rooted within has been exited.
1130 ///
1131 /// Because this method takes any `impl RootedGcRef<T>` arguments, it can be
1132 /// used to compare, for example, a `Rooted<T>` and a `OwnedRooted<T>`.
1133 ///
1134 /// # Panics
1135 ///
1136 /// Panics if either `a` or `b` is not associated with the given `store`.
1137 ///
1138 /// # Example
1139 ///
1140 /// ```
1141 /// # use wasmtime::*;
1142 /// # fn foo() -> Result<()> {
1143 /// let mut store = Store::<()>::default();
1144 ///
1145 /// let a = ExternRef::new(&mut store, "hello")?;
1146 /// let b = a;
1147 ///
1148 /// // `a` and `b` are rooting the same object.
1149 /// assert!(Rooted::ref_eq(&store, &a, &b)?);
1150 ///
1151 /// {
1152 /// let mut scope = RootScope::new(&mut store);
1153 ///
1154 /// // `c` is a different GC root, in a different scope, but still
1155 /// // rooting the same object.
1156 /// let c = a.to_owned_rooted(&mut scope)?.to_rooted(&mut scope);
1157 /// assert!(!Rooted::ref_eq(&scope, &a, &c)?);
1158 /// }
1159 ///
1160 /// let x = ExternRef::new(&mut store, "goodbye")?;
1161 ///
1162 /// // `a` and `x` are rooting different objects.
1163 /// assert!(!Rooted::ref_eq(&store, &a, &x)?);
1164 ///
1165 /// // You can also compare `Rooted<T>`s and `OwnedRooted<T>`s with this
1166 /// // function.
1167 /// let d = a.to_owned_rooted(&mut store)?;
1168 /// assert!(Rooted::ref_eq(&store, &a, &d)?);
1169 /// # Ok(())
1170 /// # }
1171 /// ```
1172 pub fn ref_eq(
1173 store: impl AsContext,
1174 a: &impl RootedGcRef<T>,
1175 b: &impl RootedGcRef<T>,
1176 ) -> Result<bool> {
1177 let store = store.as_context().0;
1178 Self::_ref_eq(store, a, b)
1179 }
1180
1181 pub(crate) fn _ref_eq(
1182 store: &StoreOpaque,
1183 a: &impl RootedGcRef<T>,
1184 b: &impl RootedGcRef<T>,
1185 ) -> Result<bool> {
1186 let a = a.try_gc_ref(store)?;
1187 let b = b.try_gc_ref(store)?;
1188 Ok(a == b)
1189 }
1190
1191 /// Hash this root.
1192 ///
1193 /// Note that, similar to `Rooted::rooted_eq`, this only operates on the
1194 /// root and *not* the underlying GC reference. That means that two
1195 /// different rootings of the same object will hash to different values
1196 /// (modulo hash collisions). If this is undesirable, use the
1197 /// [`ref_hash`][crate::Rooted::ref_hash] method instead.
1198 pub fn rooted_hash<H>(&self, state: &mut H)
1199 where
1200 H: Hasher,
1201 {
1202 self.inner.hash(state);
1203 }
1204
1205 /// Hash the underlying rooted object reference.
1206 ///
1207 /// Note that, similar to `Rooted::ref_eq`, and operates on the underlying
1208 /// rooted GC object reference, not the root. That means that two
1209 /// *different* rootings of the same object will hash to the *same*
1210 /// value. If this is undesirable, use the
1211 /// [`rooted_hash`][crate::Rooted::rooted_hash] method instead.
1212 pub fn ref_hash<H>(&self, store: impl AsContext, state: &mut H) -> Result<()>
1213 where
1214 H: Hasher,
1215 {
1216 let gc_ref = self.try_gc_ref(store.as_context().0)?;
1217 gc_ref.hash(state);
1218 Ok(())
1219 }
1220
1221 /// Cast `self` to a `Rooted<U>`.
1222 ///
1223 /// It is the caller's responsibility to ensure that `self` is actually a
1224 /// `U`. Failure to uphold this invariant will be memory safe but will
1225 /// result in general incorrectness such as panics and wrong results.
1226 pub(crate) fn unchecked_cast<U: GcRef>(self) -> Rooted<U> {
1227 Rooted::from_gc_root_index(self.inner)
1228 }
1229
1230 /// Common implementation of the `WasmTy::store` trait method for all
1231 /// `Rooted<T>`s.
1232 pub(super) fn wasm_ty_store(
1233 self,
1234 store: &mut AutoAssertNoGc<'_>,
1235 ptr: &mut MaybeUninit<ValRaw>,
1236 val_raw: impl Fn(u32) -> ValRaw,
1237 ) -> Result<()> {
1238 let raw = self.inner.expose_gc_ref_to_wasm(store)?;
1239 ptr.write(val_raw(raw.get()));
1240 Ok(())
1241 }
1242
1243 /// Common implementation of the `WasmTy::load` trait method for all
1244 /// `Rooted<T>`s.
1245 pub(super) fn wasm_ty_load(
1246 store: &mut AutoAssertNoGc<'_>,
1247 raw_gc_ref: u32,
1248 from_cloned_gc_ref: impl Fn(&mut AutoAssertNoGc<'_>, VMGcRef) -> Self,
1249 ) -> Self {
1250 debug_assert_ne!(raw_gc_ref, 0);
1251 let gc_ref = VMGcRef::from_raw_u32(raw_gc_ref).expect("non-null");
1252
1253 let gc_ref = match store.optional_gc_store_mut() {
1254 Some(s) => s.clone_gc_ref(&gc_ref),
1255 None => {
1256 // NB: do not force the allocation of a GC heap just because the
1257 // program is using `i31ref`s.
1258 debug_assert!(gc_ref.is_i31());
1259 gc_ref.unchecked_copy()
1260 }
1261 };
1262
1263 from_cloned_gc_ref(store, gc_ref)
1264 }
1265
1266 /// Common implementation of the `WasmTy::store` trait method for all
1267 /// `Option<Rooted<T>>`s.
1268 pub(super) fn wasm_ty_option_store(
1269 me: Option<Self>,
1270 store: &mut AutoAssertNoGc<'_>,
1271 ptr: &mut MaybeUninit<ValRaw>,
1272 val_raw: impl Fn(u32) -> ValRaw,
1273 ) -> Result<()> {
1274 match me {
1275 Some(me) => me.wasm_ty_store(store, ptr, val_raw),
1276 None => {
1277 ptr.write(val_raw(0));
1278 Ok(())
1279 }
1280 }
1281 }
1282
1283 /// Common implementation of the `WasmTy::load` trait method for all
1284 /// `Option<Rooted<T>>`s.
1285 pub(super) fn wasm_ty_option_load(
1286 store: &mut AutoAssertNoGc<'_>,
1287 raw_gc_ref: u32,
1288 from_cloned_gc_ref: impl Fn(&mut AutoAssertNoGc<'_>, VMGcRef) -> Self,
1289 ) -> Option<Self> {
1290 let gc_ref = VMGcRef::from_raw_u32(raw_gc_ref)?;
1291 let gc_ref = store.clone_gc_ref(&gc_ref);
1292 Some(from_cloned_gc_ref(store, gc_ref))
1293 }
1294
1295 pub(crate) fn try_gc_ref<'a>(&self, store: &'a StoreOpaque) -> Result<&'a VMGcRef> {
1296 <Self as RootedGcRefImpl<_>>::try_gc_ref(self, store)
1297 }
1298
1299 pub(crate) fn try_clone_gc_ref(&self, store: &mut AutoAssertNoGc<'_>) -> Result<VMGcRef> {
1300 <Self as RootedGcRefImpl<_>>::try_clone_gc_ref(self, store)
1301 }
1302}
1303
1304/// Nested rooting scopes.
1305///
1306/// `RootScope` allows the creation or nested rooting scopes for use with
1307/// [`Rooted<T>`][crate::Rooted]. This allows for fine-grained control over how
1308/// long a set of [`Rooted<T>`][crate::Rooted]s are strongly held alive, giving
1309/// gives you the tools necessary to avoid holding onto GC objects longer than
1310/// necessary. `Rooted<T>`s created within a `RootScope` are automatically
1311/// unrooted when the `RootScope` is dropped. For more details on
1312/// [`Rooted<T>`][crate::Rooted] lifetimes and their interaction with rooting
1313/// scopes, see [`Rooted<T>`][crate::Rooted]'s documentation.
1314///
1315/// A `RootScope<C>` wraps a `C: AsContextMut` (that is, anything that
1316/// represents exclusive access to a [`Store`][crate::Store]) and in turn
1317/// implements [`AsContext`][crate::AsContext] and
1318/// [`AsContextMut`][crate::AsContextMut] in terms of its underlying
1319/// `C`. Therefore, `RootScope<C>` can be used anywhere you would use the
1320/// underlying `C`, for example in the [`Global::get`][crate::Global::get]
1321/// method. Any `Rooted<T>`s created by a method that a `RootScope<C>` was
1322/// passed as context to are tied to the `RootScope<C>`'s scope and
1323/// automatically unrooted when the scope is dropped.
1324///
1325/// # Example
1326///
1327/// ```
1328/// # use wasmtime::*;
1329/// # fn _foo() -> Result<()> {
1330/// let mut store = Store::<()>::default();
1331///
1332/// let a: Rooted<_>;
1333/// let b: Rooted<_>;
1334/// let c: Rooted<_>;
1335///
1336/// // Root `a` in the store's scope. It will be rooted for the duration of the
1337/// // store's lifetime.
1338/// a = ExternRef::new(&mut store, 42)?;
1339///
1340/// // `a` is rooted, so we can access its data successfully.
1341/// assert!(a.data(&store).is_ok());
1342///
1343/// {
1344/// let mut scope1 = RootScope::new(&mut store);
1345///
1346/// // Root `b` in `scope1`.
1347/// b = ExternRef::new(&mut scope1, 36)?;
1348///
1349/// // Both `a` and `b` are rooted.
1350/// assert!(a.data(&scope1).is_ok());
1351/// assert!(b.data(&scope1).is_ok());
1352///
1353/// {
1354/// let mut scope2 = RootScope::new(&mut scope1);
1355///
1356/// // Root `c` in `scope2`.
1357/// c = ExternRef::new(&mut scope2, 36)?;
1358///
1359/// // All of `a`, `b`, and `c` are rooted.
1360/// assert!(a.data(&scope2).is_ok());
1361/// assert!(b.data(&scope2).is_ok());
1362/// assert!(c.data(&scope2).is_ok());
1363///
1364/// // Drop `scope2`.
1365/// }
1366///
1367/// // Now `a` and `b` are still rooted, but `c` was unrooted when we dropped
1368/// // `scope2`.
1369/// assert!(a.data(&scope1).is_ok());
1370/// assert!(b.data(&scope1).is_ok());
1371/// assert!(c.data(&scope1).is_err());
1372///
1373/// // Drop `scope1`.
1374/// }
1375///
1376/// // And now only `a` is still rooted. Both `b` and `c` were unrooted when we
1377/// // dropped their respective rooting scopes.
1378/// assert!(a.data(&store).is_ok());
1379/// assert!(b.data(&store).is_err());
1380/// assert!(c.data(&store).is_err());
1381/// # Ok(())
1382/// # }
1383/// ```
1384pub struct RootScope<C>
1385where
1386 C: AsContextMut,
1387{
1388 store: C,
1389 scope: usize,
1390}
1391
1392impl<C> Drop for RootScope<C>
1393where
1394 C: AsContextMut,
1395{
1396 fn drop(&mut self) {
1397 self.store.as_context_mut().0.exit_gc_lifo_scope(self.scope);
1398 }
1399}
1400
1401impl<C> RootScope<C>
1402where
1403 C: AsContextMut,
1404{
1405 // NB: we MUST NOT expose a method like
1406 //
1407 // pub fn store(&mut self) -> &mut Store { ... }
1408 //
1409 // because callers could do treacherous things like
1410 //
1411 // let scope1 = RootScope::new(&mut store1);
1412 // let scope2 = RootScope::new(&mut store2);
1413 // std::mem::swap(scope1.store(), scope2.store());
1414 //
1415 // and then we would start truncate the store's GC root set's LIFO roots to
1416 // the wrong lengths.
1417 //
1418 // Instead, we just implement `AsContext[Mut]` for `RootScope`.
1419
1420 /// Construct a new scope for rooting GC objects.
1421 ///
1422 /// # Example
1423 ///
1424 /// ```
1425 /// # use wasmtime::*;
1426 /// let mut store = Store::<()>::default();
1427 ///
1428 /// {
1429 /// let mut scope = RootScope::new(&mut store);
1430 ///
1431 /// // Temporarily root GC objects in this nested rooting scope...
1432 /// }
1433 /// ```
1434 pub fn new(store: C) -> Self {
1435 let scope = store.as_context().0.gc_roots().enter_lifo_scope();
1436 RootScope { store, scope }
1437 }
1438
1439 fn gc_roots(&mut self) -> &mut RootSet {
1440 self.store.as_context_mut().0.gc_roots_mut()
1441 }
1442
1443 fn lifo_roots(&mut self) -> &mut Vec<LifoRoot> {
1444 &mut self.gc_roots().lifo_roots
1445 }
1446
1447 /// Reserve enough capacity for `additional` GC roots in this scope.
1448 ///
1449 /// # Example
1450 ///
1451 /// ```
1452 /// # use wasmtime::*;
1453 /// let mut store = Store::<()>::default();
1454 ///
1455 /// {
1456 /// let mut scope = RootScope::new(&mut store);
1457 ///
1458 /// // Ensure we have enough storage pre-allocated to root five GC
1459 /// // references inside this scope without any underlying reallocation.
1460 /// scope.reserve(5);
1461 ///
1462 /// // ...
1463 /// }
1464 /// ```
1465 pub fn reserve(&mut self, additional: usize) {
1466 self.lifo_roots().reserve(additional);
1467 }
1468}
1469
1470impl<T> AsContext for RootScope<T>
1471where
1472 T: AsContextMut,
1473{
1474 type Data = T::Data;
1475
1476 fn as_context(&self) -> crate::StoreContext<'_, Self::Data> {
1477 self.store.as_context()
1478 }
1479}
1480
1481impl<T> AsContextMut for RootScope<T>
1482where
1483 T: AsContextMut,
1484{
1485 fn as_context_mut(&mut self) -> crate::StoreContextMut<'_, Self::Data> {
1486 self.store.as_context_mut()
1487 }
1488}
1489
1490/// Internal version of `RootScope` that only wraps a `&mut StoreOpaque` rather
1491/// than a whole `impl AsContextMut<Data = T>`.
1492pub(crate) struct OpaqueRootScope<S>
1493where
1494 S: AsStoreOpaque,
1495{
1496 store: S,
1497 scope: usize,
1498}
1499
1500impl<S> Drop for OpaqueRootScope<S>
1501where
1502 S: AsStoreOpaque,
1503{
1504 fn drop(&mut self) {
1505 self.store.as_store_opaque().exit_gc_lifo_scope(self.scope);
1506 }
1507}
1508
1509impl<S> Deref for OpaqueRootScope<S>
1510where
1511 S: AsStoreOpaque,
1512{
1513 type Target = S;
1514
1515 fn deref(&self) -> &Self::Target {
1516 &self.store
1517 }
1518}
1519
1520// XXX: Don't use this `DerefMut` implementation to `mem::{swap,replace}` or
1521// etc... the underlying `StoreOpaque` in a `OpaqueRootScope`! That will result
1522// in truncating the store's GC root set's LIFO roots to the wrong length.
1523//
1524// We don't implement `DerefMut` for `RootScope` for exactly this reason, but
1525// allow it for `OpaqueRootScope` because it is only Wasmtime-internal and not
1526// publicly exported.
1527impl<S> DerefMut for OpaqueRootScope<S>
1528where
1529 S: AsStoreOpaque,
1530{
1531 fn deref_mut(&mut self) -> &mut Self::Target {
1532 &mut self.store
1533 }
1534}
1535
1536impl<S> OpaqueRootScope<S>
1537where
1538 S: AsStoreOpaque,
1539{
1540 pub(crate) fn new(mut store: S) -> Self {
1541 let scope = store.as_store_opaque().gc_roots().enter_lifo_scope();
1542 OpaqueRootScope { store, scope }
1543 }
1544}
1545
1546/// A rooted reference to a garbage-collected `T` with automatic lifetime.
1547///
1548/// An `OwnedRooted<T>` is a strong handle to a garbage-collected `T`,
1549/// preventing its referent (and anything else transitively referenced) from
1550/// being collected by the GC until it is dropped.
1551///
1552/// An `OwnedRooted<T>` keeps its rooted GC object alive at least
1553/// until the `OwnedRooted<T>` itself is dropped. The
1554/// "de-registration" of the root is automatic and is triggered (in a
1555/// deferred way) by the drop of this type.
1556///
1557/// The primary way to create an `OwnedRooted<T>` is to promote a temporary
1558/// `Rooted<T>` into an `OwnedRooted<T>` via its
1559/// [`to_owned_rooted`][crate::Rooted::to_owned_rooted] method.
1560///
1561/// `OwnedRooted<T>` dereferences to its underlying `T`, allowing you to call
1562/// `T`'s methods.
1563///
1564/// # Example
1565///
1566/// ```
1567/// # use wasmtime::*;
1568/// # fn _foo() -> Result<()> {
1569/// let mut store = Store::<Option<OwnedRooted<ExternRef>>>::default();
1570///
1571/// // Create our `OwnedRooted` in a nested scope to avoid rooting it for
1572/// // the duration of the store's lifetime.
1573/// let x = {
1574/// let mut scope = RootScope::new(&mut store);
1575/// let x = ExternRef::new(&mut scope, 1234)?;
1576/// x.to_owned_rooted(&mut scope)?
1577/// };
1578///
1579/// // Place `x` into our store.
1580/// *store.data_mut() = Some(x);
1581///
1582/// // Do a bunch stuff that may or may not access, replace, or take `x`...
1583/// # Ok(())
1584/// # }
1585/// ```
1586pub struct OwnedRooted<T>
1587where
1588 T: GcRef,
1589{
1590 inner: GcRootIndex,
1591 liveness_flag: Arc<()>,
1592 _phantom: marker::PhantomData<T>,
1593}
1594
1595const _: () = {
1596 use crate::{AnyRef, ExternRef};
1597
1598 // NB: these match the C API which should also be updated if this changes.
1599 //
1600 // The size is really "16 + pointer + alignment", which is either
1601 // 20 bytes on some 32-bit platforms or 24 bytes on other 32-bit
1602 // platforms (e.g., riscv32, which adds an extra 4 bytes of
1603 // padding) and 64-bit platforms.
1604 assert!(
1605 mem::size_of::<OwnedRooted<AnyRef>>() >= 16 && mem::size_of::<OwnedRooted<AnyRef>>() <= 24
1606 );
1607 assert!(mem::align_of::<OwnedRooted<AnyRef>>() == mem::align_of::<u64>());
1608 assert!(
1609 mem::size_of::<OwnedRooted<ExternRef>>() >= 16
1610 && mem::size_of::<OwnedRooted<ExternRef>>() <= 24
1611 );
1612 assert!(mem::align_of::<OwnedRooted<ExternRef>>() == mem::align_of::<u64>());
1613};
1614
1615impl<T: GcRef> Debug for OwnedRooted<T> {
1616 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1617 let name = format!("OwnedRooted<{}>", any::type_name::<T>());
1618 f.debug_struct(&name).field("inner", &self.inner).finish()
1619 }
1620}
1621
1622impl<T: GcRef> Deref for OwnedRooted<T> {
1623 type Target = T;
1624
1625 fn deref(&self) -> &Self::Target {
1626 T::transmute_ref(&self.inner)
1627 }
1628}
1629
1630impl<T: GcRef> Clone for OwnedRooted<T> {
1631 fn clone(&self) -> Self {
1632 OwnedRooted {
1633 inner: self.inner,
1634 liveness_flag: self.liveness_flag.clone(),
1635 _phantom: marker::PhantomData,
1636 }
1637 }
1638}
1639
1640impl<T> OwnedRooted<T>
1641where
1642 T: GcRef,
1643{
1644 /// Construct a new owned GC root.
1645 ///
1646 /// `gc_ref` should belong to `store`'s heap; failure to uphold this is
1647 /// memory safe but will result in general failures down the line such as
1648 /// panics or incorrect results.
1649 ///
1650 /// `gc_ref` should be a GC reference pointing to an instance of the GC type
1651 /// that `T` represents. Failure to uphold this invariant is memory safe but
1652 /// will result in general incorrectness such as panics and wrong results.
1653 pub(crate) fn new(
1654 store: &mut AutoAssertNoGc<'_>,
1655 gc_ref: VMGcRef,
1656 ) -> Result<Self, OutOfMemory> {
1657 // We always have the opportunity to trim and unregister stale
1658 // owned roots whenever we have a mut borrow to the store. We
1659 // take the opportunity to do so here to avoid tying growth of
1660 // the root-set to the GC frequency -- it is much cheaper to
1661 // eagerly trim these roots. Note that the trimming keeps a
1662 // "high water mark" that grows exponentially, so we have
1663 // amortized constant time even though an individual trim
1664 // takes time linear in the number of roots.
1665 store.trim_gc_liveness_flags(false);
1666
1667 let roots = store.gc_roots_mut();
1668 let id = roots.owned_rooted.alloc(gc_ref)?;
1669 let liveness_flag = Arc::new(());
1670 roots
1671 .liveness_flags
1672 .push((Arc::downgrade(&liveness_flag), id));
1673 Ok(OwnedRooted {
1674 inner: GcRootIndex {
1675 store_id: store.id(),
1676 generation: 0,
1677 index: PackedIndex::new_owned(id),
1678 },
1679 liveness_flag,
1680 _phantom: marker::PhantomData,
1681 })
1682 }
1683
1684 #[inline]
1685 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
1686 debug_assert!(self.inner.index.is_owned());
1687 self.inner.comes_from_same_store(store)
1688 }
1689
1690 /// Clone this `OwnedRooted<T>` into a `Rooted<T>`.
1691 ///
1692 /// This operation does not consume or unroot this `OwnedRooted<T>`.
1693 ///
1694 /// The underlying GC object is re-rooted in the given context's scope. The
1695 /// resulting `Rooted<T>` is only valid during the given context's
1696 /// scope. See the [`Rooted<T>`][crate::Rooted] documentation for more
1697 /// details on rooting scopes.
1698 ///
1699 /// This operation does not consume or unroot this `OwnedRooted<T>`.
1700 ///
1701 /// # Panics
1702 ///
1703 /// Panics if this object is not associated with the given context's store.
1704 ///
1705 /// # Example
1706 ///
1707 /// ```
1708 /// # use wasmtime::*;
1709 /// # fn _foo() -> Result<()> {
1710 /// let mut store = Store::<()>::default();
1711 ///
1712 /// let root1: Rooted<_>;
1713 ///
1714 /// let owned = {
1715 /// let mut scope = RootScope::new(&mut store);
1716 /// root1 = ExternRef::new(&mut scope, 1234)?;
1717 /// root1.to_owned_rooted(&mut scope)?
1718 /// };
1719 ///
1720 /// // `root1` is no longer accessible because it was unrooted when `scope`
1721 /// // was dropped.
1722 /// assert!(root1.data(&store).is_err());
1723 ///
1724 /// // But we can re-root `owned` into this scope.
1725 /// let root2 = owned.to_rooted(&mut store);
1726 /// assert!(root2.data(&store).is_ok());
1727 /// # Ok(())
1728 /// # }
1729 /// ```
1730 pub fn to_rooted(&self, mut context: impl AsContextMut) -> Rooted<T> {
1731 self._to_rooted(context.as_context_mut().0)
1732 }
1733
1734 pub(crate) fn _to_rooted(&self, store: &mut StoreOpaque) -> Rooted<T> {
1735 assert!(
1736 self.comes_from_same_store(store),
1737 "object used with wrong store"
1738 );
1739 let mut store = AutoAssertNoGc::new(store);
1740 let gc_ref = self.clone_gc_ref(&mut store).unwrap();
1741 Rooted::new(&mut store, gc_ref)
1742 }
1743
1744 /// Are these two GC roots referencing the same underlying GC object?
1745 ///
1746 /// This function will return `true` even when `a` and `b` are different GC
1747 /// roots (for example because they were rooted in different scopes) if they
1748 /// are rooting the same underlying GC object.
1749 ///
1750 /// Because this method takes any `impl RootedGcRef<T>` arguments, it can be
1751 /// used to compare, for example, a `Rooted<T>` and an `OwnedRooted<T>`.
1752 ///
1753 /// # Panics
1754 ///
1755 /// Panics if either `a` or `b` is not associated with the given `store`.
1756 ///
1757 /// # Example
1758 ///
1759 /// ```
1760 /// # use wasmtime::*;
1761 /// # fn foo() -> Result<()> {
1762 /// let mut store = Store::<()>::default();
1763 ///
1764 /// let a;
1765 /// let b;
1766 /// let x;
1767 ///
1768 /// {
1769 /// let mut scope = RootScope::new(&mut store);
1770 ///
1771 /// a = ExternRef::new(&mut scope, "hello")?.to_owned_rooted(&mut scope)?;
1772 /// b = a.clone();
1773 ///
1774 /// // `a` and `b` are rooting the same object.
1775 /// assert!(OwnedRooted::ref_eq(&scope, &a, &b)?);
1776 ///
1777 /// // `c` is a different GC root, is in a different scope, and is a
1778 /// // `Rooted<T>` instead of a `OwnedRooted<T>`, but is still rooting
1779 /// // the same object.
1780 /// let c = a.to_rooted(&mut scope);
1781 /// assert!(OwnedRooted::ref_eq(&scope, &a, &c)?);
1782 ///
1783 /// x = ExternRef::new(&mut scope, "goodbye")?.to_owned_rooted(&mut scope)?;
1784 ///
1785 /// // `a` and `x` are rooting different objects.
1786 /// assert!(!OwnedRooted::ref_eq(&scope, &a, &x)?);
1787 /// }
1788 /// # Ok(())
1789 /// # }
1790 /// ```
1791 pub fn ref_eq(
1792 store: impl AsContext,
1793 a: &impl RootedGcRef<T>,
1794 b: &impl RootedGcRef<T>,
1795 ) -> Result<bool> {
1796 Rooted::ref_eq(store, a, b)
1797 }
1798
1799 /// Hash this root.
1800 ///
1801 /// Note that, similar to `Rooted::rooted_eq`, this only operates on the
1802 /// root and *not* the underlying GC reference. That means that two
1803 /// different rootings of the same object will hash to different values
1804 /// (modulo hash collisions). If this is undesirable, use the
1805 /// [`ref_hash`][crate::OwnedRooted::ref_hash] method instead.
1806 pub fn rooted_hash<H>(&self, state: &mut H)
1807 where
1808 H: Hasher,
1809 {
1810 self.inner.hash(state);
1811 }
1812
1813 /// Hash the underlying rooted object reference.
1814 ///
1815 /// Note that, similar to `Rooted::ref_eq`, and operates on the underlying
1816 /// rooted GC object reference, not the root. That means that two
1817 /// *different* rootings of the same object will hash to the *same*
1818 /// value. If this is undesirable, use the
1819 /// [`rooted_hash`][crate::Rooted::rooted_hash] method instead.
1820 pub fn ref_hash<H>(&self, store: impl AsContext, state: &mut H)
1821 where
1822 H: Hasher,
1823 {
1824 let gc_ref = self
1825 .get_gc_ref(store.as_context().0)
1826 .expect("OwnedRooted's get_gc_ref is infallible");
1827 gc_ref.hash(state);
1828 }
1829
1830 /// Cast `self` to an `OwnedRooted<U>`.
1831 ///
1832 /// It is the caller's responsibility to ensure that `self` is actually a
1833 /// `U`. Failure to uphold this invariant will be memory safe but will
1834 /// result in general incorrectness such as panics and wrong results.
1835 pub(crate) fn unchecked_cast<U: GcRef>(self) -> OwnedRooted<U> {
1836 OwnedRooted {
1837 inner: self.inner,
1838 liveness_flag: self.liveness_flag,
1839 _phantom: core::marker::PhantomData,
1840 }
1841 }
1842
1843 /// Common implementation of the `WasmTy::store` trait method for all
1844 /// `OwnedRooted<T>`s.
1845 pub(super) fn wasm_ty_store(
1846 self,
1847 store: &mut AutoAssertNoGc<'_>,
1848 ptr: &mut MaybeUninit<ValRaw>,
1849 val_raw: impl Fn(u32) -> ValRaw,
1850 ) -> Result<()> {
1851 let raw = self.inner.expose_gc_ref_to_wasm(store)?;
1852 ptr.write(val_raw(raw.get()));
1853 Ok(())
1854 }
1855
1856 /// Common implementation of the `WasmTy::load` trait method for all
1857 /// `OwnedRooted<T>`s.
1858 pub(super) fn wasm_ty_load(
1859 store: &mut AutoAssertNoGc<'_>,
1860 raw_gc_ref: u32,
1861 from_cloned_gc_ref: impl Fn(&mut AutoAssertNoGc<'_>, VMGcRef) -> Rooted<T>,
1862 ) -> Self {
1863 debug_assert_ne!(raw_gc_ref, 0);
1864 let gc_ref = VMGcRef::from_raw_u32(raw_gc_ref).expect("non-null");
1865 let gc_ref = store.clone_gc_ref(&gc_ref);
1866 RootSet::with_lifo_scope(store, |store| {
1867 let rooted = from_cloned_gc_ref(store, gc_ref);
1868 rooted._to_owned_rooted(store).expect("rooted is in scope")
1869 })
1870 }
1871
1872 /// Common implementation of the `WasmTy::store` trait method for all
1873 /// `Option<OwnedRooted<T>>`s.
1874 pub(super) fn wasm_ty_option_store(
1875 me: Option<Self>,
1876 store: &mut AutoAssertNoGc<'_>,
1877 ptr: &mut MaybeUninit<ValRaw>,
1878 val_raw: impl Fn(u32) -> ValRaw,
1879 ) -> Result<()> {
1880 match me {
1881 Some(me) => me.wasm_ty_store(store, ptr, val_raw),
1882 None => {
1883 ptr.write(val_raw(0));
1884 Ok(())
1885 }
1886 }
1887 }
1888
1889 /// Common implementation of the `WasmTy::load` trait method for all
1890 /// `Option<OwnedRooted<T>>`s.
1891 pub(super) fn wasm_ty_option_load(
1892 store: &mut AutoAssertNoGc<'_>,
1893 raw_gc_ref: u32,
1894 from_cloned_gc_ref: impl Fn(&mut AutoAssertNoGc<'_>, VMGcRef) -> Rooted<T>,
1895 ) -> Option<Self> {
1896 let gc_ref = VMGcRef::from_raw_u32(raw_gc_ref)?;
1897 let gc_ref = store.clone_gc_ref(&gc_ref);
1898 RootSet::with_lifo_scope(store, |store| {
1899 let rooted = from_cloned_gc_ref(store, gc_ref);
1900 Some(rooted._to_owned_rooted(store).expect("rooted is in scope"))
1901 })
1902 }
1903
1904 #[doc(hidden)]
1905 pub fn into_parts_for_c_api(self) -> (NonZeroU64, u32, u32, *const ()) {
1906 (
1907 self.inner.store_id.as_raw(),
1908 self.inner.generation,
1909 self.inner.index.0,
1910 Arc::into_raw(self.liveness_flag),
1911 )
1912 }
1913
1914 #[doc(hidden)]
1915 pub unsafe fn from_borrowed_raw_parts_for_c_api(
1916 a: NonZeroU64,
1917 b: u32,
1918 c: u32,
1919 d: *const (),
1920 ) -> OwnedRooted<T> {
1921 // We are given a *borrow* of the Arc. This is a little
1922 // sketchy because `Arc::from_raw()` takes *ownership* of the
1923 // passed-in pointer, so we need to clone then forget that
1924 // original.
1925 let liveness_flag = {
1926 let original = unsafe { Arc::from_raw(d) };
1927 let clone = original.clone();
1928 core::mem::forget(original);
1929 clone
1930 };
1931 OwnedRooted {
1932 inner: GcRootIndex {
1933 store_id: StoreId::from_raw(a),
1934 generation: b,
1935 index: PackedIndex(c),
1936 },
1937 liveness_flag,
1938 _phantom: marker::PhantomData,
1939 }
1940 }
1941
1942 #[doc(hidden)]
1943 pub unsafe fn from_owned_raw_parts_for_c_api(
1944 a: NonZeroU64,
1945 b: u32,
1946 c: u32,
1947 d: *const (),
1948 ) -> OwnedRooted<T> {
1949 let liveness_flag = unsafe { Arc::from_raw(d) };
1950 OwnedRooted {
1951 inner: GcRootIndex {
1952 store_id: StoreId::from_raw(a),
1953 generation: b,
1954 index: PackedIndex(c),
1955 },
1956 liveness_flag,
1957 _phantom: marker::PhantomData,
1958 }
1959 }
1960}
1961
1962impl<T: GcRef> RootedGcRefImpl<T> for OwnedRooted<T> {
1963 fn get_gc_ref<'a>(&self, store: &'a StoreOpaque) -> Option<&'a VMGcRef> {
1964 assert!(
1965 self.comes_from_same_store(store),
1966 "object used with wrong store"
1967 );
1968
1969 let id = self.inner.index.as_owned().unwrap();
1970 store.gc_roots().owned_rooted.get(id)
1971 }
1972}
1973
1974#[cfg(test)]
1975mod tests {
1976 use crate::ExternRef;
1977
1978 use super::*;
1979
1980 #[test]
1981 fn sizes() {
1982 // Try to keep tabs on the size of these things. Don't want them growing
1983 // unintentionally.
1984 assert_eq!(std::mem::size_of::<Rooted<ExternRef>>(), 16);
1985 assert!(std::mem::size_of::<OwnedRooted<ExternRef>>() <= 24);
1986 }
1987}