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