1 //! Runtime library support for Wasmtime. 2 3 #![deny(missing_docs)] 4 #![warn(clippy::cast_sign_loss)] 5 6 use crate::prelude::*; 7 use alloc::sync::Arc; 8 use core::fmt; 9 use core::mem; 10 use core::ptr::NonNull; 11 use core::sync::atomic::{AtomicU64, AtomicUsize, Ordering}; 12 use wasmtime_environ::{ 13 DefinedFuncIndex, DefinedMemoryIndex, HostPtr, ModuleInternedTypeIndex, VMOffsets, 14 VMSharedTypeIndex, 15 }; 16 17 mod arch; 18 mod async_yield; 19 #[cfg(feature = "component-model")] 20 pub mod component; 21 mod const_expr; 22 mod export; 23 mod gc; 24 mod imports; 25 mod instance; 26 mod memory; 27 mod mmap; 28 mod mmap_vec; 29 mod send_sync_ptr; 30 mod store_box; 31 mod sys; 32 mod table; 33 mod traphandlers; 34 mod vmcontext; 35 36 mod threads; 37 pub use self::threads::*; 38 39 #[cfg(feature = "debug-builtins")] 40 pub mod debug_builtins; 41 pub mod libcalls; 42 pub mod mpk; 43 44 #[cfg(feature = "debug-builtins")] 45 pub use wasmtime_jit_debug::gdb_jit_int::GdbJitImageRegistration; 46 47 pub use crate::runtime::vm::arch::get_stack_pointer; 48 pub use crate::runtime::vm::async_yield::*; 49 pub use crate::runtime::vm::export::*; 50 pub use crate::runtime::vm::gc::*; 51 pub use crate::runtime::vm::imports::Imports; 52 pub use crate::runtime::vm::instance::{ 53 GcHeapAllocationIndex, Instance, InstanceAllocationRequest, InstanceAllocator, 54 InstanceAllocatorImpl, InstanceHandle, MemoryAllocationIndex, OnDemandInstanceAllocator, 55 StorePtr, TableAllocationIndex, 56 }; 57 #[cfg(feature = "pooling-allocator")] 58 pub use crate::runtime::vm::instance::{ 59 InstanceLimits, PoolConcurrencyLimitError, PoolingInstanceAllocator, 60 PoolingInstanceAllocatorConfig, 61 }; 62 pub use crate::runtime::vm::memory::{Memory, RuntimeLinearMemory, RuntimeMemoryCreator}; 63 pub use crate::runtime::vm::mmap::Mmap; 64 pub use crate::runtime::vm::mmap_vec::MmapVec; 65 pub use crate::runtime::vm::mpk::MpkEnabled; 66 pub use crate::runtime::vm::store_box::*; 67 pub use crate::runtime::vm::sys::unwind::UnwindRegistration; 68 pub use crate::runtime::vm::table::{Table, TableElement}; 69 pub use crate::runtime::vm::traphandlers::*; 70 pub use crate::runtime::vm::vmcontext::{ 71 VMArrayCallFunction, VMArrayCallHostFuncContext, VMContext, VMFuncRef, VMFunctionBody, 72 VMFunctionImport, VMGlobalDefinition, VMGlobalImport, VMMemoryDefinition, VMMemoryImport, 73 VMOpaqueContext, VMRuntimeLimits, VMTableImport, VMWasmCallFunction, ValRaw, 74 }; 75 pub use send_sync_ptr::SendSyncPtr; 76 77 mod module_id; 78 pub use module_id::CompiledModuleId; 79 80 mod cow; 81 pub use crate::runtime::vm::cow::{MemoryImage, MemoryImageSlot, ModuleMemoryImages}; 82 83 /// Dynamic runtime functionality needed by this crate throughout the execution 84 /// of a wasm instance. 85 /// 86 /// This trait is used to store a raw pointer trait object within each 87 /// `VMContext`. This raw pointer trait object points back to the 88 /// `wasmtime::Store` internally but is type-erased so this `wasmtime-runtime` 89 /// crate doesn't need the entire `wasmtime` crate to build. 90 /// 91 /// Note that this is an extra-unsafe trait because no heed is paid to the 92 /// lifetime of this store or the Send/Sync-ness of this store. All of that must 93 /// be respected by embedders (e.g. the `wasmtime::Store` structure). The theory 94 /// is that `wasmtime::Store` handles all this correctly. 95 pub unsafe trait Store { 96 /// Returns the raw pointer in memory where this store's shared 97 /// `VMRuntimeLimits` structure is located. 98 /// 99 /// Used to configure `VMContext` initialization and store the right pointer 100 /// in the `VMContext`. 101 fn vmruntime_limits(&self) -> *mut VMRuntimeLimits; 102 103 /// Returns a pointer to the global epoch counter. 104 /// 105 /// Used to configure the `VMContext` on initialization. 106 fn epoch_ptr(&self) -> *const AtomicU64; 107 108 /// Get this store's GC heap. 109 fn gc_store(&mut self) -> &mut GcStore { 110 self.maybe_gc_store() 111 .expect("attempt to access the GC store before it has been allocated") 112 } 113 114 /// Get this store's GC heap, if it has been allocated. 115 fn maybe_gc_store(&mut self) -> Option<&mut GcStore>; 116 117 /// Callback invoked to allow the store's resource limiter to reject a 118 /// memory grow operation. 119 fn memory_growing( 120 &mut self, 121 current: usize, 122 desired: usize, 123 maximum: Option<usize>, 124 ) -> Result<bool, Error>; 125 126 /// Callback invoked to notify the store's resource limiter that a memory 127 /// grow operation has failed. 128 /// 129 /// Note that this is not invoked if `memory_growing` returns an error. 130 fn memory_grow_failed(&mut self, error: Error) -> Result<()>; 131 132 /// Callback invoked to allow the store's resource limiter to reject a 133 /// table grow operation. 134 fn table_growing( 135 &mut self, 136 current: u32, 137 desired: u32, 138 maximum: Option<u32>, 139 ) -> Result<bool, Error>; 140 141 /// Callback invoked to notify the store's resource limiter that a table 142 /// grow operation has failed. 143 /// 144 /// Note that this is not invoked if `table_growing` returns an error. 145 fn table_grow_failed(&mut self, error: Error) -> Result<()>; 146 147 /// Callback invoked whenever fuel runs out by a wasm instance. If an error 148 /// is returned that's raised as a trap. Otherwise wasm execution will 149 /// continue as normal. 150 fn out_of_gas(&mut self) -> Result<(), Error>; 151 152 /// Callback invoked whenever an instance observes a new epoch 153 /// number. Cannot fail; cooperative epoch-based yielding is 154 /// completely semantically transparent. Returns the new deadline. 155 fn new_epoch(&mut self) -> Result<u64, Error>; 156 157 /// Callback invoked whenever an instance needs to trigger a GC. 158 /// 159 /// Optionally given a GC reference that is rooted for the collection, and 160 /// then whose updated GC reference is returned. 161 /// 162 /// Cooperative, async-yielding (if configured) is completely transparent. 163 /// 164 /// If the async GC was cancelled, returns an error. This should be raised 165 /// as a trap to clean up Wasm execution. 166 fn gc(&mut self, root: Option<VMGcRef>) -> Result<Option<VMGcRef>>; 167 168 /// Metadata required for resources for the component model. 169 #[cfg(feature = "component-model")] 170 fn component_calls(&mut self) -> &mut component::CallContexts; 171 } 172 173 /// Functionality required by this crate for a particular module. This 174 /// is chiefly needed for lazy initialization of various bits of 175 /// instance state. 176 /// 177 /// When an instance is created, it holds an `Arc<dyn ModuleRuntimeInfo>` 178 /// so that it can get to signatures, metadata on functions, memory and 179 /// funcref-table images, etc. All of these things are ordinarily known 180 /// by the higher-level layers of Wasmtime. Specifically, the main 181 /// implementation of this trait is provided by 182 /// `wasmtime::module::ModuleInner`. Since the runtime crate sits at 183 /// the bottom of the dependence DAG though, we don't know or care about 184 /// that; we just need some implementor of this trait for each 185 /// allocation request. 186 #[derive(Clone)] 187 pub enum ModuleRuntimeInfo { 188 Module(crate::Module), 189 Bare(Box<BareModuleInfo>), 190 } 191 192 /// A barebones implementation of ModuleRuntimeInfo that is useful for 193 /// cases where a purpose-built environ::Module is used and a full 194 /// CompiledModule does not exist (for example, for tests or for the 195 /// default-callee instance). 196 #[derive(Clone)] 197 pub struct BareModuleInfo { 198 module: Arc<wasmtime_environ::Module>, 199 one_signature: Option<VMSharedTypeIndex>, 200 offsets: VMOffsets<HostPtr>, 201 } 202 203 impl ModuleRuntimeInfo { 204 pub(crate) fn bare(module: Arc<wasmtime_environ::Module>) -> Self { 205 ModuleRuntimeInfo::bare_maybe_imported_func(module, None) 206 } 207 208 pub(crate) fn bare_maybe_imported_func( 209 module: Arc<wasmtime_environ::Module>, 210 one_signature: Option<VMSharedTypeIndex>, 211 ) -> Self { 212 ModuleRuntimeInfo::Bare(Box::new(BareModuleInfo { 213 offsets: VMOffsets::new(HostPtr, &module), 214 module, 215 one_signature, 216 })) 217 } 218 219 /// The underlying Module. 220 pub(crate) fn module(&self) -> &Arc<wasmtime_environ::Module> { 221 match self { 222 ModuleRuntimeInfo::Module(m) => m.env_module(), 223 ModuleRuntimeInfo::Bare(b) => &b.module, 224 } 225 } 226 227 /// Translate a module-level interned type index into an engine-level 228 /// interned type index. 229 fn engine_type_index(&self, module_index: ModuleInternedTypeIndex) -> VMSharedTypeIndex { 230 match self { 231 ModuleRuntimeInfo::Module(m) => m 232 .code_object() 233 .signatures() 234 .shared_type(module_index) 235 .expect("bad module-level interned type index"), 236 ModuleRuntimeInfo::Bare(_) => unreachable!(), 237 } 238 } 239 240 /// Returns the address, in memory, that the function `index` resides at. 241 fn function(&self, index: DefinedFuncIndex) -> NonNull<VMWasmCallFunction> { 242 let module = match self { 243 ModuleRuntimeInfo::Module(m) => m, 244 ModuleRuntimeInfo::Bare(_) => unreachable!(), 245 }; 246 let ptr = module 247 .compiled_module() 248 .finished_function(index) 249 .as_ptr() 250 .cast::<VMWasmCallFunction>() 251 .cast_mut(); 252 NonNull::new(ptr).unwrap() 253 } 254 255 /// Returns the address, in memory, of the trampoline that allows the given 256 /// defined Wasm function to be called by the array calling convention. 257 /// 258 /// Returns `None` for Wasm functions which do not escape, and therefore are 259 /// not callable from outside the Wasm module itself. 260 fn array_to_wasm_trampoline(&self, index: DefinedFuncIndex) -> Option<VMArrayCallFunction> { 261 let m = match self { 262 ModuleRuntimeInfo::Module(m) => m, 263 ModuleRuntimeInfo::Bare(_) => unreachable!(), 264 }; 265 let ptr = m 266 .compiled_module() 267 .array_to_wasm_trampoline(index)? 268 .as_ptr(); 269 Some(unsafe { mem::transmute::<*const u8, VMArrayCallFunction>(ptr) }) 270 } 271 272 /// Returns the `MemoryImage` structure used for copy-on-write 273 /// initialization of the memory, if it's applicable. 274 fn memory_image( 275 &self, 276 memory: DefinedMemoryIndex, 277 ) -> anyhow::Result<Option<&Arc<MemoryImage>>> { 278 match self { 279 ModuleRuntimeInfo::Module(m) => { 280 let images = m.memory_images()?; 281 Ok(images.and_then(|images| images.get_memory_image(memory))) 282 } 283 ModuleRuntimeInfo::Bare(_) => Ok(None), 284 } 285 } 286 287 /// A unique ID for this particular module. This can be used to 288 /// allow for fastpaths to optimize a "re-instantiate the same 289 /// module again" case. 290 fn unique_id(&self) -> Option<CompiledModuleId> { 291 match self { 292 ModuleRuntimeInfo::Module(m) => Some(m.id()), 293 ModuleRuntimeInfo::Bare(_) => None, 294 } 295 } 296 297 /// A slice pointing to all data that is referenced by this instance. 298 fn wasm_data(&self) -> &[u8] { 299 match self { 300 ModuleRuntimeInfo::Module(m) => m.compiled_module().code_memory().wasm_data(), 301 ModuleRuntimeInfo::Bare(_) => &[], 302 } 303 } 304 305 /// Returns an array, indexed by `ModuleInternedTypeIndex` of all 306 /// `VMSharedSignatureIndex` entries corresponding to the `SignatureIndex`. 307 fn type_ids(&self) -> &[VMSharedTypeIndex] { 308 match self { 309 ModuleRuntimeInfo::Module(m) => m 310 .code_object() 311 .signatures() 312 .as_module_map() 313 .values() 314 .as_slice(), 315 ModuleRuntimeInfo::Bare(b) => match &b.one_signature { 316 Some(s) => core::slice::from_ref(s), 317 None => &[], 318 }, 319 } 320 } 321 322 /// Offset information for the current host. 323 pub(crate) fn offsets(&self) -> &VMOffsets<HostPtr> { 324 match self { 325 ModuleRuntimeInfo::Module(m) => m.offsets(), 326 ModuleRuntimeInfo::Bare(b) => &b.offsets, 327 } 328 } 329 } 330 331 /// Returns the host OS page size, in bytes. 332 pub fn host_page_size() -> usize { 333 static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0); 334 335 return match PAGE_SIZE.load(Ordering::Relaxed) { 336 0 => { 337 let size = sys::vm::get_page_size(); 338 assert!(size != 0); 339 PAGE_SIZE.store(size, Ordering::Relaxed); 340 size 341 } 342 n => n, 343 }; 344 } 345 346 /// Is `bytes` a multiple of the host page size? 347 pub fn usize_is_multiple_of_host_page_size(bytes: usize) -> bool { 348 bytes % host_page_size() == 0 349 } 350 351 /// Round the given byte size up to a multiple of the host OS page size. 352 /// 353 /// Returns an error if rounding up overflows. 354 pub fn round_u64_up_to_host_pages(bytes: u64) -> Result<u64> { 355 let page_size = u64::try_from(crate::runtime::vm::host_page_size()).err2anyhow()?; 356 debug_assert!(page_size.is_power_of_two()); 357 bytes 358 .checked_add(page_size - 1) 359 .ok_or_else(|| anyhow!( 360 "{bytes} is too large to be rounded up to a multiple of the host page size of {page_size}" 361 )) 362 .map(|val| val & !(page_size - 1)) 363 } 364 365 /// Same as `round_u64_up_to_host_pages` but for `usize`s. 366 pub fn round_usize_up_to_host_pages(bytes: usize) -> Result<usize> { 367 let bytes = u64::try_from(bytes).err2anyhow()?; 368 let rounded = round_u64_up_to_host_pages(bytes)?; 369 Ok(usize::try_from(rounded).err2anyhow()?) 370 } 371 372 /// Result of `Memory::atomic_wait32` and `Memory::atomic_wait64` 373 #[derive(Copy, Clone, PartialEq, Eq, Debug)] 374 pub enum WaitResult { 375 /// Indicates that a `wait` completed by being awoken by a different thread. 376 /// This means the thread went to sleep and didn't time out. 377 Ok = 0, 378 /// Indicates that `wait` did not complete and instead returned due to the 379 /// value in memory not matching the expected value. 380 Mismatch = 1, 381 /// Indicates that `wait` completed with a timeout, meaning that the 382 /// original value matched as expected but nothing ever called `notify`. 383 TimedOut = 2, 384 } 385 386 /// Description about a fault that occurred in WebAssembly. 387 #[derive(Debug)] 388 pub struct WasmFault { 389 /// The size of memory, in bytes, at the time of the fault. 390 pub memory_size: usize, 391 /// The WebAssembly address at which the fault occurred. 392 pub wasm_address: u64, 393 } 394 395 impl fmt::Display for WasmFault { 396 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 397 write!( 398 f, 399 "memory fault at wasm address 0x{:x} in linear memory of size 0x{:x}", 400 self.wasm_address, self.memory_size, 401 ) 402 } 403 } 404