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