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