wasmtime/runtime/gc.rs
1#[cfg(feature = "gc")]
2mod enabled;
3#[cfg(feature = "gc")]
4pub use enabled::*;
5
6#[cfg(not(feature = "gc"))]
7mod disabled;
8#[cfg(not(feature = "gc"))]
9pub use disabled::*;
10
11mod noextern;
12pub use noextern::NoExtern;
13
14mod none_ref;
15pub use none_ref::NoneRef;
16
17use core::fmt;
18use core::ops::Deref;
19
20/// A common trait implemented by all garbage-collected reference types.
21///
22/// This is a sealed trait, and may not be implemented for any types outside of
23/// the `wasmtime` crate.
24pub trait GcRef: GcRefImpl {}
25
26impl<T> GcRef for T where T: GcRefImpl {}
27
28/// A trait implemented for GC references that are guaranteed to be rooted:
29///
30/// * [`Rooted<T>`][crate::Rooted]
31/// * [`ManuallyRooted<T>`][crate::ManuallyRooted]
32///
33/// You can use this to abstract over the different kinds of rooted GC
34/// references. Note that `Deref<Target = T>` is a supertrait for
35/// `RootedGcRef<T>`, so all rooted GC references deref to their underlying `T`,
36/// allowing you to call its methods.
37///
38/// This is a sealed trait, and may not be implemented for any types outside of
39/// the `wasmtime` crate.
40pub trait RootedGcRef<T>: RootedGcRefImpl<T> + Deref<Target = T>
41where
42 T: GcRef,
43{
44}
45
46impl<T, U> RootedGcRef<T> for U
47where
48 T: GcRef,
49 U: RootedGcRefImpl<T> + Deref<Target = T>,
50{
51}
52
53/// An error returned when attempting to allocate a GC-managed object, but the
54/// GC heap is out of memory.
55///
56/// This error wraps an inner `T` value -- which is the host value, if any, that
57/// was passed to [`ExternRef::new`][crate::ExternRef::new] -- and you can
58/// recover this value via the
59/// [`into_inner`][crate::GcHeapOutOfMemory::into_inner] method. This lets you
60/// try to allocate the `externref` again, after performing a GC to hopefully
61/// free up space in the heap, or otherwise do whatever you want with the inner
62/// value.
63///
64/// For errors that occur when attempting to allocate non-`externref` objects
65/// when the GC heap is at capacity, the `T` type parameter is just the unit
66/// type `()`.
67pub struct GcHeapOutOfMemory<T> {
68 inner: T,
69 bytes_needed: u64,
70}
71
72impl<T> fmt::Debug for GcHeapOutOfMemory<T> {
73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 fmt::Display::fmt(self, f)
75 }
76}
77
78impl<T> fmt::Display for GcHeapOutOfMemory<T> {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 write!(
81 f,
82 "GC heap out of memory: no capacity for allocation of {} bytes",
83 self.bytes_needed
84 )
85 }
86}
87
88impl<T> core::error::Error for GcHeapOutOfMemory<T> {}
89
90impl<T> GcHeapOutOfMemory<T> {
91 pub(crate) fn new(inner: T, bytes_needed: u64) -> Self {
92 Self {
93 inner,
94 bytes_needed,
95 }
96 }
97
98 #[cfg(feature = "gc")]
99 pub(crate) fn bytes_needed(&self) -> u64 {
100 self.bytes_needed
101 }
102
103 #[cfg(feature = "gc")]
104 pub(crate) fn map_inner<U>(self, f: impl FnOnce(T) -> U) -> GcHeapOutOfMemory<U> {
105 GcHeapOutOfMemory {
106 inner: f(self.inner),
107 bytes_needed: self.bytes_needed,
108 }
109 }
110
111 /// Recover this error's inner host value.
112 pub fn into_inner(self) -> T {
113 self.inner
114 }
115
116 /// Take this error's inner host value, but also retain this
117 /// `GcHeapOutOfMemory` with `T` replaced with `()`.
118 ///
119 /// This allows you to both extract the inner `T` if necessary, and also
120 /// pass the `GcHeapOutOfMemory` error to [`Store::gc`][crate::Store::gc]
121 /// calls.
122 pub fn take_inner(self) -> (T, GcHeapOutOfMemory<()>) {
123 (self.inner, GcHeapOutOfMemory::new((), self.bytes_needed))
124 }
125}