#![deny(missing_docs)]
#![warn(clippy::cast_sign_loss)]
#[cfg(all(target_arch = "x86_64", target_feature = "sse"))]
#[expect(non_camel_case_types, reason = "matching wasm conventions")]
pub(crate) type i8x16 = core::arch::x86_64::__m128i;
#[cfg(all(target_arch = "x86_64", target_feature = "sse"))]
#[expect(non_camel_case_types, reason = "matching wasm conventions")]
pub(crate) type f32x4 = core::arch::x86_64::__m128;
#[cfg(all(target_arch = "x86_64", target_feature = "sse"))]
#[expect(non_camel_case_types, reason = "matching wasm conventions")]
pub(crate) type f64x2 = core::arch::x86_64::__m128d;
#[cfg(not(all(target_arch = "x86_64", target_feature = "sse")))]
#[expect(non_camel_case_types, reason = "matching wasm conventions")]
#[derive(Copy, Clone)]
pub(crate) struct i8x16(core::convert::Infallible);
#[cfg(not(all(target_arch = "x86_64", target_feature = "sse")))]
#[expect(non_camel_case_types, reason = "matching wasm conventions")]
#[derive(Copy, Clone)]
pub(crate) struct f32x4(core::convert::Infallible);
#[cfg(not(all(target_arch = "x86_64", target_feature = "sse")))]
#[expect(non_camel_case_types, reason = "matching wasm conventions")]
#[derive(Copy, Clone)]
pub(crate) struct f64x2(core::convert::Infallible);
use crate::StoreContextMut;
use crate::prelude::*;
use crate::store::{StoreInner, StoreOpaque, StoreResourceLimiter};
use crate::type_registry::RegisteredType;
use alloc::sync::Arc;
use core::fmt;
use core::ops::{Deref, DerefMut};
use core::pin::pin;
use core::ptr::NonNull;
use core::sync::atomic::{AtomicUsize, Ordering};
use core::task::{Context, Poll, Waker};
use wasmtime_environ::error::OutOfMemory;
use wasmtime_environ::{DefinedMemoryIndex, HostPtr, VMOffsets, VMSharedTypeIndex};
#[cfg(feature = "gc")]
use wasmtime_environ::ModuleInternedTypeIndex;
mod always_mut;
#[cfg(feature = "component-model")]
pub mod component;
mod const_expr;
mod export;
mod gc;
mod imports;
mod instance;
mod memory;
mod mmap_vec;
#[cfg(has_virtual_memory)]
mod pagemap_disabled;
mod provenance;
mod send_sync_ptr;
mod stack_switching;
mod store_box;
mod sys;
mod table;
#[cfg(feature = "gc")]
mod throw;
mod traphandlers;
mod vmcontext;
#[cfg(feature = "threads")]
mod parking_spot;
#[cfg(all(has_host_compiler_backend, feature = "debug-builtins"))]
pub mod debug_builtins;
pub mod libcalls;
pub mod mpk;
#[cfg(feature = "pulley")]
pub(crate) mod interpreter;
#[cfg(not(feature = "pulley"))]
pub(crate) mod interpreter_disabled;
#[cfg(not(feature = "pulley"))]
pub(crate) use interpreter_disabled as interpreter;
#[cfg(feature = "debug-builtins")]
pub use wasmtime_jit_debug::gdb_jit_int::GdbJitImageRegistration;
pub use crate::runtime::vm::always_mut::*;
pub use crate::runtime::vm::export::*;
pub use crate::runtime::vm::gc::*;
pub use crate::runtime::vm::imports::Imports;
pub use crate::runtime::vm::instance::{
GcHeapAllocationIndex, Instance, InstanceAllocationRequest, InstanceAllocator, InstanceHandle,
MemoryAllocationIndex, OnDemandInstanceAllocator, TableAllocationIndex, initialize_instance,
};
#[cfg(feature = "pooling-allocator")]
pub use crate::runtime::vm::instance::{
InstanceLimits, PoolConcurrencyLimitError, PoolingAllocatorMetrics, PoolingInstanceAllocator,
PoolingInstanceAllocatorConfig,
};
pub use crate::runtime::vm::interpreter::*;
pub use crate::runtime::vm::memory::{
Memory, MemoryBase, RuntimeLinearMemory, RuntimeMemoryCreator, SharedMemory,
};
pub use crate::runtime::vm::mmap_vec::MmapVec;
pub use crate::runtime::vm::provenance::*;
pub use crate::runtime::vm::stack_switching::*;
pub use crate::runtime::vm::store_box::*;
#[cfg(feature = "std")]
pub use crate::runtime::vm::sys::mmap::open_file_for_mmap;
#[cfg(has_host_compiler_backend)]
pub use crate::runtime::vm::sys::unwind::UnwindRegistration;
pub use crate::runtime::vm::table::{Table, TableElementType};
#[cfg(feature = "gc")]
pub use crate::runtime::vm::throw::*;
pub use crate::runtime::vm::traphandlers::*;
#[cfg(feature = "component-model")]
pub use crate::runtime::vm::vmcontext::VMArrayCallFunction;
pub use crate::runtime::vm::vmcontext::{
VMArrayCallHostFuncContext, VMContext, VMFuncRef, VMFunctionImport, VMGlobalDefinition,
VMGlobalImport, VMGlobalKind, VMMemoryDefinition, VMMemoryImport, VMOpaqueContext,
VMStoreContext, VMTableImport, VMTagImport, VMWasmCallFunction, ValRaw,
};
#[cfg(has_custom_sync)]
pub(crate) use sys::capi;
pub use send_sync_ptr::SendSyncPtr;
pub use wasmtime_unwinder::Unwind;
#[cfg(has_host_compiler_backend)]
pub use wasmtime_unwinder::{UnwindHost, get_stack_pointer};
mod module_id;
pub use module_id::CompiledModuleId;
#[cfg(has_virtual_memory)]
mod byte_count;
#[cfg(has_virtual_memory)]
mod cow;
#[cfg(not(has_virtual_memory))]
mod cow_disabled;
#[cfg(has_virtual_memory)]
mod mmap;
#[cfg(any(feature = "async", feature = "gc"))]
mod async_yield;
#[cfg(any(feature = "async", feature = "gc"))]
pub use crate::runtime::vm::async_yield::*;
#[cfg(feature = "gc-null")]
mod send_sync_unsafe_cell;
#[cfg(feature = "gc-null")]
pub use send_sync_unsafe_cell::SendSyncUnsafeCell;
cfg_if::cfg_if! {
if #[cfg(has_virtual_memory)] {
pub use crate::runtime::vm::byte_count::*;
pub use crate::runtime::vm::mmap::{Mmap, MmapOffset};
pub use self::cow::{MemoryImage, MemoryImageSlot, ModuleMemoryImages};
} else {
pub use self::cow_disabled::{MemoryImage, MemoryImageSlot, ModuleMemoryImages};
}
}
pub trait ModuleMemoryImageSource: Send + Sync + 'static {
fn wasm_data(&self) -> &[u8];
fn mmap(&self) -> Option<&MmapVec>;
}
pub unsafe trait VMStore: 'static {
fn store_opaque(&self) -> &StoreOpaque;
fn store_opaque_mut(&mut self) -> &mut StoreOpaque;
fn resource_limiter_and_store_opaque(
&mut self,
) -> (Option<StoreResourceLimiter<'_>>, &mut StoreOpaque);
#[cfg(target_has_atomic = "64")]
fn new_epoch_updated_deadline(&mut self) -> Result<crate::UpdateDeadline>;
#[cfg(feature = "component-model")]
fn component_calls(&mut self) -> &mut component::CallContexts;
#[cfg(feature = "component-model-async")]
fn component_async_store(
&mut self,
) -> &mut dyn crate::runtime::component::VMComponentAsyncStore;
#[cfg(feature = "debug")]
fn block_on_debug_handler(&mut self, event: crate::DebugEvent) -> crate::Result<()>;
}
impl Deref for dyn VMStore + '_ {
type Target = StoreOpaque;
fn deref(&self) -> &Self::Target {
self.store_opaque()
}
}
impl DerefMut for dyn VMStore + '_ {
fn deref_mut(&mut self) -> &mut Self::Target {
self.store_opaque_mut()
}
}
impl dyn VMStore + '_ {
pub(crate) unsafe fn unchecked_context_mut<T>(&mut self) -> StoreContextMut<'_, T> {
unsafe { StoreContextMut(&mut *(self as *mut dyn VMStore as *mut StoreInner<T>)) }
}
}
#[derive(Copy, Clone)]
#[repr(transparent)]
struct VMStoreRawPtr(pub NonNull<dyn VMStore>);
unsafe impl Send for VMStoreRawPtr {}
unsafe impl Sync for VMStoreRawPtr {}
#[derive(Clone)]
pub enum ModuleRuntimeInfo {
Module(crate::Module),
Bare(Arc<BareModuleInfo>),
}
#[derive(Clone)]
pub struct BareModuleInfo {
module: Arc<wasmtime_environ::Module>,
offsets: VMOffsets<HostPtr>,
_registered_type: Option<RegisteredType>,
}
impl ModuleRuntimeInfo {
pub(crate) fn bare(module: Arc<wasmtime_environ::Module>) -> Result<Self, OutOfMemory> {
ModuleRuntimeInfo::bare_with_registered_type(module, None)
}
pub(crate) fn bare_with_registered_type(
module: Arc<wasmtime_environ::Module>,
registered_type: Option<RegisteredType>,
) -> Result<Self, OutOfMemory> {
let info = try_new(BareModuleInfo {
offsets: VMOffsets::new(HostPtr, &module),
module,
_registered_type: registered_type,
})?;
Ok(ModuleRuntimeInfo::Bare(info))
}
pub(crate) fn env_module(&self) -> &Arc<wasmtime_environ::Module> {
match self {
ModuleRuntimeInfo::Module(m) => m.env_module(),
ModuleRuntimeInfo::Bare(b) => &b.module,
}
}
#[cfg(feature = "gc")]
fn engine_type_index(&self, module_index: ModuleInternedTypeIndex) -> VMSharedTypeIndex {
match self {
ModuleRuntimeInfo::Module(m) => m
.engine_code()
.signatures()
.shared_type(module_index)
.expect("bad module-level interned type index"),
ModuleRuntimeInfo::Bare(_) => unreachable!(),
}
}
fn memory_image(&self, memory: DefinedMemoryIndex) -> crate::Result<Option<&Arc<MemoryImage>>> {
match self {
ModuleRuntimeInfo::Module(m) => {
let images = m.memory_images()?;
Ok(images.and_then(|images| images.get_memory_image(memory)))
}
ModuleRuntimeInfo::Bare(_) => Ok(None),
}
}
#[cfg(feature = "pooling-allocator")]
fn unique_id(&self) -> Option<CompiledModuleId> {
match self {
ModuleRuntimeInfo::Module(m) => Some(m.id()),
ModuleRuntimeInfo::Bare(_) => None,
}
}
fn wasm_data(&self) -> &[u8] {
match self {
ModuleRuntimeInfo::Module(m) => m.engine_code().wasm_data(),
ModuleRuntimeInfo::Bare(_) => &[],
}
}
fn type_ids(&self) -> &[VMSharedTypeIndex] {
match self {
ModuleRuntimeInfo::Module(m) => m
.engine_code()
.signatures()
.as_module_map()
.values()
.as_slice(),
ModuleRuntimeInfo::Bare(_) => &[],
}
}
pub(crate) fn offsets(&self) -> &VMOffsets<HostPtr> {
match self {
ModuleRuntimeInfo::Module(m) => m.offsets(),
ModuleRuntimeInfo::Bare(b) => &b.offsets,
}
}
}
#[cfg(has_virtual_memory)]
pub fn host_page_size() -> usize {
static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0);
return match PAGE_SIZE.load(Ordering::Relaxed) {
0 => {
let size = sys::vm::get_page_size();
assert!(size != 0);
PAGE_SIZE.store(size, Ordering::Relaxed);
size
}
n => n,
};
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum WaitResult {
Ok = 0,
Mismatch = 1,
TimedOut = 2,
}
#[derive(Debug)]
pub struct WasmFault {
pub memory_size: usize,
pub wasm_address: u64,
}
impl fmt::Display for WasmFault {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"memory fault at wasm address 0x{:x} in linear memory of size 0x{:x}",
self.wasm_address, self.memory_size,
)
}
}
pub fn assert_ready<F: Future>(f: F) -> F::Output {
one_poll(f).unwrap()
}
fn one_poll<F: Future>(f: F) -> Option<F::Output> {
let mut context = Context::from_waker(&Waker::noop());
match pin!(f).poll(&mut context) {
Poll::Ready(output) => Some(output),
Poll::Pending => None,
}
}