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