Coverage Report

Created: 2025-12-04 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wasmtime/crates/winch/src/compiler.rs
Line
Count
Source
1
use anyhow::Result;
2
use cranelift_codegen::isa::unwind::UnwindInfoKind;
3
use object::write::{Object, SymbolId};
4
use std::any::Any;
5
use std::mem;
6
use std::sync::Mutex;
7
use wasmparser::FuncValidatorAllocations;
8
use wasmtime_cranelift::CompiledFunction;
9
#[cfg(feature = "component-model")]
10
use wasmtime_environ::component::ComponentTranslation;
11
use wasmtime_environ::{
12
    CompileError, CompiledFunctionBody, DefinedFuncIndex, FuncKey, FunctionBodyData, FunctionLoc,
13
    ModuleTranslation, ModuleTypesBuilder, PrimaryMap, StaticModuleIndex, Tunables, VMOffsets,
14
};
15
use winch_codegen::{BuiltinFunctions, CallingConvention, TargetIsa};
16
17
/// Function compilation context.
18
/// This struct holds information that can be shared globally across
19
/// all function compilations.
20
struct CompilationContext {
21
    /// Validator allocations.
22
    allocations: FuncValidatorAllocations,
23
    /// Builtin functions available to JIT code.
24
    builtins: BuiltinFunctions,
25
}
26
27
pub(crate) struct Compiler {
28
    isa: Box<dyn TargetIsa>,
29
    trampolines: NoInlineCompiler,
30
    contexts: Mutex<Vec<CompilationContext>>,
31
    tunables: Tunables,
32
}
33
34
impl Compiler {
35
5.83k
    pub fn new(
36
5.83k
        isa: Box<dyn TargetIsa>,
37
5.83k
        trampolines: Box<dyn wasmtime_environ::Compiler>,
38
5.83k
        tunables: Tunables,
39
5.83k
    ) -> Self {
40
5.83k
        Self {
41
5.83k
            isa,
42
5.83k
            trampolines: NoInlineCompiler(trampolines),
43
5.83k
            contexts: Mutex::new(Vec::new()),
44
5.83k
            tunables,
45
5.83k
        }
46
5.83k
    }
47
48
    /// Get a compilation context or create a new one if none available.
49
75.0k
    fn get_context(&self, translation: &ModuleTranslation) -> CompilationContext {
50
75.0k
        self.contexts.lock().unwrap().pop().unwrap_or_else(|| {
51
5.39k
            let pointer_size = self.isa.pointer_bytes();
52
5.39k
            let vmoffsets = VMOffsets::new(pointer_size, &translation.module);
53
5.39k
            CompilationContext {
54
5.39k
                allocations: Default::default(),
55
5.39k
                builtins: BuiltinFunctions::new(
56
5.39k
                    &vmoffsets,
57
5.39k
                    self.isa.wasmtime_call_conv(),
58
5.39k
                    CallingConvention::Default,
59
5.39k
                ),
60
5.39k
            }
61
5.39k
        })
62
75.0k
    }
63
64
    /// Save a compilation context.
65
75.0k
    fn save_context(&self, mut context: CompilationContext, allocs: FuncValidatorAllocations) {
66
75.0k
        context.allocations = allocs;
67
75.0k
        self.contexts.lock().unwrap().push(context);
68
75.0k
    }
69
70
    /// Emit unwind info into the [`CompiledFunction`].
71
30.2k
    fn emit_unwind_info(
72
30.2k
        &self,
73
30.2k
        compiled_function: &mut CompiledFunction,
74
30.2k
    ) -> Result<(), CompileError> {
75
30.2k
        let kind = match self.isa.triple().operating_system {
76
0
            target_lexicon::OperatingSystem::Windows => UnwindInfoKind::Windows,
77
30.2k
            _ => UnwindInfoKind::SystemV,
78
        };
79
80
30.2k
        if let Some(info) = self
81
30.2k
            .isa
82
30.2k
            .emit_unwind_info(&compiled_function.buffer, kind)
83
30.2k
            .map_err(|e| CompileError::Codegen(format!("{e:?}")))?
84
30.2k
        {
85
30.2k
            compiled_function.set_unwind_info(info);
86
30.2k
        }
87
88
30.2k
        Ok(())
89
30.2k
    }
90
}
91
92
75.0k
fn box_dyn_any_compiled_function(f: CompiledFunction) -> Box<dyn Any + Send + Sync> {
93
75.0k
    let b = box_dyn_any(f);
94
75.0k
    debug_assert!(b.is::<CompiledFunction>());
95
75.0k
    b
96
75.0k
}
97
98
75.0k
fn box_dyn_any(x: impl Any + Send + Sync) -> Box<dyn Any + Send + Sync> {
99
75.0k
    log::trace!(
100
0
        "making Box<dyn Any + Send + Sync> of {}",
101
0
        std::any::type_name_of_val(&x)
102
    );
103
75.0k
    let b = Box::new(x);
104
75.0k
    let r: &(dyn Any + Sync + Send) = &*b;
105
75.0k
    log::trace!("  --> {r:#p}");
106
75.0k
    b
107
75.0k
}
108
109
impl wasmtime_environ::Compiler for Compiler {
110
32.1k
    fn inlining_compiler(&self) -> Option<&dyn wasmtime_environ::InliningCompiler> {
111
32.1k
        None
112
32.1k
    }
113
114
75.0k
    fn compile_function(
115
75.0k
        &self,
116
75.0k
        translation: &ModuleTranslation<'_>,
117
75.0k
        key: FuncKey,
118
75.0k
        data: FunctionBodyData<'_>,
119
75.0k
        types: &ModuleTypesBuilder,
120
75.0k
        symbol: &str,
121
75.0k
    ) -> Result<CompiledFunctionBody, CompileError> {
122
75.0k
        log::trace!("compiling function: {key:?} = {symbol:?}");
123
124
75.0k
        let (module_index, def_func_index) = key.unwrap_defined_wasm_function();
125
75.0k
        debug_assert_eq!(module_index, translation.module_index());
126
127
75.0k
        let index = translation.module.func_index(def_func_index);
128
75.0k
        let sig = translation.module.functions[index]
129
75.0k
            .signature
130
75.0k
            .unwrap_module_type_index();
131
75.0k
        let ty = types[sig].unwrap_func();
132
        let FunctionBodyData {
133
75.0k
            body, validator, ..
134
75.0k
        } = data;
135
75.0k
        let mut context = self.get_context(translation);
136
75.0k
        let mut validator = validator.into_validator(mem::take(&mut context.allocations));
137
75.0k
        let func = self
138
75.0k
            .isa
139
75.0k
            .compile_function(
140
75.0k
                ty,
141
75.0k
                &body,
142
75.0k
                translation,
143
75.0k
                types,
144
75.0k
                &mut context.builtins,
145
75.0k
                &mut validator,
146
75.0k
                &self.tunables,
147
            )
148
75.0k
            .map_err(|e| CompileError::Codegen(format!("{e:?}")));
149
75.0k
        self.save_context(context, validator.into_allocations());
150
75.0k
        let mut func = func?;
151
152
75.0k
        let reader = body.get_binary_reader();
153
75.0k
        func.set_address_map(
154
75.0k
            reader.original_position() as u32,
155
75.0k
            reader.bytes_remaining() as u32,
156
75.0k
            self.tunables.generate_address_map,
157
        );
158
159
75.0k
        if self.isa.flags().unwind_info() {
160
30.2k
            self.emit_unwind_info(&mut func)?;
161
44.8k
        }
162
163
75.0k
        Ok(CompiledFunctionBody {
164
75.0k
            code: box_dyn_any_compiled_function(func),
165
75.0k
            // TODO: Winch doesn't support GC objects and stack maps and all that yet.
166
75.0k
            needs_gc_heap: false,
167
75.0k
        })
168
75.0k
    }
169
170
12.1k
    fn compile_array_to_wasm_trampoline(
171
12.1k
        &self,
172
12.1k
        translation: &ModuleTranslation<'_>,
173
12.1k
        types: &ModuleTypesBuilder,
174
12.1k
        key: FuncKey,
175
12.1k
        symbol: &str,
176
12.1k
    ) -> Result<CompiledFunctionBody, CompileError> {
177
12.1k
        self.trampolines
178
12.1k
            .compile_array_to_wasm_trampoline(translation, types, key, symbol)
179
12.1k
    }
180
181
15.9k
    fn compile_wasm_to_array_trampoline(
182
15.9k
        &self,
183
15.9k
        wasm_func_ty: &wasmtime_environ::WasmFuncType,
184
15.9k
        key: FuncKey,
185
15.9k
        symbol: &str,
186
15.9k
    ) -> Result<CompiledFunctionBody, CompileError> {
187
15.9k
        self.trampolines
188
15.9k
            .compile_wasm_to_array_trampoline(wasm_func_ty, key, symbol)
189
15.9k
    }
190
191
24.5k
    fn append_code(
192
24.5k
        &self,
193
24.5k
        obj: &mut Object<'static>,
194
24.5k
        funcs: &[(String, FuncKey, Box<dyn Any + Send + Sync>)],
195
24.5k
        resolve_reloc: &dyn Fn(usize, wasmtime_environ::FuncKey) -> usize,
196
24.5k
    ) -> Result<Vec<(SymbolId, FunctionLoc)>> {
197
24.5k
        self.trampolines.append_code(obj, funcs, resolve_reloc)
198
24.5k
    }
199
200
82.6k
    fn triple(&self) -> &target_lexicon::Triple {
201
82.6k
        self.isa.triple()
202
82.6k
    }
203
204
30.4k
    fn flags(&self) -> Vec<(&'static str, wasmtime_environ::FlagValue<'static>)> {
205
30.4k
        wasmtime_cranelift::clif_flags_to_wasmtime(self.isa.flags().iter())
206
30.4k
    }
207
208
30.4k
    fn isa_flags(&self) -> Vec<(&'static str, wasmtime_environ::FlagValue<'static>)> {
209
30.4k
        wasmtime_cranelift::clif_flags_to_wasmtime(self.isa.isa_flags())
210
30.4k
    }
211
212
24.5k
    fn is_branch_protection_enabled(&self) -> bool {
213
24.5k
        self.isa.is_branch_protection_enabled()
214
24.5k
    }
215
216
    #[cfg(feature = "component-model")]
217
2
    fn component_compiler(&self) -> &dyn wasmtime_environ::component::ComponentCompiler {
218
2
        self.trampolines.component_compiler()
219
2
    }
220
221
0
    fn append_dwarf<'a>(
222
0
        &self,
223
0
        _obj: &mut Object<'_>,
224
0
        _translations: &'a PrimaryMap<StaticModuleIndex, ModuleTranslation<'a>>,
225
0
        _get_func: &'a dyn Fn(
226
0
            StaticModuleIndex,
227
0
            DefinedFuncIndex,
228
0
        ) -> (SymbolId, &'a (dyn Any + Send + Sync)),
229
0
        _dwarf_package_bytes: Option<&'a [u8]>,
230
0
        _tunables: &'a Tunables,
231
0
    ) -> Result<()> {
232
0
        todo!()
233
    }
