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