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}