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