234
235
0
    fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
236
0
        self.isa.create_systemv_cie()
237
0
    }
238
239
7.47k
    fn compile_wasm_to_builtin(
240
7.47k
        &self,
241
7.47k
        key: FuncKey,
242
7.47k
        symbol: &str,
243
7.47k
    ) -> Result<CompiledFunctionBody, CompileError> {
244
7.47k
        self.trampolines.compile_wasm_to_builtin(key, symbol)
245
7.47k
    }
246
247
103k
    fn compiled_function_relocation_targets<'a>(
248
103k
        &'a self,
249
103k
        func: &'a dyn Any,
250
103k
    ) -> Box<dyn Iterator<Item = FuncKey> + 'a> {
251
103k
        self.trampolines.compiled_function_relocation_targets(func)
252
103k
    }
253
}
254
255
/// A wrapper around another `Compiler` implementation that may or may not be an
256
/// inlining compiler and turns it into a non-inlining compiler.
257
struct NoInlineCompiler(Box<dyn wasmtime_environ::Compiler>);
258
259
impl wasmtime_environ::Compiler for NoInlineCompiler {
260
0
    fn inlining_compiler(&self) -> Option<&dyn wasmtime_environ::InliningCompiler> {
261
0
        None
262
0
    }
263
264
0
    fn compile_function(
265
0
        &self,
266
0
        translation: &ModuleTranslation<'_>,
267
0
        key: FuncKey,
268
0
        data: FunctionBodyData<'_>,
269
0
        types: &ModuleTypesBuilder,
270
0
        symbol: &str,
271
0
    ) -> Result<CompiledFunctionBody, CompileError> {
272
0
        let input = data.body.clone();
273
0
        let mut body = self
274
0
            .0
275
0
            .compile_function(translation, key, data, types, symbol)?;
276
0
        if let Some(c) = self.0.inlining_compiler() {
277
0
            c.finish_compiling(&mut body, Some(input), symbol)
278
0
                .map_err(|e| CompileError::Codegen(e.to_string()))?;
279
0
        }
280
0
        Ok(body)
281
0
    }
282
283
12.1k
    fn compile_array_to_wasm_trampoline(
284
12.1k
        &self,
285
12.1k
        translation: &ModuleTranslation<'_>,
286
12.1k
        types: &ModuleTypesBuilder,
287
12.1k
        key: FuncKey,
288
12.1k
        symbol: &str,
289
12.1k
    ) -> Result<CompiledFunctionBody, CompileError> {
290
12.1k
        let mut body = self
291
12.1k
            .0
292
12.1k
            .compile_array_to_wasm_trampoline(translation, types, key, symbol)?;
293
12.1k
        if let Some(c) = self.0.inlining_compiler() {
294
12.1k
            c.finish_compiling(&mut body, None, symbol)
295
12.1k
                .map_err(|e| CompileError::Codegen(e.to_string()))?;
296
0
        }
297
12.1k
        Ok(body)
298
12.1k
    }
299
300
15.9k
    fn compile_wasm_to_array_trampoline(
301
15.9k
        &self,
302
15.9k
        wasm_func_ty: &wasmtime_environ::WasmFuncType,
303
15.9k
        key: FuncKey,
304
15.9k
        symbol: &str,
305
15.9k
    ) -> Result<CompiledFunctionBody, CompileError> {
306
15.9k
        let mut body = self
307
15.9k
            .0
308
15.9k
            .compile_wasm_to_array_trampoline(wasm_func_ty, key, symbol)?;
309
15.9k
        if let Some(c) = self.0.inlining_compiler() {
310
15.9k
            c.finish_compiling(&mut body, None, symbol)
311
15.9k
                .map_err(|e| CompileError::Codegen(e.to_string()))?;
312
0
        }
313
15.9k
        Ok(body)
314
15.9k
    }
315
316
7.47k
    fn compile_wasm_to_builtin(
317
7.47k
        &self,
318
7.47k
        key: FuncKey,
319
7.47k
        symbol: &str,
320
7.47k
    ) -> Result<CompiledFunctionBody, CompileError> {
321
7.47k
        let mut body = self.0.compile_wasm_to_builtin(key, symbol)?;
322
7.47k
        if let Some(c) = self.0.inlining_compiler() {
323
7.47k
            c.finish_compiling(&mut body, None, symbol)
324
7.47k
                .map_err(|e| CompileError::Codegen(e.to_string()))?;
325
0
        }
326
7.47k
        Ok(body)
327
7.47k
    }
328
329
103k
    fn compiled_function_relocation_targets<'a>(
330
103k
        &'a self,
331
103k
        func: &'a dyn Any,
332
103k
    ) -> Box<dyn Iterator<Item = FuncKey> + 'a> {
