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