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