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    DefinedFuncIndex, FlagValue, FuncKey, FunctionLoc, ObjectKind, PrimaryMap, StaticModuleIndex,
7    TripleExt, Tunables, WasmError, WasmFuncType, obj,
8};
9use anyhow::Result;
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        anyhow::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_array_to_wasm_trampoline(
265        &self,
266        translation: &ModuleTranslation<'_>,
267        types: &ModuleTypesBuilder,
268        key: FuncKey,
269        symbol: &str,
270    ) -> Result<CompiledFunctionBody, CompileError>;
271
272    /// Compile a trampoline for a Wasm caller calling a array callee with the
273    /// given signature.
274    ///
275    /// The trampoline should save the necessary state to record the
276    /// Wasm-to-host transition (e.g. registers used for fast stack walking).
277    fn compile_wasm_to_array_trampoline(
278        &self,
279        wasm_func_ty: &WasmFuncType,
280        key: FuncKey,
281        symbol: &str,
282    ) -> Result<CompiledFunctionBody, CompileError>;
283
284    /// Creates a trampoline that can be used to call Wasmtime's implementation
285    /// of the builtin function specified by `index`.
286    ///
287    /// The trampoline created can technically have any ABI but currently has
288    /// the native ABI. This will then perform all the necessary duties of an
289    /// exit trampoline from wasm and then perform the actual dispatch to the
290    /// builtin function. Builtin functions in Wasmtime are stored in an array
291    /// in all `VMContext` pointers, so the call to the host is an indirect
292    /// call.
293    fn compile_wasm_to_builtin(
294        &self,
295        key: FuncKey,
296        symbol: &str,
297    ) -> Result<CompiledFunctionBody, CompileError>;
298
299    /// Returns the list of relocations required for a function from one of the
300    /// previous `compile_*` functions above.
301    fn compiled_function_relocation_targets<'a>(
302        &'a self,
303        func: &'a dyn Any,
304    ) -> Box<dyn Iterator<Item = FuncKey> + 'a>;
305
306    /// Appends a list of compiled functions to an in-memory object.
307    ///
308    /// This function will receive the same `Box<dyn Any>` produced as part of
309    /// compilation from functions like `compile_function`,
310    /// `compile_host_to_wasm_trampoline`, and other component-related shims.
311    /// Internally this will take all of these functions and add information to
312    /// the object such as:
313    ///
314    /// * Compiled code in a `.text` section
315    /// * Unwind information in Wasmtime-specific sections
316    /// * Relocations, if necessary, for the text section
317    ///
318    /// Each function is accompanied with its desired symbol name and the return
319    /// value of this function is the symbol for each function as well as where
320    /// each function was placed within the object.
321    ///
322    /// The `resolve_reloc` argument is intended to resolving relocations
323    /// between function, chiefly resolving intra-module calls within one core
324    /// wasm module. The closure here takes two arguments:
325    ///
326    /// 1. First, the index within `funcs` that is being resolved,
327    ///
328    /// 2. and next the `RelocationTarget` which is the relocation target to
329    ///    resolve.
330    ///
331    /// The return value is an index within `funcs` that the relocation points
332    /// to.
333    fn append_code(
334        &self,
335        obj: &mut Object<'static>,
336        funcs: &[(String, FuncKey, Box<dyn Any + Send + Sync>)],
337        resolve_reloc: &dyn Fn(usize, FuncKey) -> usize,
338    ) -> Result<Vec<(SymbolId, FunctionLoc)>>;
339
340    /// Creates a new `Object` file which is used to build the results of a
341    /// compilation into.
342    ///
343    /// The returned object file will have an appropriate
344    /// architecture/endianness for `self.triple()`, but at this time it is
345    /// always an ELF file, regardless of target platform.
346    fn object(&self, kind: ObjectKind) -> Result<Object<'static>> {
347        use target_lexicon::Architecture::*;
348
349        let triple = self.triple();
350        let (arch, flags) = match triple.architecture {
351            X86_32(_) => (Architecture::I386, 0),
352            X86_64 => (Architecture::X86_64, 0),
353            Arm(_) => (Architecture::Arm, 0),
354            Aarch64(_) => (Architecture::Aarch64, 0),
355            S390x => (Architecture::S390x, 0),
356            Riscv64(_) => (Architecture::Riscv64, 0),
357            // XXX: the `object` crate won't successfully build an object
358            // with relocations and such if it doesn't know the
359            // architecture, so just pretend we are riscv64. Yolo!
360            //
361            // Also note that we add some flags to `e_flags` in the object file
362            // to indicate that it's pulley, not actually riscv64. This is used
363            // by `wasmtime objdump` for example.
364            Pulley32 | Pulley32be => (Architecture::Riscv64, obj::EF_WASMTIME_PULLEY32),
365            Pulley64 | Pulley64be => (Architecture::Riscv64, obj::EF_WASMTIME_PULLEY64),
366            architecture => {
367                anyhow::bail!("target architecture {architecture:?} is unsupported");
368            }
369        };
370        let mut obj = Object::new(
371            BinaryFormat::Elf,
372            arch,
373            match triple.endianness().unwrap() {
374                target_lexicon::Endianness::Little => object::Endianness::Little,
375                target_lexicon::Endianness::Big => object::Endianness::Big,
376            },
377        );
378        obj.flags = FileFlags::Elf {
379            os_abi: obj::ELFOSABI_WASMTIME,
380            e_flags: flags
381                | match kind {
382                    ObjectKind::Module => obj::EF_WASMTIME_MODULE,
383                    ObjectKind::Component => obj::EF_WASMTIME_COMPONENT,
384                },
385            abi_version: 0,
386        };
387        Ok(obj)
388    }
389
390    /// Returns the target triple that this compiler is compiling for.
391    fn triple(&self) -> &target_lexicon::Triple;
392
393    /// Returns the alignment necessary to align values to the page size of the
394    /// compilation target. Note that this may be an upper-bound where the
395    /// alignment is larger than necessary for some platforms since it may
396    /// depend on the platform's runtime configuration.
397    fn page_size_align(&self) -> u64 {
398        // Conservatively assume the max-of-all-supported-hosts for pulley
399        // and round up to 64k.
400        if self.triple().is_pulley() {
401            return 0x10000;
402        }
403
404        use target_lexicon::*;
405        match (self.triple().operating_system, self.triple().architecture) {
406            (
407                OperatingSystem::MacOSX { .. }
408                | OperatingSystem::Darwin(_)
409                | OperatingSystem::IOS(_)
410                | OperatingSystem::TvOS(_),
411                Architecture::Aarch64(..),
412            ) => 0x4000,
413            // 64 KB is the maximal page size (i.e. memory translation granule size)
414            // supported by the architecture and is used on some platforms.
415            (_, Architecture::Aarch64(..)) => 0x10000,
416            _ => 0x1000,
417        }
418    }
419
420    /// Returns a list of configured settings for this compiler.
421    fn flags(&self) -> Vec<(&'static str, FlagValue<'static>)>;
422
423    /// Same as [`Compiler::flags`], but ISA-specific (a cranelift-ism)
424    fn isa_flags(&self) -> Vec<(&'static str, FlagValue<'static>)>;
425
426    /// Get a flag indicating whether branch protection is enabled.
427    fn is_branch_protection_enabled(&self) -> bool;
428
429    /// Returns a suitable compiler usable for component-related compilations.
430    ///
431    /// Note that the `ComponentCompiler` trait can also be implemented for
432    /// `Self` in which case this function would simply return `self`.
433    #[cfg(feature = "component-model")]
434    fn component_compiler(&self) -> &dyn crate::component::ComponentCompiler;
435
436    /// Appends generated DWARF sections to the `obj` specified.
437    ///
438    /// The `translations` track all compiled functions and `get_func` can be
439    /// used to acquire the metadata for a particular function within a module.
440    fn append_dwarf<'a>(
441        &self,
442        obj: &mut Object<'_>,
443        translations: &'a PrimaryMap<StaticModuleIndex, ModuleTranslation<'a>>,
444        get_func: &'a dyn Fn(
445            StaticModuleIndex,
446            DefinedFuncIndex,
447        ) -> (SymbolId, &'a (dyn Any + Send + Sync)),
448        dwarf_package_bytes: Option<&'a [u8]>,
449        tunables: &'a Tunables,
450    ) -> Result<()>;
451
452    /// Creates a new System V Common Information Entry for the ISA.
453    ///
454    /// Returns `None` if the ISA does not support System V unwind information.
455    fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
456        // By default, an ISA cannot create a System V CIE.
457        None
458    }
459}
460
461/// An inlining compiler.
462pub trait InliningCompiler: Sync + Send {
463    /// Enumerate the function calls that the given `func` makes.
464    fn calls(&self, func: &CompiledFunctionBody, calls: &mut IndexSet<FuncKey>) -> Result<()>;
465
466    /// Get the abstract size of the given function, for the purposes of
467    /// inlining heuristics.
468    fn size(&self, func: &CompiledFunctionBody) -> u32;
469
470    /// Process this function for inlining.
471    ///
472    /// Implementations should call `get_callee` for each of their direct
473    /// function call sites and if `get_callee` returns `Some(_)`, they should
474    /// inline the given function body into that call site.
475    fn inline<'a>(
476        &self,
477        func: &mut CompiledFunctionBody,
478        get_callee: &'a mut dyn FnMut(FuncKey) -> Option<&'a CompiledFunctionBody>,
479    ) -> Result<()>;
480
481    /// Finish compiling the given function.
482    ///
483    /// This method **must** be called before passing the
484    /// `CompiledFunctionBody`'s contents to `Compiler::append_code`, even if no
485    /// inlining was performed.
486    fn finish_compiling(
487        &self,
488        func: &mut CompiledFunctionBody,
489        input: Option<wasmparser::FunctionBody<'_>>,
490        symbol: &str,
491    ) -> Result<()>;
492}