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