wasmtime_internal_cranelift/func_environ/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, TagIndex, 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(feature = "gc"), expect(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 code to allocate a new exception object.
71 ///
72 /// The exception object should be of the given type and its
73 /// fields initialized to the given values. The tag field is left
74 /// uninitialized; that is the responsibility of generated code to
75 /// fill in. `tag_index` is used only to look up the appropriate
76 /// exception object type.
77 #[cfg_attr(not(feature = "gc"), allow(dead_code))]
78 fn alloc_exn(
79 &mut self,
80 func_env: &mut FuncEnvironment<'_>,
81 builder: &mut FunctionBuilder<'_>,
82 tag_index: TagIndex,
83 fields: &[ir::Value],
84 instance_id: ir::Value,
85 tag: ir::Value,
86 ) -> WasmResult<ir::Value>;
87
88 /// Emit a read barrier for when we are cloning a GC reference onto the Wasm
89 /// stack.
90 ///
91 /// This is used, for example, when reading from a global or a table
92 /// element.
93 ///
94 /// In pseudocode, this is the following operation:
95 ///
96 /// ```ignore
97 /// x = *src;
98 /// ```
99 ///
100 /// Parameters:
101 ///
102 /// * `func_env`: The function environment that this GC compiler is
103 /// operating within.
104 ///
105 /// * `builder`: Function builder. Currently at the position where the read
106 /// should be inserted. Upon return, should be positioned where control
107 /// continues just after the read completes. Any intermediate blocks
108 /// created in the process of emitting the read barrier should be added to
109 /// the layout and sealed.
110 ///
111 /// * `ty`: The Wasm reference type that is being read.
112 ///
113 /// * `src`: A pointer to the GC reference that should be read; this is an
114 /// instance of a `*mut Option<VMGcRef>`.
115 ///
116 /// * `flags`: The memory flags that should be used when accessing `src`.
117 ///
118 /// This method should return the cloned GC reference (an instance of
119 /// `VMGcRef`) of type `i32`.
120 fn translate_read_gc_reference(
121 &mut self,
122 func_env: &mut FuncEnvironment<'_>,
123 builder: &mut FunctionBuilder,
124 ty: WasmRefType,
125 src: ir::Value,
126 flags: ir::MemFlags,
127 ) -> WasmResult<ir::Value>;
128
129 /// Emit a write barrier for when we are writing a GC reference over another
130 /// GC reference.
131 ///
132 /// This is used, for example, when writing to a global or a table element.
133 ///
134 /// In pseudocode, this is the following operation:
135 ///
136 /// ```ignore
137 /// *dst = new_val;
138 /// ```
139 ///
140 /// Parameters:
141 ///
142 /// * `func_env`: The function environment that this GC compiler is
143 /// operating within.
144 ///
145 /// * `builder`: Function builder. Currently at the position where the write
146 /// should be inserted. Upon return, should be positioned where control
147 /// continues just after the write completes. Any intermediate blocks
148 /// created in the process of emitting the read barrier should be added to
149 /// the layout and sealed.
150 ///
151 /// * `ty`: The Wasm reference type that is being written.
152 ///
153 /// * `dst`: A pointer to the GC reference that will be overwritten; note
154 /// that is this is an instance of a `*mut VMGcRef`, *not* a `VMGcRef`
155 /// itself or a `*mut VMGcHeader`!
156 ///
157 /// * `new_val`: The new value that should be written into `dst`. This is a
158 /// `VMGcRef` of Cranelift type `i32`; not a `*mut VMGcRef`.
159 ///
160 /// * `flags`: The memory flags that should be used when accessing `dst`.
161 fn translate_write_gc_reference(
162 &mut self,
163 func_env: &mut FuncEnvironment<'_>,
164 builder: &mut FunctionBuilder,
165 ty: WasmRefType,
166 dst: ir::Value,
167 new_val: ir::Value,
168 flags: ir::MemFlags,
169 ) -> WasmResult<()>;
170}
171
172pub mod builtins {
173 use super::*;
174
175 macro_rules! define_builtin_accessors {
176 ( $( $name:ident , )* ) => {
177 $(
178 #[inline]
179 pub fn $name(
180 func_env: &mut FuncEnvironment<'_>,
181 func: &mut ir::Function,
182 ) -> WasmResult<ir::FuncRef> {
183 #[cfg(feature = "gc")]
184 {
185 func_env.needs_gc_heap = true;
186 return Ok(func_env.builtin_functions.$name(func));
187 }
188
189 #[cfg(not(feature = "gc"))]
190 {
191 let _ = (func, func_env);
192 return Err(wasmtime_environ::wasm_unsupported!(
193 "support for Wasm GC disabled at compile time because the `gc` cargo \
194 feature was not enabled"
195 ));
196 }
197 }
198 )*
199 };
200 }
201
202 define_builtin_accessors! {
203 table_grow_gc_ref,
204 table_fill_gc_ref,
205 array_new_data,
206 array_new_elem,
207 array_copy,
208 array_init_data,
209 array_init_elem,
210 }
211}