wasmtime_cranelift/
gc.rs

1//! Interface to compiling GC-related things.
2//!
3//! This module and its interface are implemented twice: once when the `gc`
4//! cargo feature is enabled and once when the feature is disabled. The goal is
5//! to have just a single `cfg(feature = "gc")` for the whole crate, which
6//! selects between these two implementations.
7
8use crate::func_environ::FuncEnvironment;
9use cranelift_codegen::ir;
10use cranelift_frontend::FunctionBuilder;
11use wasmtime_environ::{GcTypeLayouts, TypeIndex, WasmRefType, WasmResult};
12
13#[cfg(feature = "gc")]
14mod enabled;
15#[cfg(feature = "gc")]
16use enabled as imp;
17
18#[cfg(not(feature = "gc"))]
19mod disabled;
20#[cfg(not(feature = "gc"))]
21use disabled as imp;
22
23// Re-export the GC compilation interface from the implementation that we chose
24// based on the compile-time features enabled.
25pub use imp::*;
26
27/// How to initialize a newly-allocated array's elements.
28#[derive(Clone, Copy)]
29#[cfg_attr(not(any(feature = "gc-null", feature = "gc-drc")), allow(dead_code))]
30pub enum ArrayInit<'a> {
31    /// Initialize the array's elements with the given values.
32    Elems(&'a [ir::Value]),
33
34    /// Initialize the array's elements with `elem` repeated `len` times.
35    Fill { elem: ir::Value, len: ir::Value },
36}
37
38/// A trait for different collectors to emit any GC barriers they might require.
39pub trait GcCompiler {
40    /// Get the GC type layouts for this GC compiler.
41    #[cfg_attr(not(feature = "gc"), allow(dead_code))]
42    fn layouts(&self) -> &dyn GcTypeLayouts;
43
44    /// Emit code to allocate a new array.
45    ///
46    /// The array should be of the given type and its elements initialized as
47    /// described by the given `ArrayInit`.
48    #[cfg_attr(not(feature = "gc"), allow(dead_code))]
49    fn alloc_array(
50        &mut self,
51        func_env: &mut FuncEnvironment<'_>,
52        builder: &mut FunctionBuilder<'_>,
53        array_type_index: TypeIndex,
54        init: ArrayInit<'_>,
55    ) -> WasmResult<ir::Value>;
56
57    /// Emit code to allocate a new struct.
58    ///
59    /// The struct should be of the given type and its fields initialized to the
60    /// given values.
61    #[cfg_attr(not(feature = "gc"), allow(dead_code))]
62    fn alloc_struct(
63        &mut self,
64        func_env: &mut FuncEnvironment<'_>,
65        builder: &mut FunctionBuilder<'_>,
66        struct_type_index: TypeIndex,
67        fields: &[ir::Value],
68    ) -> WasmResult<ir::Value>;
69
70    /// Emit a read barrier for when we are cloning a GC reference onto the Wasm
71    /// stack.
72    ///
73    /// This is used, for example, when reading from a global or a table
74    /// element.
75    ///
76    /// In pseudocode, this is the following operation:
77    ///
78    /// ```ignore
79    /// x = *src;
80    /// ```
81    ///
82    /// Parameters:
83    ///
84    /// * `func_env`: The function environment that this GC compiler is
85    ///   operating within.
86    ///
87    /// * `builder`: Function builder. Currently at the position where the read
88    ///   should be inserted. Upon return, should be positioned where control
89    ///   continues just after the read completes. Any intermediate blocks
90    ///   created in the process of emitting the read barrier should be added to
91    ///   the layout and sealed.
92    ///
93    /// * `ty`: The Wasm reference type that is being read.
94    ///
95    /// * `src`: A pointer to the GC reference that should be read; this is an
96    ///   instance of a `*mut Option<VMGcRef>`.
97    ///
98    /// * `flags`: The memory flags that should be used when accessing `src`.
99    ///
100    /// This method should return the cloned GC reference (an instance of
101    /// `VMGcRef`) of type `i32`.
102    fn translate_read_gc_reference(
103        &mut self,
104        func_env: &mut FuncEnvironment<'_>,
105        builder: &mut FunctionBuilder,
106        ty: WasmRefType,
107        src: ir::Value,
108        flags: ir::MemFlags,
109    ) -> WasmResult<ir::Value>;
110
111    /// Emit a write barrier for when we are writing a GC reference over another
112    /// GC reference.
113    ///
114    /// This is used, for example, when writing to a global or a table element.
115    ///
116    /// In pseudocode, this is the following operation:
117    ///
118    /// ```ignore
119    /// *dst = new_val;
120    /// ```
121    ///
122    /// Parameters:
123    ///
124    /// * `func_env`: The function environment that this GC compiler is
125    ///   operating within.
126    ///
127    /// * `builder`: Function builder. Currently at the position where the write
128    ///   should be inserted. Upon return, should be positioned where control
129    ///   continues just after the write completes. Any intermediate blocks
130    ///   created in the process of emitting the read barrier should be added to
131    ///   the layout and sealed.
132    ///
133    /// * `ty`: The Wasm reference type that is being written.
134    ///
135    /// * `dst`: A pointer to the GC reference that will be overwritten; note
136    ///   that is this is an instance of a `*mut VMGcRef`, *not* a `VMGcRef`
137    ///   itself or a `*mut VMGcHeader`!
138    ///
139    /// * `new_val`: The new value that should be written into `dst`. This is a
140    ///   `VMGcRef` of Cranelift type `i32`; not a `*mut VMGcRef`.
141    ///
142    /// * `flags`: The memory flags that should be used when accessing `dst`.
143    fn translate_write_gc_reference(
144        &mut self,
145        func_env: &mut FuncEnvironment<'_>,
146        builder: &mut FunctionBuilder,
147        ty: WasmRefType,
148        dst: ir::Value,
149        new_val: ir::Value,
150        flags: ir::MemFlags,
151    ) -> WasmResult<()>;
152}
153
154pub mod builtins {
155    use super::*;
156
157    macro_rules! define_builtin_accessors {
158        ( $( $name:ident , )* ) => {
159            $(
160                #[inline]
161                pub fn $name(
162                    func_env: &mut FuncEnvironment<'_>,
163                    func: &mut ir::Function,
164                ) -> WasmResult<ir::FuncRef> {
165                    #[cfg(feature = "gc")]
166                    return Ok(func_env.builtin_functions.$name(func));
167
168                    #[cfg(not(feature = "gc"))]
169                    let _ = (func, func_env);
170                    #[cfg(not(feature = "gc"))]
171                    return Err(wasmtime_environ::wasm_unsupported!(
172                        "support for Wasm GC disabled at compile time because the `gc` cargo \
173                         feature was not enabled"
174                    ));
175                }
176            )*
177        };
178    }
179
180    define_builtin_accessors! {
181        table_grow_gc_ref,
182        table_fill_gc_ref,
183        array_new_data,
184        array_new_elem,
185        array_copy,
186        array_init_data,
187        array_init_elem,
188    }
189}