333
103k
        self.0.compiled_function_relocation_targets(func)
334
103k
    }
335
336
24.5k
    fn append_code(
337
24.5k
        &self,
338
24.5k
        obj: &mut Object<'static>,
339
24.5k
        funcs: &[(String, FuncKey, Box<dyn Any + Send + Sync>)],
340
24.5k
        resolve_reloc: &dyn Fn(usize, FuncKey) -> usize,
341
24.5k
    ) -> Result<Vec<(SymbolId, FunctionLoc)>> {
342
24.5k
        self.0.append_code(obj, funcs, resolve_reloc)
343
24.5k
    }
344
345
0
    fn triple(&self) -> &target_lexicon::Triple {
346
0
        self.0.triple()
347
0
    }
348
349
0
    fn flags(&self) -> Vec<(&'static str, wasmtime_environ::FlagValue<'static>)> {
350
0
        self.0.flags()
351
0
    }
352
353
0
    fn isa_flags(&self) -> Vec<(&'static str, wasmtime_environ::FlagValue<'static>)> {
354
0
        self.0.isa_flags()
355
0
    }
356
357
0
    fn is_branch_protection_enabled(&self) -> bool {
358
0
        self.0.is_branch_protection_enabled()
359
0
    }
360
361
    #[cfg(feature = "component-model")]
