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