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