wasmtime_environ/
compilation.rs

1//! A `Compilation` contains the compiled function bodies for a WebAssembly
2//! module.
3
4use crate::obj;
5use crate::{
6    DefinedFuncIndex, FilePos, FuncIndex, FunctionBodyData, ModuleTranslation, ModuleTypes,
7    PrimaryMap, StackMap, Tunables, WasmError, WasmFuncType,
8};
9use anyhow::Result;
10use object::write::{Object, SymbolId};
11use object::{Architecture, BinaryFormat, FileFlags};
12use serde::{Deserialize, Serialize};
13use std::any::Any;
14use std::borrow::Cow;
15use std::collections::BTreeMap;
16use std::fmt;
17use std::sync::Arc;
18use thiserror::Error;
19
20/// Information about a function, such as trap information, address map,
21/// and stack maps.
22#[derive(Serialize, Deserialize, Default)]
23#[allow(missing_docs)]
24pub struct WasmFunctionInfo {
25    pub start_srcloc: FilePos,
26    pub stack_maps: Box<[StackMapInformation]>,
27}
28
29/// Description of where a function is located in the text section of a
30/// compiled image.
31#[derive(Copy, Clone, Serialize, Deserialize)]
32pub struct FunctionLoc {
33    /// The byte offset from the start of the text section where this
34    /// function starts.
35    pub start: u32,
36    /// The byte length of this function's function body.
37    pub length: u32,
38}
39
40/// The offset within a function of a GC safepoint, and its associated stack
41/// map.
42#[derive(Serialize, Deserialize, Debug)]
43pub struct StackMapInformation {
44    /// The offset of the GC safepoint within the function's native code. It is
45    /// relative to the beginning of the function.
46    pub code_offset: u32,
47
48    /// The stack map for identifying live GC refs at the GC safepoint.
49    pub stack_map: StackMap,
50}
51
52/// An error while compiling WebAssembly to machine code.
53#[derive(Error, Debug)]
54pub enum CompileError {
55    /// A wasm translation error occured.
56    #[error("WebAssembly translation error")]
57    Wasm(#[from] WasmError),
58
59    /// A compilation error occured.
60    #[error("Compilation error: {0}")]
61    Codegen(String),
62
63    /// A compilation error occured.
64    #[error("Debug info is not supported with this configuration")]
65    DebugInfoNotSupported,
66}
67
68/// Implementation of an incremental compilation's key/value cache store.
69///
70/// In theory, this could just be Cranelift's `CacheKvStore` trait, but it is not as we want to
71/// make sure that wasmtime isn't too tied to Cranelift internals (and as a matter of fact, we
72/// can't depend on the Cranelift trait here).
73pub trait CacheStore: Send + Sync + std::fmt::Debug {
74    /// Try to retrieve an arbitrary cache key entry, and returns a reference to bytes that were
75    /// inserted via `Self::insert` before.
76    fn get(&self, key: &[u8]) -> Option<Cow<[u8]>>;
77
78    /// Given an arbitrary key and bytes, stores them in the cache.
79    ///
80    /// Returns false when insertion in the cache failed.
81    fn insert(&self, key: &[u8], value: Vec<u8>) -> bool;
82}
83
84/// Abstract trait representing the ability to create a `Compiler` below.
85///
86/// This is used in Wasmtime to separate compiler implementations, currently
87/// mostly used to separate Cranelift from Wasmtime itself.
88pub trait CompilerBuilder: Send + Sync + fmt::Debug {
89    /// Sets the target of compilation to the target specified.
90    fn target(&mut self, target: target_lexicon::Triple) -> Result<()>;
91
92    /// Returns the currently configured target triple that compilation will
93    /// produce artifacts for.
94    fn triple(&self) -> &target_lexicon::Triple;
95
96    /// Compiler-specific method to configure various settings in the compiler
97    /// itself.
98    ///
99    /// This is expected to be defined per-compiler. Compilers should return
100    /// errors for unknown names/values.
101    fn set(&mut self, name: &str, val: &str) -> Result<()>;
102
103    /// Compiler-specific method for configuring settings.
104    ///
105    /// Same as [`CompilerBuilder::set`] except for enabling boolean flags.
106    /// Currently cranelift uses this to sometimes enable a family of settings.
107    fn enable(&mut self, name: &str) -> Result<()>;
108
109    /// Returns a list of all possible settings that can be configured with
110    /// [`CompilerBuilder::set`] and [`CompilerBuilder::enable`].
111    fn settings(&self) -> Vec<Setting>;
112
113    /// Enables Cranelift's incremental compilation cache, using the given `CacheStore`
114    /// implementation.
115    ///
116    /// This will return an error if the compiler does not support incremental compilation.
117    fn enable_incremental_compilation(&mut self, cache_store: Arc<dyn CacheStore>) -> Result<()>;
118
119    /// Builds a new [`Compiler`] object from this configuration.
120    fn build(&self) -> Result<Box<dyn Compiler>>;
121}
122
123/// Description of compiler settings returned by [`CompilerBuilder::settings`].
124#[derive(Clone, Copy, Debug)]
125pub struct Setting {
126    /// The name of the setting.
127    pub name: &'static str,
128    /// The description of the setting.
129    pub description: &'static str,
130    /// The kind of the setting.
131    pub kind: SettingKind,
132    /// The supported values of the setting (for enum values).
133    pub values: Option<&'static [&'static str]>,
134}
135
136/// Different kinds of [`Setting`] values that can be configured in a
137/// [`CompilerBuilder`]
138#[derive(Clone, Copy, Debug)]
139pub enum SettingKind {
140    /// The setting is an enumeration, meaning it's one of a set of values.
141    Enum,
142    /// The setting is a number.
143    Num,
144    /// The setting is a boolean.
145    Bool,
146    /// The setting is a preset.
147    Preset,
148}
149
150/// Types of objects that can be created by `Compiler::object`
151pub enum ObjectKind {
152    /// A core wasm compilation artifact
153    Module,
154    /// A component compilation artifact
155    Component,
156}
157
158/// An implementation of a compiler which can compile WebAssembly functions to
159/// machine code and perform other miscellaneous tasks needed by the JIT runtime.
160pub trait Compiler: Send + Sync {
161    /// Compiles the function `index` within `translation`.
162    ///
163    /// The body of the function is available in `data` and configuration
164    /// values are also passed in via `tunables`. Type information in
165    /// `translation` is all relative to `types`.
166    fn compile_function(
167        &self,
168        translation: &ModuleTranslation<'_>,
169        index: DefinedFuncIndex,
170        data: FunctionBodyData<'_>,
171        tunables: &Tunables,
172        types: &ModuleTypes,
173    ) -> Result<(WasmFunctionInfo, Box<dyn Any + Send>), CompileError>;
174
175    /// Creates a function of type `VMTrampoline` which will then call the
176    /// function pointer argument which has the `ty` type provided.
177    fn compile_host_to_wasm_trampoline(
178        &self,
179        ty: &WasmFuncType,
180    ) -> Result<Box<dyn Any + Send>, CompileError>;
181
182    /// Appends a list of compiled functions to an in-memory object.
183    ///
184    /// This function will receive the same `Box<dyn Any>` produced as part of
185    /// compilation from functions like `compile_function`,
186    /// `compile_host_to_wasm_trampoline`, and other component-related shims.
187    /// Internally this will take all of these functions and add information to
188    /// the object such as:
189    ///
190    /// * Compiled code in a `.text` section
191    /// * Unwind information in Wasmtime-specific sections
192    /// * Relocations, if necessary, for the text section
193    ///
194    /// Each function is accompanied with its desired symbol name and the return
195    /// value of this function is the symbol for each function as well as where
196    /// each function was placed within the object.
197    ///
198    /// The `resolve_reloc` argument is intended to resolving relocations
199    /// between function, chiefly resolving intra-module calls within one core
200    /// wasm module. The closure here takes two arguments: first the index
201    /// within `funcs` that is being resolved and next the `FuncIndex` which is
202    /// the relocation target to resolve. The return value is an index within
203    /// `funcs` that the relocation points to.
204    fn append_code(
205        &self,
206        obj: &mut Object<'static>,
207        funcs: &[(String, Box<dyn Any + Send>)],
208        tunables: &Tunables,
209        resolve_reloc: &dyn Fn(usize, FuncIndex) -> usize,
210    ) -> Result<Vec<(SymbolId, FunctionLoc)>>;
211
212    /// Inserts two functions for host-to-wasm and wasm-to-host trampolines into
213    /// the `obj` provided.
214    ///
215    /// This will configure the same sections as `emit_obj`, but will likely be
216    /// much smaller. The two returned `Trampoline` structures describe where to
217    /// find the host-to-wasm and wasm-to-host trampolines in the text section,
218    /// respectively.
219    fn emit_trampoline_obj(
220        &self,
221        ty: &WasmFuncType,
222        host_fn: usize,
223        obj: &mut Object<'static>,
224    ) -> Result<(FunctionLoc, FunctionLoc)>;
225
226    /// Creates a new `Object` file which is used to build the results of a
227    /// compilation into.
228    ///
229    /// The returned object file will have an appropriate
230    /// architecture/endianness for `self.triple()`, but at this time it is
231    /// always an ELF file, regardless of target platform.
232    fn object(&self, kind: ObjectKind) -> Result<Object<'static>> {
233        use target_lexicon::Architecture::*;
234
235        let triple = self.triple();
236        let mut obj = Object::new(
237            BinaryFormat::Elf,
238            match triple.architecture {
239                X86_32(_) => Architecture::I386,
240                X86_64 => Architecture::X86_64,
241                Arm(_) => Architecture::Arm,
242                Aarch64(_) => Architecture::Aarch64,
243                S390x => Architecture::S390x,
244                Riscv64(_) => Architecture::Riscv64,
245                architecture => {
246                    anyhow::bail!("target architecture {:?} is unsupported", architecture,);
247                }
248            },
249            match triple.endianness().unwrap() {
250                target_lexicon::Endianness::Little => object::Endianness::Little,
251                target_lexicon::Endianness::Big => object::Endianness::Big,
252            },
253        );
254        obj.flags = FileFlags::Elf {
255            os_abi: obj::ELFOSABI_WASMTIME,
256            e_flags: match kind {
257                ObjectKind::Module => obj::EF_WASMTIME_MODULE,
258                ObjectKind::Component => obj::EF_WASMTIME_COMPONENT,
259            },
260            abi_version: 0,
261        };
262        Ok(obj)
263    }
264
265    /// Returns the target triple that this compiler is compiling for.
266    fn triple(&self) -> &target_lexicon::Triple;
267
268    /// Returns the alignment necessary to align values to the page size of the
269    /// compilation target. Note that this may be an upper-bound where the
270    /// alignment is larger than necessary for some platforms since it may
271    /// depend on the platform's runtime configuration.
272    fn page_size_align(&self) -> u64 {
273        use target_lexicon::*;
274        match (self.triple().operating_system, self.triple().architecture) {
275            (
276                OperatingSystem::MacOSX { .. }
277                | OperatingSystem::Darwin
278                | OperatingSystem::Ios
279                | OperatingSystem::Tvos,
280                Architecture::Aarch64(..),
281            ) => 0x4000,
282            // 64 KB is the maximal page size (i.e. memory translation granule size)
283            // supported by the architecture and is used on some platforms.
284            (_, Architecture::Aarch64(..)) => 0x10000,
285            _ => 0x1000,
286        }
287    }
288
289    /// Returns a list of configured settings for this compiler.
290    fn flags(&self) -> BTreeMap<String, FlagValue>;
291
292    /// Same as [`Compiler::flags`], but ISA-specific (a cranelift-ism)
293    fn isa_flags(&self) -> BTreeMap<String, FlagValue>;
294
295    /// Get a flag indicating whether branch protection is enabled.
296    fn is_branch_protection_enabled(&self) -> bool;
297
298    /// Returns a suitable compiler usable for component-related compliations.
299    ///
300    /// Note that the `ComponentCompiler` trait can also be implemented for
301    /// `Self` in which case this function would simply return `self`.
302    #[cfg(feature = "component-model")]
303    fn component_compiler(&self) -> &dyn crate::component::ComponentCompiler;
304
305    /// Appends generated DWARF sections to the `obj` specified for the compiled
306    /// functions.
307    fn append_dwarf(
308        &self,
309        obj: &mut Object<'_>,
310        translation: &ModuleTranslation<'_>,
311        funcs: &PrimaryMap<DefinedFuncIndex, (SymbolId, &(dyn Any + Send))>,
312    ) -> Result<()>;
313
314    /// The function alignment required by this ISA.
315    fn function_alignment(&self) -> u32;
316
317    /// Creates a new System V Common Information Entry for the ISA.
318    ///
319    /// Returns `None` if the ISA does not support System V unwind information.
320    fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
321        // By default, an ISA cannot create a System V CIE.
322        None
323    }
324}
325
326/// Value of a configured setting for a [`Compiler`]
327#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Debug)]
328pub enum FlagValue {
329    /// Name of the value that has been configured for this setting.
330    Enum(Cow<'static, str>),
331    /// The numerical value of the configured settings.
332    Num(u8),
333    /// Whether the setting is on or off.
334    Bool(bool),
335}
336
337impl fmt::Display for FlagValue {
338    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
339        match self {
340            Self::Enum(v) => v.fmt(f),
341            Self::Num(v) => v.fmt(f),
342            Self::Bool(v) => v.fmt(f),
343        }
344    }
345}