//! A `Compilation` contains the compiled function bodies for a WebAssembly //! module. use crate::{ DefinedFuncIndex, FilePos, FunctionBodyData, ModuleTranslation, ModuleTypes, PrimaryMap, SignatureIndex, StackMap, Tunables, WasmError, WasmFuncType, }; use anyhow::Result; use object::write::Object; use object::{Architecture, BinaryFormat}; use serde::{Deserialize, Serialize}; use std::any::Any; use std::borrow::Cow; use std::collections::BTreeMap; use std::fmt; use std::sync::Arc; use thiserror::Error; /// Information about a function, such as trap information, address map, /// and stack maps. #[derive(Serialize, Deserialize, Default)] #[allow(missing_docs)] pub struct FunctionInfo { pub start_srcloc: FilePos, pub stack_maps: Vec, /// Offset in the text section of where this function starts. pub start: u64, /// The size of the compiled function, in bytes. pub length: u32, /// The alignment requirements of this function, in bytes. pub alignment: u32, } /// Information about a compiled trampoline which the host can call to enter /// wasm. #[derive(Serialize, Deserialize)] #[allow(missing_docs)] pub struct Trampoline { /// The signature this trampoline is for pub signature: SignatureIndex, /// Offset in the text section of where this function starts. pub start: u64, /// The size of the compiled function, in bytes. pub length: u32, } /// The offset within a function of a GC safepoint, and its associated stack /// map. #[derive(Serialize, Deserialize, Debug)] pub struct StackMapInformation { /// The offset of the GC safepoint within the function's native code. It is /// relative to the beginning of the function. pub code_offset: u32, /// The stack map for identifying live GC refs at the GC safepoint. pub stack_map: StackMap, } /// An error while compiling WebAssembly to machine code. #[derive(Error, Debug)] pub enum CompileError { /// A wasm translation error occured. #[error("WebAssembly translation error")] Wasm(#[from] WasmError), /// A compilation error occured. #[error("Compilation error: {0}")] Codegen(String), /// A compilation error occured. #[error("Debug info is not supported with this configuration")] DebugInfoNotSupported, } /// Implementation of an incremental compilation's key/value cache store. /// /// In theory, this could just be Cranelift's `CacheKvStore` trait, but it is not as we want to /// make sure that wasmtime isn't too tied to Cranelift internals (and as a matter of fact, we /// can't depend on the Cranelift trait here). pub trait CacheStore: Send + Sync + std::fmt::Debug { /// Try to retrieve an arbitrary cache key entry, and returns a reference to bytes that were /// inserted via `Self::insert` before. fn get(&self, key: &[u8]) -> Option>; /// Given an arbitrary key and bytes, stores them in the cache. /// /// Returns false when insertion in the cache failed. fn insert(&self, key: &[u8], value: Vec) -> bool; } /// Abstract trait representing the ability to create a `Compiler` below. /// /// This is used in Wasmtime to separate compiler implementations, currently /// mostly used to separate Cranelift from Wasmtime itself. pub trait CompilerBuilder: Send + Sync + fmt::Debug { /// Sets the target of compilation to the target specified. fn target(&mut self, target: target_lexicon::Triple) -> Result<()>; /// Returns the currently configured target triple that compilation will /// produce artifacts for. fn triple(&self) -> &target_lexicon::Triple; /// Compiler-specific method to configure various settings in the compiler /// itself. /// /// This is expected to be defined per-compiler. Compilers should return /// errors for unknown names/values. fn set(&mut self, name: &str, val: &str) -> Result<()>; /// Compiler-specific method for configuring settings. /// /// Same as [`CompilerBuilder::set`] except for enabling boolean flags. /// Currently cranelift uses this to sometimes enable a family of settings. fn enable(&mut self, name: &str) -> Result<()>; /// Returns a list of all possible settings that can be configured with /// [`CompilerBuilder::set`] and [`CompilerBuilder::enable`]. fn settings(&self) -> Vec; /// Enables Cranelift's incremental compilation cache, using the given `CacheStore` /// implementation. fn enable_incremental_compilation(&mut self, cache_store: Arc); /// Builds a new [`Compiler`] object from this configuration. fn build(&self) -> Result>; } /// Description of compiler settings returned by [`CompilerBuilder::settings`]. #[derive(Clone, Copy, Debug)] pub struct Setting { /// The name of the setting. pub name: &'static str, /// The description of the setting. pub description: &'static str, /// The kind of the setting. pub kind: SettingKind, /// The supported values of the setting (for enum values). pub values: Option<&'static [&'static str]>, } /// Different kinds of [`Setting`] values that can be configured in a /// [`CompilerBuilder`] #[derive(Clone, Copy, Debug)] pub enum SettingKind { /// The setting is an enumeration, meaning it's one of a set of values. Enum, /// The setting is a number. Num, /// The setting is a boolean. Bool, /// The setting is a preset. Preset, } /// An implementation of a compiler which can compile WebAssembly functions to /// machine code and perform other miscellaneous tasks needed by the JIT runtime. pub trait Compiler: Send + Sync { /// Compiles the function `index` within `translation`. /// /// The body of the function is available in `data` and configuration /// values are also passed in via `tunables`. Type information in /// `translation` is all relative to `types`. fn compile_function( &self, translation: &ModuleTranslation<'_>, index: DefinedFuncIndex, data: FunctionBodyData<'_>, tunables: &Tunables, types: &ModuleTypes, ) -> Result, CompileError>; /// Creates a function of type `VMTrampoline` which will then call the /// function pointer argument which has the `ty` type provided. fn compile_host_to_wasm_trampoline( &self, ty: &WasmFuncType, ) -> Result, CompileError>; /// Collects the results of compilation into an in-memory object. /// /// This function will receive the same `Box` produced as part of /// `compile_function`, as well as the general compilation environment with /// the translation. THe `trampolines` argument is generated by /// `compile_host_to_wasm_trampoline` for each of /// `module.exported_signatures`. This method is expected to populate /// information in the object file such as: /// /// * Compiled code in a `.text` section /// * Unwind information in Wasmtime-specific sections /// * DWARF debugging information for the host, if `emit_dwarf` is `true` /// and the compiler supports it. /// * Relocations, if necessary, for the text section /// /// The final result of compilation will contain more sections inserted by /// the compiler-agnostic runtime. /// /// This function returns information about the compiled functions (where /// they are in the text section) along with where trampolines are located. fn emit_obj( &self, module: &ModuleTranslation, funcs: PrimaryMap>, trampolines: Vec>, tunables: &Tunables, obj: &mut Object<'static>, ) -> Result<(PrimaryMap, Vec)>; /// Inserts two functions for host-to-wasm and wasm-to-host trampolines into /// the `obj` provided. /// /// This will configure the same sections as `emit_obj`, but will likely be /// much smaller. The two returned `Trampoline` structures describe where to /// find the host-to-wasm and wasm-to-host trampolines in the text section, /// respectively. fn emit_trampoline_obj( &self, ty: &WasmFuncType, host_fn: usize, obj: &mut Object<'static>, ) -> Result<(Trampoline, Trampoline)>; /// Creates a new `Object` file which is used to build the results of a /// compilation into. /// /// The returned object file will have an appropriate /// architecture/endianness for `self.triple()`, but at this time it is /// always an ELF file, regardless of target platform. fn object(&self) -> Result> { use target_lexicon::Architecture::*; let triple = self.triple(); Ok(Object::new( BinaryFormat::Elf, match triple.architecture { X86_32(_) => Architecture::I386, X86_64 => Architecture::X86_64, Arm(_) => Architecture::Arm, Aarch64(_) => Architecture::Aarch64, S390x => Architecture::S390x, architecture => { anyhow::bail!("target architecture {:?} is unsupported", architecture,); } }, match triple.endianness().unwrap() { target_lexicon::Endianness::Little => object::Endianness::Little, target_lexicon::Endianness::Big => object::Endianness::Big, }, )) } /// Returns the target triple that this compiler is compiling for. fn triple(&self) -> &target_lexicon::Triple; /// Returns the alignment necessary to align values to the page size of the /// compilation target. Note that this may be an upper-bound where the /// alignment is larger than necessary for some platforms since it may /// depend on the platform's runtime configuration. fn page_size_align(&self) -> u64; /// Returns a list of configured settings for this compiler. fn flags(&self) -> BTreeMap; /// Same as [`Compiler::flags`], but ISA-specific (a cranelift-ism) fn isa_flags(&self) -> BTreeMap; /// Get a flag indicating whether branch protection is enabled. fn is_branch_protection_enabled(&self) -> bool; /// Returns a suitable compiler usable for component-related compliations. /// /// Note that the `ComponentCompiler` trait can also be implemented for /// `Self` in which case this function would simply return `self`. #[cfg(feature = "component-model")] fn component_compiler(&self) -> &dyn crate::component::ComponentCompiler; } /// Value of a configured setting for a [`Compiler`] #[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Debug)] pub enum FlagValue { /// Name of the value that has been configured for this setting. Enum(Cow<'static, str>), /// The numerical value of the configured settings. Num(u8), /// Whether the setting is on or off. Bool(bool), } impl fmt::Display for FlagValue { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Self::Enum(v) => v.fmt(f), Self::Num(v) => v.fmt(f), Self::Bool(v) => v.fmt(f), } } }