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}