wasmtime_environ/
gc.rs

1//! Target- and pointer-width-agnostic definitions of GC-related types and
2//! constants.
3//!
4//! These definitions are suitable for use both during compilation and at
5//! runtime.
6//!
7//! Note: We don't bother gating these on `cfg(feature = "gc")` because that
8//! makes downstream uses pretty annoying, and the primary thing we want to gate
9//! on our various `gc` cargo features is the actual garbage collection
10//! functions and their associated impact on binary size anyways.
11
12/// Discriminant to check whether GC reference is an `i31ref` or not.
13pub const I31_DISCRIMINANT: u64 = 1;
14
15/// A mask that can be used to check for non-null and non-i31ref GC references
16/// with a single bitwise-and operation.
17pub const NON_NULL_NON_I31_MASK: u64 = !I31_DISCRIMINANT;
18
19/// The kind of an object in a GC heap.
20///
21/// Note that this type is accessed from Wasm JIT code.
22///
23/// `VMGcKind` is a bitset where to test if `a` is a subtype of an
24/// "abstract-ish" type `b`, we can simply use a single bitwise-and operation:
25///
26/// ```ignore
27/// a <: b   iff   a & b == b
28/// ```
29///
30/// For example, because `VMGcKind::AnyRef` has the high bit set, every kind
31/// representing some subtype of `anyref` also has its high bit set.
32///
33/// We say "abstract-ish" type because in addition to the abstract heap types
34/// (other than `i31`) we also have variants for `externref`s that have been
35/// converted into an `anyref` via `extern.convert_any` and `externref`s that
36/// have been converted into an `anyref` via `any.convert_extern`. Note that in
37/// the latter case, because `any.convert_extern $foo` produces a value that is
38/// not an instance of `eqref`, `VMGcKind::AnyOfExternRef & VMGcKind::EqRef !=
39/// VMGcKind::EqRef`.
40///
41/// Furthermore, this type only uses the highest 6 bits of its `u32`
42/// representation, allowing the lower 26 bytes to be bitpacked with other stuff
43/// as users see fit.
44#[repr(u32)]
45#[derive(Clone, Copy, Debug, PartialEq, Eq)]
46#[rustfmt::skip]
47#[allow(missing_docs)]
48pub enum VMGcKind {
49    ExternRef      = 0b010000 << 26,
50    ExternOfAnyRef = 0b011000 << 26,
51    AnyRef         = 0b100000 << 26,
52    AnyOfExternRef = 0b100100 << 26,
53    EqRef          = 0b101000 << 26,
54    ArrayRef       = 0b101001 << 26,
55    StructRef      = 0b101010 << 26,
56}
57
58impl VMGcKind {
59    /// Mask this value with a `u32` to get just the bits that `VMGcKind` uses.
60    pub const MASK: u32 = 0b111111 << 26;
61
62    /// Mask this value with a `u32` that potentially contains a `VMGcKind` to
63    /// get the bits that `VMGcKind` doesn't use.
64    pub const UNUSED_MASK: u32 = !Self::MASK;
65
66    /// Convert the given value into a `VMGcKind` by masking off the unused
67    /// bottom bits.
68    pub fn from_high_bits_of_u32(val: u32) -> VMGcKind {
69        let masked = val & Self::MASK;
70        match masked {
71            x if x == Self::ExternRef as u32 => Self::ExternRef,
72            x if x == Self::ExternOfAnyRef as u32 => Self::ExternOfAnyRef,
73            x if x == Self::AnyRef as u32 => Self::AnyRef,
74            x if x == Self::AnyOfExternRef as u32 => Self::AnyOfExternRef,
75            x if x == Self::EqRef as u32 => Self::EqRef,
76            x if x == Self::ArrayRef as u32 => Self::ArrayRef,
77            x if x == Self::StructRef as u32 => Self::StructRef,
78            _ => panic!("invalid `VMGcKind`: {masked:#032b}"),
79        }
80    }
81
82    /// Does this kind match the other kind?
83    ///
84    /// That is, is this kind a subtype of the other kind?
85    pub fn matches(self, other: Self) -> bool {
86        (self as u32) & (other as u32) == (other as u32)
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    use super::VMGcKind::*;
93    use crate::prelude::*;
94
95    #[test]
96    fn kind_matches() {
97        let all = [
98            ExternRef,
99            ExternOfAnyRef,
100            AnyRef,
101            AnyOfExternRef,
102            EqRef,
103            ArrayRef,
104            StructRef,
105        ];
106
107        for (sup, subs) in [
108            (ExternRef, vec![ExternOfAnyRef]),
109            (ExternOfAnyRef, vec![]),
110            (AnyRef, vec![AnyOfExternRef, EqRef, ArrayRef, StructRef]),
111            (AnyOfExternRef, vec![]),
112            (EqRef, vec![ArrayRef, StructRef]),
113            (ArrayRef, vec![]),
114            (StructRef, vec![]),
115        ] {
116            assert!(sup.matches(sup));
117            for sub in &subs {
118                assert!(sub.matches(sup));
119            }
120            for kind in all.iter().filter(|k| **k != sup && !subs.contains(k)) {
121                assert!(!kind.matches(sup));
122            }
123        }
124    }
125}