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