wasmtime_environ/compile/mod.rs
1//! A `Compilation` contains the compiled function bodies for a WebAssembly
2//! module.
3
4use crate::prelude::*;
5use crate::{
6 BuiltinFunctionIndex, DefinedFuncIndex, FlagValue, FuncIndex, FunctionLoc, ObjectKind,
7 PrimaryMap, StaticModuleIndex, TripleExt, WasmError, WasmFuncType,
8};
9use crate::{Tunables, obj};
10use anyhow::Result;
11use object::write::{Object, SymbolId};
12use object::{Architecture, BinaryFormat, FileFlags};
13use std::any::Any;
14use std::borrow::Cow;
15use std::fmt;
16use std::path;
17use std::sync::Arc;
18
19mod address_map;
20mod module_artifacts;
21mod module_environ;
22mod module_types;
23mod stack_maps;
24mod trap_encoding;
25
26pub use self::address_map::*;
27pub use self::module_artifacts::*;
28pub use self::module_environ::*;
29pub use self::module_types::*;
30pub use self::stack_maps::*;
31pub use self::trap_encoding::*;
32
33/// An error while compiling WebAssembly to machine code.
34#[derive(Debug)]
35pub enum CompileError {
36 /// A wasm translation error occurred.
37 Wasm(WasmError),
38
39 /// A compilation error occurred.
40 Codegen(String),
41
42 /// A compilation error occurred.
43 DebugInfoNotSupported,
44}
45
46impl fmt::Display for CompileError {
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 match self {
49 CompileError::Wasm(_) => write!(f, "WebAssembly translation error"),
50 CompileError::Codegen(s) => write!(f, "Compilation error: {s}"),
51 CompileError::DebugInfoNotSupported => {
52 write!(f, "Debug info is not supported with this configuration")
53 }
54 }
55 }
56}
57
58impl From<WasmError> for CompileError {
59 fn from(err: WasmError) -> CompileError {
60 CompileError::Wasm(err)
61 }
62}
63
64impl core::error::Error for CompileError {
65 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
66 match self {
67 CompileError::Wasm(e) => Some(e),
68 _ => None,
69 }
70 }
71}
72
73/// What relocations can be applied against.
74///
75/// Each wasm function may refer to various other `RelocationTarget` entries.
76#[derive(Copy, Clone, Debug, PartialEq, Eq)]
77pub enum RelocationTarget {
78 /// This is a reference to another defined wasm function in the same module.
79 Wasm(FuncIndex),
80 /// This is a reference to a trampoline for a builtin function.
81 Builtin(BuiltinFunctionIndex),
82 /// A pulley->host call from the interpreter.
83 PulleyHostcall(u32),
84}
85
86/// Implementation of an incremental compilation's key/value cache store.
87///
88/// In theory, this could just be Cranelift's `CacheKvStore` trait, but it is not as we want to
89/// make sure that wasmtime isn't too tied to Cranelift internals (and as a matter of fact, we
90/// can't depend on the Cranelift trait here).
91pub trait CacheStore: Send + Sync + std::fmt::Debug {
92 /// Try to retrieve an arbitrary cache key entry, and returns a reference to bytes that were
93 /// inserted via `Self::insert` before.
94 fn get(&self, key: &[u8]) -> Option<Cow<'_, [u8]>>;
95
96 /// Given an arbitrary key and bytes, stores them in the cache.
97 ///
98 /// Returns false when insertion in the cache failed.
99 fn insert(&self, key: &[u8], value: Vec<u8>) -> bool;
100}
101
102/// Abstract trait representing the ability to create a `Compiler` below.
103///
104/// This is used in Wasmtime to separate compiler implementations, currently
105/// mostly used to separate Cranelift from Wasmtime itself.
106pub trait CompilerBuilder: Send + Sync + fmt::Debug {
107 /// Sets the target of compilation to the target specified.
108 fn target(&mut self, target: target_lexicon::Triple) -> Result<()>;
109
110 /// Enables clif output in the directory specified.
111 fn clif_dir(&mut self, _path: &path::Path) -> Result<()> {
112 anyhow::bail!("clif output not supported");
113 }
114
115 /// Returns the currently configured target triple that compilation will
116 /// produce artifacts for.
117 fn triple(&self) -> &target_lexicon::Triple;
118
119 /// Compiler-specific method to configure various settings in the compiler
120 /// itself.
121 ///
122 /// This is expected to be defined per-compiler. Compilers should return
123 /// errors for unknown names/values.
124 fn set(&mut self, name: &str, val: &str) -> Result<()>;
125
126 /// Compiler-specific method for configuring settings.
127 ///
128 /// Same as [`CompilerBuilder::set`] except for enabling boolean flags.
129 /// Currently cranelift uses this to sometimes enable a family of settings.
130 fn enable(&mut self, name: &str) -> Result<()>;
131
132 /// Returns a list of all possible settings that can be configured with
133 /// [`CompilerBuilder::set`] and [`CompilerBuilder::enable`].
134 fn settings(&self) -> Vec<Setting>;
135
136 /// Enables Cranelift's incremental compilation cache, using the given `CacheStore`
137 /// implementation.
138 ///
139 /// This will return an error if the compiler does not support incremental compilation.
140 fn enable_incremental_compilation(&mut self, cache_store: Arc<dyn CacheStore>) -> Result<()>;
141
142 /// Set the tunables for this compiler.
143 fn set_tunables(&mut self, tunables: Tunables) -> Result<()>;
144
145 /// Builds a new [`Compiler`] object from this configuration.
146 fn build(&self) -> Result<Box<dyn Compiler>>;
147
148 /// Enables or disables wmemcheck during runtime according to the wmemcheck CLI flag.
149 fn wmemcheck(&mut self, _enable: bool) {}
150}
151
152/// Description of compiler settings returned by [`CompilerBuilder::settings`].
153#[derive(Clone, Copy, Debug)]
154pub struct Setting {
155 /// The name of the setting.
156 pub name: &'static str,
157 /// The description of the setting.
158 pub description: &'static str,
159 /// The kind of the setting.
160 pub kind: SettingKind,
161 /// The supported values of the setting (for enum values).
162 pub values: Option<&'static [&'static str]>,
163}
164
165/// Different kinds of [`Setting`] values that can be configured in a
166/// [`CompilerBuilder`]
167#[derive(Clone, Copy, Debug)]
168pub enum SettingKind {
169 /// The setting is an enumeration, meaning it's one of a set of values.
170 Enum,
171 /// The setting is a number.
172 Num,
173 /// The setting is a boolean.
174 Bool,
175 /// The setting is a preset.
176 Preset,
177}
178
179/// The result of compiling a single function body.
180pub struct CompiledFunctionBody {
181 /// The code. This is whatever type the `Compiler` implementation wants it
182 /// to be, we just shepherd it around.
183 pub code: Box<dyn Any + Send + Sync>,
184 /// Whether the compiled function needs a GC heap to run; that is, whether
185 /// it reads a struct field, allocates, an array, or etc...
186 pub needs_gc_heap: bool,
187}
188
189/// An implementation of a compiler which can compile WebAssembly functions to
190/// machine code and perform other miscellaneous tasks needed by the JIT runtime.
191///
192/// The diagram below depicts typical usage of this trait:
193///
194/// ```ignore
195/// +------+
196/// | Wasm |
197/// +------+
198/// |
199/// |
200/// Compiler::compile_function()
201/// |
202/// |
203/// V
204/// +----------------------+
205/// | CompiledFunctionBody |
206/// +----------------------+
207/// | |
208/// | |
209/// | When
210/// | Compiler::inlining_compiler()
211/// | is some
212/// | |
213/// When |
214/// Compiler::inlining_compiler() |-----------------.
215/// is none | |
216/// | | |
217/// | Optionally call |
218/// | InliningCompiler::inline() |
219/// | | |
220/// | | |
221/// | |-----------------'
222/// | |
223/// | |
224/// | V
225/// | InliningCompiler::finish_compiling()
226/// | |
227/// | |
228/// |------------------'
229/// |
230/// |
231/// Compiler::append_code()
232/// |
233/// |
234/// V
235/// +--------+
236/// | Object |
237/// +--------+
238/// ```
239pub trait Compiler: Send + Sync {
240 /// Get this compiler's inliner.
241 ///
242 /// Consumers of this trait **must** check for when when this method returns
243 /// `Some(_)`, and **must** call `InliningCompiler::finish_compiling` on all
244 /// `CompiledFunctionBody`s produced by this compiler in that case before
245 /// passing the the compiled functions to `Compiler::append_code`, even if
246 /// the consumer does not actually intend to do any inlining. This allows
247 /// implementations of the trait to only translate to an internal
248 /// representation in `Compiler::compile_*` methods so that they can then
249 /// perform inlining afterwards if the consumer desires, and then finally
250 /// proceed with compilng that internal representation to native code in
251 /// `InliningCompiler::finish_compiling`.
252 fn inlining_compiler(&self) -> Option<&dyn InliningCompiler>;
253
254 /// Compiles the function `index` within `translation`.
255 ///
256 /// The body of the function is available in `data` and configuration
257 /// values are also passed in via `tunables`. Type information in
258 /// `translation` is all relative to `types`.
259 fn compile_function(
260 &self,
261 translation: &ModuleTranslation<'_>,
262 index: DefinedFuncIndex,
263 data: FunctionBodyData<'_>,
264 types: &ModuleTypesBuilder,
265 symbol: &str,
266 ) -> Result<CompiledFunctionBody, CompileError>;
267
268 /// Compile a trampoline for an array-call host function caller calling the
269 /// `index`th Wasm function.
270 ///
271 /// The trampoline should save the necessary state to record the
272 /// host-to-Wasm transition (e.g. registers used for fast stack walking).
273 fn compile_array_to_wasm_trampoline(
274 &self,
275 translation: &ModuleTranslation<'_>,
276 types: &ModuleTypesBuilder,
277 index: DefinedFuncIndex,
278 symbol: &str,
279 ) -> Result<CompiledFunctionBody, CompileError>;
280
281 /// Compile a trampoline for a Wasm caller calling a array callee with the
282 /// given signature.
283 ///
284 /// The trampoline should save the necessary state to record the
285 /// Wasm-to-host transition (e.g. registers used for fast stack walking).
286 fn compile_wasm_to_array_trampoline(
287 &self,
288 wasm_func_ty: &WasmFuncType,
289 symbol: &str,
290 ) -> Result<CompiledFunctionBody, CompileError>;
291
292 /// Creates a trampoline that can be used to call Wasmtime's implementation
293 /// of the builtin function specified by `index`.
294 ///
295 /// The trampoline created can technically have any ABI but currently has
296 /// the native ABI. This will then perform all the necessary duties of an
297 /// exit trampoline from wasm and then perform the actual dispatch to the
298 /// builtin function. Builtin functions in Wasmtime are stored in an array
299 /// in all `VMContext` pointers, so the call to the host is an indirect
300 /// call.
301 fn compile_wasm_to_builtin(
302 &self,
303 index: BuiltinFunctionIndex,
304 symbol: &str,
305 ) -> Result<CompiledFunctionBody, CompileError>;
306
307 /// Returns the list of relocations required for a function from one of the
308 /// previous `compile_*` functions above.
309 fn compiled_function_relocation_targets<'a>(
310 &'a self,
311 func: &'a dyn Any,
312 ) -> Box<dyn Iterator<Item = RelocationTarget> + 'a>;
313
314 /// Appends a list of compiled functions to an in-memory object.
315 ///
316 /// This function will receive the same `Box<dyn Any>` produced as part of
317 /// compilation from functions like `compile_function`,
318 /// `compile_host_to_wasm_trampoline`, and other component-related shims.
319 /// Internally this will take all of these functions and add information to
320 /// the object such as:
321 ///
322 /// * Compiled code in a `.text` section
323 /// * Unwind information in Wasmtime-specific sections
324 /// * Relocations, if necessary, for the text section
325 ///
326 /// Each function is accompanied with its desired symbol name and the return
327 /// value of this function is the symbol for each function as well as where
328 /// each function was placed within the object.
329 ///
330 /// The `resolve_reloc` argument is intended to resolving relocations
331 /// between function, chiefly resolving intra-module calls within one core
332 /// wasm module. The closure here takes two arguments:
333 ///
334 /// 1. First, the index within `funcs` that is being resolved,
335 ///
336 /// 2. and next the `RelocationTarget` which is the relocation target to
337 /// resolve.
338 ///
339 /// The return value is an index within `funcs` that the relocation points
340 /// to.
341 fn append_code(
342 &self,
343 obj: &mut Object<'static>,
344 funcs: &[(String, Box<dyn Any + Send + Sync>)],
345 resolve_reloc: &dyn Fn(usize, RelocationTarget) -> usize,
346 ) -> Result<Vec<(SymbolId, FunctionLoc)>>;
347
348 /// Creates a new `Object` file which is used to build the results of a
349 /// compilation into.
350 ///
351 /// The returned object file will have an appropriate
352 /// architecture/endianness for `self.triple()`, but at this time it is
353 /// always an ELF file, regardless of target platform.
354 fn object(&self, kind: ObjectKind) -> Result<Object<'static>> {
355 use target_lexicon::Architecture::*;
356
357 let triple = self.triple();
358 let (arch, flags) = match triple.architecture {
359 X86_32(_) => (Architecture::I386, 0),
360 X86_64 => (Architecture::X86_64, 0),
361 Arm(_) => (Architecture::Arm, 0),
362 Aarch64(_) => (Architecture::Aarch64, 0),
363 S390x => (Architecture::S390x, 0),
364 Riscv64(_) => (Architecture::Riscv64, 0),
365 // XXX: the `object` crate won't successfully build an object
366 // with relocations and such if it doesn't know the
367 // architecture, so just pretend we are riscv64. Yolo!
368 //
369 // Also note that we add some flags to `e_flags` in the object file
370 // to indicate that it's pulley, not actually riscv64. This is used
371 // by `wasmtime objdump` for example.
372 Pulley32 | Pulley32be => (Architecture::Riscv64, obj::EF_WASMTIME_PULLEY32),
373 Pulley64 | Pulley64be => (Architecture::Riscv64, obj::EF_WASMTIME_PULLEY64),
374 architecture => {
375 anyhow::bail!("target architecture {:?} is unsupported", architecture,);
376 }
377 };
378 let mut obj = Object::new(
379 BinaryFormat::Elf,
380 arch,
381 match triple.endianness().unwrap() {
382 target_lexicon::Endianness::Little => object::Endianness::Little,
383 target_lexicon::Endianness::Big => object::Endianness::Big,
384 },
385 );
386 obj.flags = FileFlags::Elf {
387 os_abi: obj::ELFOSABI_WASMTIME,
388 e_flags: flags
389 | match kind {
390 ObjectKind::Module => obj::EF_WASMTIME_MODULE,
391 ObjectKind::Component => obj::EF_WASMTIME_COMPONENT,
392 },
393 abi_version: 0,
394 };
395 Ok(obj)
396 }
397
398 /// Returns the target triple that this compiler is compiling for.
399 fn triple(&self) -> &target_lexicon::Triple;
400
401 /// Returns the alignment necessary to align values to the page size of the
402 /// compilation target. Note that this may be an upper-bound where the
403 /// alignment is larger than necessary for some platforms since it may
404 /// depend on the platform's runtime configuration.
405 fn page_size_align(&self) -> u64 {
406 // Conservatively assume the max-of-all-supported-hosts for pulley
407 // and round up to 64k.
408 if self.triple().is_pulley() {
409 return 0x10000;
410 }
411
412 use target_lexicon::*;
413 match (self.triple().operating_system, self.triple().architecture) {
414 (
415 OperatingSystem::MacOSX { .. }
416 | OperatingSystem::Darwin(_)
417 | OperatingSystem::IOS(_)
418 | OperatingSystem::TvOS(_),
419 Architecture::Aarch64(..),
420 ) => 0x4000,
421 // 64 KB is the maximal page size (i.e. memory translation granule size)
422 // supported by the architecture and is used on some platforms.
423 (_, Architecture::Aarch64(..)) => 0x10000,
424 _ => 0x1000,
425 }
426 }
427
428 /// Returns a list of configured settings for this compiler.
429 fn flags(&self) -> Vec<(&'static str, FlagValue<'static>)>;
430
431 /// Same as [`Compiler::flags`], but ISA-specific (a cranelift-ism)
432 fn isa_flags(&self) -> Vec<(&'static str, FlagValue<'static>)>;
433
434 /// Get a flag indicating whether branch protection is enabled.
435 fn is_branch_protection_enabled(&self) -> bool;
436
437 /// Returns a suitable compiler usable for component-related compilations.
438 ///
439 /// Note that the `ComponentCompiler` trait can also be implemented for
440 /// `Self` in which case this function would simply return `self`.
441 #[cfg(feature = "component-model")]
442 fn component_compiler(&self) -> &dyn crate::component::ComponentCompiler;
443
444 /// Appends generated DWARF sections to the `obj` specified.
445 ///
446 /// The `translations` track all compiled functions and `get_func` can be
447 /// used to acquire the metadata for a particular function within a module.
448 fn append_dwarf<'a>(
449 &self,
450 obj: &mut Object<'_>,
451 translations: &'a PrimaryMap<StaticModuleIndex, ModuleTranslation<'a>>,
452 get_func: &'a dyn Fn(
453 StaticModuleIndex,
454 DefinedFuncIndex,
455 ) -> (SymbolId, &'a (dyn Any + Send + Sync)),
456 dwarf_package_bytes: Option<&'a [u8]>,
457 tunables: &'a Tunables,
458 ) -> Result<()>;
459
460 /// Creates a new System V Common Information Entry for the ISA.
461 ///
462 /// Returns `None` if the ISA does not support System V unwind information.
463 fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
464 // By default, an ISA cannot create a System V CIE.
465 None
466 }
467}
468
469/// An inlining compiler.
470pub trait InliningCompiler: Sync + Send {
471 /// Enumerate the function calls that the given `func` makes.
472 fn calls(&self, func: &CompiledFunctionBody, calls: &mut IndexSet<FuncIndex>) -> Result<()>;
473
474 /// Get the abstract size of the given function, for the purposes of
475 /// inlining heuristics.
476 fn size(&self, func: &CompiledFunctionBody) -> u32;
477
478 /// Process this function for inlining.
479 ///
480 /// Implementations should call `get_callee` for each of their direct
481 /// function call sites and if `get_callee` returns `Some(_)`, they should
482 /// inline the given function body into that call site.
483 fn inline<'a>(
484 &self,
485 func: &mut CompiledFunctionBody,
486 get_callee: &'a mut dyn FnMut(FuncIndex) -> Option<&'a CompiledFunctionBody>,
487 ) -> Result<()>;
488
489 /// Finish compiling the given function.
490 ///
491 /// This method **must** be called before passing the
492 /// `CompiledFunctionBody`'s contents to `Compiler::append_code`, even if no
493 /// inlining was performed.
494 fn finish_compiling(
495 &self,
496 func: &mut CompiledFunctionBody,
497 input: Option<wasmparser::FunctionBody<'_>>,
498 symbol: &str,
499 ) -> Result<()>;
500}