1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
//! Target- and pointer-width-agnostic definitions of GC-related types and
//! constants.
//!
//! These definitions are suitable for use both during compilation and at
//! runtime.
//!
//! Note: We don't bother gating these on `cfg(feature = "gc")` because that
//! makes downstream uses pretty annoying, and the primary thing we want to gate
//! on our various `gc` cargo features is the actual garbage collection
//! functions and their associated impact on binary size anyways.

/// Discriminant to check whether GC reference is an `i31ref` or not.
pub const I31_DISCRIMINANT: u64 = 1;

/// A mask that can be used to check for non-null and non-i31ref GC references
/// with a single bitwise-and operation.
pub const NON_NULL_NON_I31_MASK: u64 = !I31_DISCRIMINANT;

/// The kind of an object in a GC heap.
///
/// This is accessed from Wasm JIT code.
#[repr(u32)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum VMGcKind {
    /// An `externref` holding some kind of host data.
    ExternRef = 0b00 << 30,
    //
    // When we support more GC types, we will complete this type with:
    //
    // /// An `anyref` (or one of its subtypes, other than `i31ref`).
    // AnyRef = 0b01 << 30,
    //
    // /// An `anyref` that was wrapped into an `externref` via
    // /// `extern.convert_any`.
    // ExternOfAnyRef = 0b10 << 30,
    //
    // /// An `externref` that was wrapped into an `anyref` via
    // /// `any.convert_extern`.
    // AnyOfExternRef = 0b11 << 30,
}

impl VMGcKind {
    /// Mask this value with a `u32` to turn it into a valid `VMGcKind`.
    pub const MASK: u32 = 0b11 << 30;

    /// Mask this value with a `u32` that potentially contains a `VMGcKind` to
    /// get the bits that `VMGcKind` doesn't use.
    pub const UNUSED_MASK: u32 = !Self::MASK;

    /// Convert the given value into a `VMGcKind` by masking off the unused
    /// bits.
    pub const fn from_u32(val: u32) -> VMGcKind {
        let masked = val & Self::MASK;
        assert!(
            masked == Self::ExternRef as u32,
            "not all masked bit patterns are valid `VMGcKind`s yet"
        );
        Self::ExternRef
    }
}