1 //! Runtime library support for Wasmtime. 2 3 #![deny(missing_docs)] 4 // See documentation in crates/wasmtime/src/runtime.rs for why this is 5 // selectively enabled here. 6 #![warn(clippy::cast_sign_loss)] 7 8 // Polyfill `std::simd::i8x16` etc. until they're stable. 9 #[cfg(all(target_arch = "x86_64", target_feature = "sse"))] 10 #[expect(non_camel_case_types, reason = "matching wasm conventions")] 11 pub(crate) type i8x16 = core::arch::x86_64::__m128i; 12 #[cfg(all(target_arch = "x86_64", target_feature = "sse"))] 13 #[expect(non_camel_case_types, reason = "matching wasm conventions")] 14 pub(crate) type f32x4 = core::arch::x86_64::__m128; 15 #[cfg(all(target_arch = "x86_64", target_feature = "sse"))] 16 #[expect(non_camel_case_types, reason = "matching wasm conventions")] 17 pub(crate) type f64x2 = core::arch::x86_64::__m128d; 18 19 // On platforms other than x86_64, define i8x16 to a non-constructible type; 20 // we need a type because we have a lot of macros for defining builtin 21 // functions that are awkward to make conditional on the target, but it 22 // doesn't need to actually be constructible unless we're on x86_64. 23 #[cfg(not(all(target_arch = "x86_64", target_feature = "sse")))] 24 #[expect(non_camel_case_types, reason = "matching wasm conventions")] 25 #[derive(Copy, Clone)] 26 pub(crate) struct i8x16(crate::uninhabited::Uninhabited); 27 #[cfg(not(all(target_arch = "x86_64", target_feature = "sse")))] 28 #[expect(non_camel_case_types, reason = "matching wasm conventions")] 29 #[derive(Copy, Clone)] 30 pub(crate) struct f32x4(crate::uninhabited::Uninhabited); 31 #[cfg(not(all(target_arch = "x86_64", target_feature = "sse")))] 32 #[expect(non_camel_case_types, reason = "matching wasm conventions")] 33 #[derive(Copy, Clone)] 34 pub(crate) struct f64x2(crate::uninhabited::Uninhabited); 35 36 use crate::StoreContextMut; 37 use crate::prelude::*; 38 use crate::store::StoreInner; 39 use crate::store::StoreOpaque; 40 use crate::type_registry::RegisteredType; 41 use alloc::sync::Arc; 42 use core::fmt; 43 use core::ops::Deref; 44 use core::ops::DerefMut; 45 use core::ptr::NonNull; 46 use core::sync::atomic::{AtomicUsize, Ordering}; 47 use wasmtime_environ::{ 48 DefinedFuncIndex, DefinedMemoryIndex, HostPtr, VMOffsets, VMSharedTypeIndex, 49 }; 50 51 #[cfg(feature = "gc")] 52 use wasmtime_environ::ModuleInternedTypeIndex; 53 54 #[cfg(feature = "component-model")] 55 pub mod component; 56 mod const_expr; 57 mod export; 58 mod gc; 59 mod imports; 60 mod instance; 61 mod memory; 62 mod mmap_vec; 63 #[cfg(has_virtual_memory)] 64 mod pagemap_disabled; 65 mod provenance; 66 mod send_sync_ptr; 67 mod stack_switching; 68 mod store_box; 69 mod sys; 70 mod table; 71 mod traphandlers; 72 mod vmcontext; 73 74 #[cfg(feature = "threads")] 75 mod parking_spot; 76 77 // Note that `debug_builtins` here is disabled with a feature or a lack of a 78 // native compilation backend because it's only here to assist in debugging 79 // natively compiled code. 80 #[cfg(all(has_host_compiler_backend, feature = "debug-builtins"))] 81 pub mod debug_builtins; 82 pub mod libcalls; 83 pub mod mpk; 84 85 #[cfg(feature = "pulley")] 86 pub(crate) mod interpreter; 87 #[cfg(not(feature = "pulley"))] 88 pub(crate) mod interpreter_disabled; 89 #[cfg(not(feature = "pulley"))] 90 pub(crate) use interpreter_disabled as interpreter; 91 92 #[cfg(feature = "debug-builtins")] 93 pub use wasmtime_jit_debug::gdb_jit_int::GdbJitImageRegistration; 94 95 pub use crate::runtime::vm::export::*; 96 pub use crate::runtime::vm::gc::*; 97 pub use crate::runtime::vm::imports::Imports; 98 pub use crate::runtime::vm::instance::{ 99 GcHeapAllocationIndex, Instance, InstanceAllocationRequest, InstanceAllocator, 100 InstanceAllocatorImpl, InstanceAndStore, InstanceHandle, MemoryAllocationIndex, 101 OnDemandInstanceAllocator, StorePtr, TableAllocationIndex, initialize_instance, 102 }; 103 #[cfg(feature = "pooling-allocator")] 104 pub use crate::runtime::vm::instance::{ 105 InstanceLimits, PoolConcurrencyLimitError, PoolingInstanceAllocator, 106 PoolingInstanceAllocatorConfig, 107 }; 108 pub use crate::runtime::vm::interpreter::*; 109 pub use crate::runtime::vm::memory::{ 110 Memory, MemoryBase, RuntimeLinearMemory, RuntimeMemoryCreator, SharedMemory, 111 }; 112 pub use crate::runtime::vm::mmap_vec::MmapVec; 113 pub use crate::runtime::vm::provenance::*; 114 pub use crate::runtime::vm::stack_switching::*; 115 pub use crate::runtime::vm::store_box::*; 116 #[cfg(feature = "std")] 117 pub use crate::runtime::vm::sys::mmap::open_file_for_mmap; 118 #[cfg(has_host_compiler_backend)] 119 pub use crate::runtime::vm::sys::unwind::UnwindRegistration; 120 pub use crate::runtime::vm::table::{Table, TableElementType}; 121 pub use crate::runtime::vm::traphandlers::*; 122 pub use crate::runtime::vm::vmcontext::{ 123 VMArrayCallFunction, VMArrayCallHostFuncContext, VMContext, VMFuncRef, VMFunctionImport, 124 VMGlobalDefinition, VMGlobalImport, VMGlobalKind, VMMemoryDefinition, VMMemoryImport, 125 VMOpaqueContext, VMStoreContext, VMTableImport, VMTagImport, VMWasmCallFunction, ValRaw, 126 }; 127 128 pub use send_sync_ptr::SendSyncPtr; 129 pub use wasmtime_unwinder::Unwind; 130 131 #[cfg(has_host_compiler_backend)] 132 pub use wasmtime_unwinder::{UnwindHost, get_stack_pointer}; 133 134 mod module_id; 135 pub use module_id::CompiledModuleId; 136 137 #[cfg(has_virtual_memory)] 138 mod byte_count; 139 #[cfg(has_virtual_memory)] 140 mod cow; 141 #[cfg(not(has_virtual_memory))] 142 mod cow_disabled; 143 #[cfg(has_virtual_memory)] 144 mod mmap; 145 146 #[cfg(feature = "async")] 147 mod async_yield; 148 #[cfg(feature = "async")] 149 pub use crate::runtime::vm::async_yield::*; 150 151 #[cfg(feature = "gc-null")] 152 mod send_sync_unsafe_cell; 153 #[cfg(feature = "gc-null")] 154 pub use send_sync_unsafe_cell::SendSyncUnsafeCell; 155 156 cfg_if::cfg_if! { 157 if #[cfg(has_virtual_memory)] { 158 pub use crate::runtime::vm::byte_count::*; 159 pub use crate::runtime::vm::mmap::{Mmap, MmapOffset}; 160 pub use self::cow::{MemoryImage, MemoryImageSlot, ModuleMemoryImages}; 161 } else { 162 pub use self::cow_disabled::{MemoryImage, MemoryImageSlot, ModuleMemoryImages}; 163 } 164 } 165 166 /// Source of data used for [`MemoryImage`] 167 pub trait ModuleMemoryImageSource: Send + Sync + 'static { 168 /// Returns this image's slice of all wasm data for a module which is then 169 /// further sub-sliced for a particular initialization segment. 170 fn wasm_data(&self) -> &[u8]; 171 172 /// Optionally returns the backing mmap. Used for using the backing mmap's 173 /// file to perform other mmaps, for example. 174 fn mmap(&self) -> Option<&MmapVec>; 175 } 176 177 /// Dynamic runtime functionality needed by this crate throughout the execution 178 /// of a wasm instance. 179 /// 180 /// This trait is used to store a raw pointer trait object within each 181 /// `VMContext`. This raw pointer trait object points back to the 182 /// `wasmtime::Store` internally but is type-erased to avoid needing to 183 /// monomorphize the entire runtime on the `T` in `Store<T>` 184 /// 185 /// # Safety 186 /// 187 /// This trait should be implemented by nothing other than `StoreInner<T>` in 188 /// this crate. It's not sound to implement it for anything else due to 189 /// `unchecked_context_mut` below. 190 /// 191 /// It's also worth nothing that there are various locations where a `*mut dyn 192 /// VMStore` is asserted to be both `Send` and `Sync` which disregards the `T` 193 /// that's actually stored in the store itself. It's assume that the high-level 194 /// APIs using `Store<T>` are correctly inferring send/sync on the returned 195 /// values (e.g. futures) and that internally in the runtime we aren't doing 196 /// anything "weird" with threads for example. 197 pub unsafe trait VMStore: 'static { 198 /// Get a shared borrow of this store's `StoreOpaque`. 199 fn store_opaque(&self) -> &StoreOpaque; 200 201 /// Get an exclusive borrow of this store's `StoreOpaque`. 202 fn store_opaque_mut(&mut self) -> &mut StoreOpaque; 203 204 /// Callback invoked to allow the store's resource limiter to reject a 205 /// memory grow operation. 206 fn memory_growing( 207 &mut self, 208 current: usize, 209 desired: usize, 210 maximum: Option<usize>, 211 ) -> Result<bool, Error>; 212 213 /// Callback invoked to notify the store's resource limiter that a memory 214 /// grow operation has failed. 215 /// 216 /// Note that this is not invoked if `memory_growing` returns an error. 217 fn memory_grow_failed(&mut self, error: Error) -> Result<()>; 218 219 /// Callback invoked to allow the store's resource limiter to reject a 220 /// table grow operation. 221 fn table_growing( 222 &mut self, 223 current: usize, 224 desired: usize, 225 maximum: Option<usize>, 226 ) -> Result<bool, Error>; 227 228 /// Callback invoked to notify the store's resource limiter that a table 229 /// grow operation has failed. 230 /// 231 /// Note that this is not invoked if `table_growing` returns an error. 232 fn table_grow_failed(&mut self, error: Error) -> Result<()>; 233 234 /// Callback invoked whenever fuel runs out by a wasm instance. If an error 235 /// is returned that's raised as a trap. Otherwise wasm execution will 236 /// continue as normal. 237 fn out_of_gas(&mut self) -> Result<(), Error>; 238 239 /// Callback invoked whenever an instance observes a new epoch 240 /// number. Cannot fail; cooperative epoch-based yielding is 241 /// completely semantically transparent. Returns the new deadline. 242 #[cfg(target_has_atomic = "64")] 243 fn new_epoch(&mut self) -> Result<u64, Error>; 244 245 /// Metadata required for resources for the component model. 246 #[cfg(feature = "component-model")] 247 fn component_calls(&mut self) -> &mut component::CallContexts; 248 249 #[cfg(feature = "component-model-async")] 250 fn component_async_store( 251 &mut self, 252 ) -> &mut dyn crate::runtime::component::VMComponentAsyncStore; 253 } 254 255 impl Deref for dyn VMStore + '_ { 256 type Target = StoreOpaque; 257 258 fn deref(&self) -> &Self::Target { 259 self.store_opaque() 260 } 261 } 262 263 impl DerefMut for dyn VMStore + '_ { 264 fn deref_mut(&mut self) -> &mut Self::Target { 265 self.store_opaque_mut() 266 } 267 } 268 269 impl dyn VMStore + '_ { 270 /// Asserts that this `VMStore` was originally paired with `StoreInner<T>` 271 /// and then casts to the `StoreContextMut` type. 272 /// 273 /// # Unsafety 274 /// 275 /// This method is not safe as there's no static guarantee that `T` is 276 /// correct for this store. 277 pub(crate) unsafe fn unchecked_context_mut<T>(&mut self) -> StoreContextMut<'_, T> { 278 unsafe { StoreContextMut(&mut *(self as *mut dyn VMStore as *mut StoreInner<T>)) } 279 } 280 } 281 282 /// A newtype wrapper around `NonNull<dyn VMStore>` intended to be a 283 /// self-pointer back to the `Store<T>` within raw data structures like 284 /// `VMContext`. 285 /// 286 /// This type exists to manually, and unsafely, implement `Send` and `Sync`. 287 /// The `VMStore` trait doesn't require `Send` or `Sync` which means this isn't 288 /// naturally either trait (e.g. with `SendSyncPtr` instead). Note that this 289 /// means that `Instance` is, for example, mistakenly considered 290 /// unconditionally `Send` and `Sync`. This is hopefully ok for now though 291 /// because from a user perspective the only type that matters is `Store<T>`. 292 /// That type is `Send + Sync` if `T: Send + Sync` already so the internal 293 /// storage of `Instance` shouldn't matter as the final result is the same. 294 /// Note though that this means we need to be extra vigilant about cross-thread 295 /// usage of `Instance` and `ComponentInstance` for example. 296 #[derive(Copy, Clone)] 297 #[repr(transparent)] 298 struct VMStoreRawPtr(pub NonNull<dyn VMStore>); 299 300 // SAFETY: this is the purpose of `VMStoreRawPtr`, see docs above about safe 301 // usage. 302 unsafe impl Send for VMStoreRawPtr {} 303 unsafe impl Sync for VMStoreRawPtr {} 304 305 /// Functionality required by this crate for a particular module. This 306 /// is chiefly needed for lazy initialization of various bits of 307 /// instance state. 308 /// 309 /// When an instance is created, it holds an `Arc<dyn ModuleRuntimeInfo>` 310 /// so that it can get to signatures, metadata on functions, memory and 311 /// funcref-table images, etc. All of these things are ordinarily known 312 /// by the higher-level layers of Wasmtime. Specifically, the main 313 /// implementation of this trait is provided by 314 /// `wasmtime::module::ModuleInner`. Since the runtime crate sits at 315 /// the bottom of the dependence DAG though, we don't know or care about 316 /// that; we just need some implementor of this trait for each 317 /// allocation request. 318 #[derive(Clone)] 319 pub enum ModuleRuntimeInfo { 320 Module(crate::Module), 321 Bare(Box<BareModuleInfo>), 322 } 323 324 /// A barebones implementation of ModuleRuntimeInfo that is useful for 325 /// cases where a purpose-built environ::Module is used and a full 326 /// CompiledModule does not exist (for example, for tests or for the 327 /// default-callee instance). 328 #[derive(Clone)] 329 pub struct BareModuleInfo { 330 module: Arc<wasmtime_environ::Module>, 331 offsets: VMOffsets<HostPtr>, 332 _registered_type: Option<RegisteredType>, 333 } 334 335 impl ModuleRuntimeInfo { 336 pub(crate) fn bare(module: Arc<wasmtime_environ::Module>) -> Self { 337 ModuleRuntimeInfo::bare_with_registered_type(module, None) 338 } 339 340 pub(crate) fn bare_with_registered_type( 341 module: Arc<wasmtime_environ::Module>, 342 registered_type: Option<RegisteredType>, 343 ) -> Self { 344 ModuleRuntimeInfo::Bare(Box::new(BareModuleInfo { 345 offsets: VMOffsets::new(HostPtr, &module), 346 module, 347 _registered_type: registered_type, 348 })) 349 } 350 351 /// The underlying Module. 352 pub(crate) fn env_module(&self) -> &Arc<wasmtime_environ::Module> { 353 match self { 354 ModuleRuntimeInfo::Module(m) => m.env_module(), 355 ModuleRuntimeInfo::Bare(b) => &b.module, 356 } 357 } 358 359 /// Translate a module-level interned type index into an engine-level 360 /// interned type index. 361 #[cfg(feature = "gc")] 362 fn engine_type_index(&self, module_index: ModuleInternedTypeIndex) -> VMSharedTypeIndex { 363 match self { 364 ModuleRuntimeInfo::Module(m) => m 365 .code_object() 366 .signatures() 367 .shared_type(module_index) 368 .expect("bad module-level interned type index"), 369 ModuleRuntimeInfo::Bare(_) => unreachable!(), 370 } 371 } 372 373 /// Returns the address, in memory, that the function `index` resides at. 374 fn function(&self, index: DefinedFuncIndex) -> NonNull<VMWasmCallFunction> { 375 let module = match self { 376 ModuleRuntimeInfo::Module(m) => m, 377 ModuleRuntimeInfo::Bare(_) => unreachable!(), 378 }; 379 let ptr = module 380 .compiled_module() 381 .finished_function(index) 382 .as_ptr() 383 .cast::<VMWasmCallFunction>() 384 .cast_mut(); 385 NonNull::new(ptr).unwrap() 386 } 387 388 /// Returns the address, in memory, of the trampoline that allows the given 389 /// defined Wasm function to be called by the array calling convention. 390 /// 391 /// Returns `None` for Wasm functions which do not escape, and therefore are 392 /// not callable from outside the Wasm module itself. 393 fn array_to_wasm_trampoline( 394 &self, 395 index: DefinedFuncIndex, 396 ) -> Option<NonNull<VMArrayCallFunction>> { 397 let m = match self { 398 ModuleRuntimeInfo::Module(m) => m, 399 ModuleRuntimeInfo::Bare(_) => unreachable!(), 400 }; 401 let ptr = NonNull::from(m.compiled_module().array_to_wasm_trampoline(index)?); 402 Some(ptr.cast()) 403 } 404 405 /// Returns the `MemoryImage` structure used for copy-on-write 406 /// initialization of the memory, if it's applicable. 407 fn memory_image( 408 &self, 409 memory: DefinedMemoryIndex, 410 ) -> anyhow::Result<Option<&Arc<MemoryImage>>> { 411 match self { 412 ModuleRuntimeInfo::Module(m) => { 413 let images = m.memory_images()?; 414 Ok(images.and_then(|images| images.get_memory_image(memory))) 415 } 416 ModuleRuntimeInfo::Bare(_) => Ok(None), 417 } 418 } 419 420 /// A unique ID for this particular module. This can be used to 421 /// allow for fastpaths to optimize a "re-instantiate the same 422 /// module again" case. 423 #[cfg(feature = "pooling-allocator")] 424 fn unique_id(&self) -> Option<CompiledModuleId> { 425 match self { 426 ModuleRuntimeInfo::Module(m) => Some(m.id()), 427 ModuleRuntimeInfo::Bare(_) => None, 428 } 429 } 430 431 /// A slice pointing to all data that is referenced by this instance. 432 fn wasm_data(&self) -> &[u8] { 433 match self { 434 ModuleRuntimeInfo::Module(m) => m.compiled_module().code_memory().wasm_data(), 435 ModuleRuntimeInfo::Bare(_) => &[], 436 } 437 } 438 439 /// Returns an array, indexed by `ModuleInternedTypeIndex` of all 440 /// `VMSharedSignatureIndex` entries corresponding to the `SignatureIndex`. 441 fn type_ids(&self) -> &[VMSharedTypeIndex] { 442 match self { 443 ModuleRuntimeInfo::Module(m) => m 444 .code_object() 445 .signatures() 446 .as_module_map() 447 .values() 448 .as_slice(), 449 ModuleRuntimeInfo::Bare(_) => &[], 450 } 451 } 452 453 /// Offset information for the current host. 454 pub(crate) fn offsets(&self) -> &VMOffsets<HostPtr> { 455 match self { 456 ModuleRuntimeInfo::Module(m) => m.offsets(), 457 ModuleRuntimeInfo::Bare(b) => &b.offsets, 458 } 459 } 460 } 461 462 /// Returns the host OS page size, in bytes. 463 #[cfg(has_virtual_memory)] 464 pub fn host_page_size() -> usize { 465 // NB: this function is duplicated in `crates/fiber/src/unix.rs` so if this 466 // changes that should probably get updated as well. 467 static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0); 468 469 return match PAGE_SIZE.load(Ordering::Relaxed) { 470 0 => { 471 let size = sys::vm::get_page_size(); 472 assert!(size != 0); 473 PAGE_SIZE.store(size, Ordering::Relaxed); 474 size 475 } 476 n => n, 477 }; 478 } 479 480 /// Result of `Memory::atomic_wait32` and `Memory::atomic_wait64` 481 #[derive(Copy, Clone, PartialEq, Eq, Debug)] 482 pub enum WaitResult { 483 /// Indicates that a `wait` completed by being awoken by a different thread. 484 /// This means the thread went to sleep and didn't time out. 485 Ok = 0, 486 /// Indicates that `wait` did not complete and instead returned due to the 487 /// value in memory not matching the expected value. 488 Mismatch = 1, 489 /// Indicates that `wait` completed with a timeout, meaning that the 490 /// original value matched as expected but nothing ever called `notify`. 491 TimedOut = 2, 492 } 493 494 /// Description about a fault that occurred in WebAssembly. 495 #[derive(Debug)] 496 pub struct WasmFault { 497 /// The size of memory, in bytes, at the time of the fault. 498 pub memory_size: usize, 499 /// The WebAssembly address at which the fault occurred. 500 pub wasm_address: u64, 501 } 502 503 impl fmt::Display for WasmFault { 504 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 505 write!( 506 f, 507 "memory fault at wasm address 0x{:x} in linear memory of size 0x{:x}", 508 self.wasm_address, self.memory_size, 509 ) 510 } 511 } 512