1use anyhow::Result;
2use cranelift_codegen::isa::unwind::UnwindInfoKind;
3use object::write::{Object, SymbolId};
4use std::any::Any;
5use std::mem;
6use std::sync::Mutex;
7use wasmparser::FuncValidatorAllocations;
8use wasmtime_cranelift::{CompiledFunction, ModuleTextBuilder};
9use wasmtime_environ::{
10 AddressMapSection, BuiltinFunctionIndex, CompileError, DefinedFuncIndex, FunctionBodyData,
11 FunctionLoc, ModuleTranslation, ModuleTypesBuilder, PrimaryMap, RelocationTarget,
12 StaticModuleIndex, TrapEncodingBuilder, Tunables, VMOffsets, WasmFunctionInfo,
13};
14use winch_codegen::{BuiltinFunctions, CallingConvention, TargetIsa};
15
16struct CompilationContext {
20 allocations: FuncValidatorAllocations,
22 builtins: BuiltinFunctions,
24}
25
26pub(crate) struct Compiler {
27 isa: Box<dyn TargetIsa>,
28 trampolines: Box<dyn wasmtime_environ::Compiler>,
29 contexts: Mutex<Vec<CompilationContext>>,
30 tunables: Tunables,
31}
32
33impl Compiler {
34 pub fn new(
35 isa: Box<dyn TargetIsa>,
36 trampolines: Box<dyn wasmtime_environ::Compiler>,
37 tunables: Tunables,
38 ) -> Self {
39 Self {
40 isa,
41 trampolines,
42 contexts: Mutex::new(Vec::new()),
43 tunables,
44 }
45 }
46
47 fn get_context(&self, translation: &ModuleTranslation) -> CompilationContext {
49 self.contexts.lock().unwrap().pop().unwrap_or_else(|| {
50 let pointer_size = self.isa.pointer_bytes();
51 let vmoffsets = VMOffsets::new(pointer_size, &translation.module);
52 CompilationContext {
53 allocations: Default::default(),
54 builtins: BuiltinFunctions::new(
55 &vmoffsets,
56 self.isa.wasmtime_call_conv(),
57 CallingConvention::Default,
58 ),
59 }
60 })
61 }
62
63 fn save_context(&self, mut context: CompilationContext, allocs: FuncValidatorAllocations) {
65 context.allocations = allocs;
66 self.contexts.lock().unwrap().push(context);
67 }
68
69 fn emit_unwind_info(
71 &self,
72 compiled_function: &mut CompiledFunction,
73 ) -> Result<(), CompileError> {
74 let kind = match self.isa.triple().operating_system {
75 target_lexicon::OperatingSystem::Windows => UnwindInfoKind::Windows,
76 _ => UnwindInfoKind::SystemV,
77 };
78
79 if let Some(info) = self
80 .isa
81 .emit_unwind_info(&compiled_function.buffer, kind)
82 .map_err(|e| CompileError::Codegen(format!("{e:?}")))?
83 {
84 compiled_function.set_unwind_info(info);
85 }
86
87 Ok(())
88 }
89}
90
91impl wasmtime_environ::Compiler for Compiler {
92 fn compile_function(
93 &self,
94 translation: &ModuleTranslation<'_>,
95 index: DefinedFuncIndex,
96 data: FunctionBodyData<'_>,
97 types: &ModuleTypesBuilder,
98 ) -> Result<(WasmFunctionInfo, Box<dyn Any + Send>), CompileError> {
99 let index = translation.module.func_index(index);
100 let sig = translation.module.functions[index]
101 .signature
102 .unwrap_module_type_index();
103 let ty = types[sig].unwrap_func();
104 let FunctionBodyData {
105 body, validator, ..
106 } = data;
107 let mut context = self.get_context(translation);
108 let mut validator = validator.into_validator(mem::take(&mut context.allocations));
109 let func = self
110 .isa
111 .compile_function(
112 ty,
113 &body,
114 translation,
115 types,
116 &mut context.builtins,
117 &mut validator,
118 &self.tunables,
119 )
120 .map_err(|e| CompileError::Codegen(format!("{e:?}")));
121 self.save_context(context, validator.into_allocations());
122 let mut func = func?;
123
124 let reader = body.get_binary_reader();
125 func.set_address_map(
126 reader.original_position() as u32,
127 reader.bytes_remaining() as u32,
128 self.tunables.generate_address_map,
129 );
130
131 if self.isa.flags().unwind_info() {
132 self.emit_unwind_info(&mut func)?;
133 }
134
135 Ok((
136 WasmFunctionInfo {
137 start_srcloc: func.metadata().address_map.start_srcloc,
138 stack_maps: Box::new([]),
139 },
140 Box::new(func),
141 ))
142 }
143
144 fn compile_array_to_wasm_trampoline(
145 &self,
146 translation: &ModuleTranslation<'_>,
147 types: &ModuleTypesBuilder,
148 index: DefinedFuncIndex,
149 ) -> Result<Box<dyn Any + Send>, CompileError> {
150 self.trampolines
151 .compile_array_to_wasm_trampoline(translation, types, index)
152 }
153
154 fn compile_wasm_to_array_trampoline(
155 &self,
156 wasm_func_ty: &wasmtime_environ::WasmFuncType,
157 ) -> Result<Box<dyn Any + Send>, CompileError> {
158 self.trampolines
159 .compile_wasm_to_array_trampoline(wasm_func_ty)
160 }
161
162 fn append_code(
163 &self,
164 obj: &mut Object<'static>,
165 funcs: &[(String, Box<dyn Any + Send>)],
166 resolve_reloc: &dyn Fn(usize, wasmtime_environ::RelocationTarget) -> usize,
167 ) -> Result<Vec<(SymbolId, FunctionLoc)>> {
168 let mut builder =
169 ModuleTextBuilder::new(obj, self, self.isa.text_section_builder(funcs.len()));
170 let mut traps = TrapEncodingBuilder::default();
171 let mut addrs = AddressMapSection::default();
172
173 let mut ret = Vec::with_capacity(funcs.len());
174 for (i, (sym, func)) in funcs.iter().enumerate() {
175 let func = func.downcast_ref::<CompiledFunction>().unwrap();
176
177 let (sym, range) = builder.append_func(&sym, func, |idx| resolve_reloc(i, idx));
178 if self.tunables.generate_address_map {
179 addrs.push(range.clone(), &func.address_map().instructions);
180 }
181 traps.push(range.clone(), &func.traps().collect::<Vec<_>>());
182
183 let info = FunctionLoc {
184 start: u32::try_from(range.start).unwrap(),
185 length: u32::try_from(range.end - range.start).unwrap(),
186 };
187 ret.push((sym, info));
188 }
189 builder.finish();
190 if self.tunables.generate_address_map {
191 addrs.append_to(obj);
192 }
193 traps.append_to(obj);
194 Ok(ret)
195 }
196
197 fn triple(&self) -> &target_lexicon::Triple {
198 self.isa.triple()
199 }
200
201 fn flags(&self) -> Vec<(&'static str, wasmtime_environ::FlagValue<'static>)> {
202 wasmtime_cranelift::clif_flags_to_wasmtime(self.isa.flags().iter())
203 }
204
205 fn isa_flags(&self) -> Vec<(&'static str, wasmtime_environ::FlagValue<'static>)> {
206 wasmtime_cranelift::clif_flags_to_wasmtime(self.isa.isa_flags())
207 }
208
209 fn is_branch_protection_enabled(&self) -> bool {
210 self.isa.is_branch_protection_enabled()
211 }
212
213 #[cfg(feature = "component-model")]
214 fn component_compiler(&self) -> &dyn wasmtime_environ::component::ComponentCompiler {
215 self.trampolines.component_compiler()
216 }
217
218 fn append_dwarf<'a>(
219 &self,
220 _obj: &mut Object<'_>,
221 _translations: &'a PrimaryMap<StaticModuleIndex, ModuleTranslation<'a>>,
222 _get_func: &'a dyn Fn(
223 StaticModuleIndex,
224 DefinedFuncIndex,
225 ) -> (SymbolId, &'a (dyn Any + Send)),
226 _dwarf_package_bytes: Option<&'a [u8]>,
227 _tunables: &'a Tunables,
228 ) -> Result<()> {
229 todo!()
230 }
231
232 fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
233 self.isa.create_systemv_cie()
234 }
235
236 fn compile_wasm_to_builtin(
237 &self,
238 index: BuiltinFunctionIndex,
239 ) -> Result<Box<dyn Any + Send>, CompileError> {
240 self.trampolines.compile_wasm_to_builtin(index)
241 }
242
243 fn compiled_function_relocation_targets<'a>(
244 &'a self,
245 func: &'a dyn Any,
246 ) -> Box<dyn Iterator<Item = RelocationTarget> + 'a> {
247 self.trampolines.compiled_function_relocation_targets(func)
248 }
249}