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