362
2
    fn component_compiler(&self) -> &dyn wasmtime_environ::component::ComponentCompiler {
363
2
        self
364
2
    }
365
366
0
    fn append_dwarf<'a>(
367
0
        &self,
368
0
        obj: &mut Object<'_>,
369
0
        translations: &'a PrimaryMap<StaticModuleIndex, ModuleTranslation<'a>>,
370
0
        get_func: &'a dyn Fn(
371
0
            StaticModuleIndex,
372
0
            DefinedFuncIndex,
373
0
        ) -> (SymbolId, &'a (dyn Any + Send + Sync)),
374
0
        dwarf_package_bytes: Option<&'a [u8]>,
375
0
        tunables: &'a Tunables,
376
0
    ) -> Result<()> {
377
0
        self.0
378
0
            .append_dwarf(obj, translations, get_func, dwarf_package_bytes, tunables)
379
0
    }
380
}
381
382
#[cfg(feature = "component-model")]
383
impl wasmtime_environ::component::ComponentCompiler for NoInlineCompiler {
384
2
    fn compile_trampoline(
385
2
        &self,
386
2
        component: &wasmtime_environ::component::ComponentTranslation,
387
2
        types: &wasmtime_environ::component::ComponentTypesBuilder,
388
2
        key: FuncKey,
389
2
        abi: wasmtime_environ::Abi,
390
2
        tunables: &Tunables,
391
2
        symbol: &str,
392
2
    ) -> Result<CompiledFunctionBody> {
393
2
        let mut body = self
394
2
            .0
395
2
            .component_compiler()
396
2
            .compile_trampoline(component, types, key, abi, tunables, symbol)?;
397
2
        if let Some(c) = self.0.inlining_compiler() {
398
2
            c.finish_compiling(&mut body, None, symbol)
399
2
                .map_err(|e| CompileError::Codegen(e.to_string()))?;
400
0
        }
401
2
        Ok(body)
402
2
    }
403
404
0
    fn compile_intrinsic(
405
0
        &self,
406
0
        tunables: &Tunables,
407
0
        component: &ComponentTranslation,
408
0
        types: &wasmtime_environ::component::ComponentTypesBuilder,
409
0
        intrinsic: wasmtime_environ::component::UnsafeIntrinsic,
410
0
        abi: wasmtime_environ::Abi,
411
0
        symbol: &str,
412
0
    ) -> Result<CompiledFunctionBody> {
413
0
        let mut body = self
414
0
            .0
415
0
            .component_compiler()
416
0
            .compile_intrinsic(tunables, component, types, intrinsic, abi, symbol)?;
417
0
        if let Some(c) = self.0.inlining_compiler() {
418
0
            c.finish_compiling(&mut body, None, symbol)
419
0
                .map_err(|e| CompileError::Codegen(e.to_string()))?;
420
0
        }
421
0
        Ok(body)
422
0
    }
423
}