wasmtime/runtime/
vm.rs

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