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