Skip to main content

wasmtime/
runtime.rs

1// Wasmtime's runtime has lots of fiddly bits where we're doing operations like
2// casting between wasm i32/i64 and host `usize` values. There's also in general
3// just lots of pieces of low-level manipulation of memory and internals of VM
4// runtime state. To help keep all the integer casts correct be a bit more
5// strict than the default settings to help weed out bugs ahead of time.
6//
7// This inevitably leads to wordier code than might otherwise be used because,
8// for example, `u64 as usize` is warned against and will be an error on CI.
9// This happens pretty frequently and needs to be replaced with `val.try_into()`
10// or `usize::try_from(val)` where the error is handled. In some cases the
11// correct thing to do is to `.unwrap()` the error to indicate a fatal mistake,
12// but in some cases the correct thing is to propagate the error.
13//
14// Some niche cases that explicitly want truncation are recommended to have a
15// function along the lines of
16//
17//     #[allow(clippy::cast_possible_truncation)]
18//     fn truncate_i32_to_i8(a: i32) -> i8 { a as i8 }
19//
20// as this explicitly indicates the intent of truncation is desired. Other
21// locations should use fallible conversions.
22//
23// If performance is absolutely critical then it's recommended to use `#[allow]`
24// with a comment indicating why performance is critical as well as a short
25// explanation of why truncation shouldn't be happening at runtime. This
26// situation should be pretty rare though.
27#![warn(clippy::cast_possible_truncation)]
28
29use crate::prelude::*;
30use core::marker;
31use core::pin::Pin;
32use core::task::{Context, Poll};
33
34mod bug;
35
36#[macro_use]
37pub(crate) mod func;
38
39pub(crate) mod code;
40pub(crate) mod code_memory;
41#[cfg(feature = "debug")]
42pub(crate) mod debug;
43pub(crate) mod exception;
44pub(crate) mod externals;
45#[cfg(feature = "async")]
46pub(crate) mod fiber;
47pub(crate) mod gc;
48pub(crate) mod instance;
49pub(crate) mod instantiate;
50pub(crate) mod limits;
51pub(crate) mod linker;
52pub(crate) mod memory;
53pub(crate) mod module;
54#[cfg(feature = "debug-builtins")]
55pub(crate) mod native_debug;
56pub(crate) mod resources;
57pub(crate) mod store;
58pub(crate) mod trampoline;
59pub(crate) mod trap;
60#[cfg(feature = "component-model-async")]
61pub(crate) mod try_mutex;
62pub(crate) mod type_registry;
63pub(crate) mod types;
64pub(crate) mod v128;
65pub(crate) mod values;
66pub(crate) mod vm;
67
68#[cfg(feature = "component-model")]
69pub mod component;
70
71cfg_select! {
72    miri => {
73        // no extensions on miri
74    }
75    not(feature = "std") => {
76        // no extensions on no-std
77    }
78    unix => {
79        pub mod unix;
80    }
81    windows => {
82        pub mod windows;
83    }
84    _ => {
85        // ... unknown os!
86    }
87}
88
89pub use bug::WasmtimeBug;
90pub(crate) use bug::{bail_bug, bug};
91pub use code_memory::CodeMemory;
92#[cfg(feature = "debug")]
93pub use debug::*;
94pub use exception::*;
95pub use externals::*;
96pub use func::*;
97pub use gc::*;
98pub use instance::{Instance, InstancePre};
99pub use instantiate::CompiledModule;
100pub use limits::*;
101pub use linker::*;
102pub use memory::*;
103pub use module::{Module, ModuleExport, ModuleFunction};
104pub use resources::*;
105#[cfg(all(feature = "async", feature = "call-hook"))]
106pub use store::CallHookHandler;
107pub use store::{
108    AsContext, AsContextMut, CallHook, Store, StoreContext, StoreContextMut, UpdateDeadline,
109};
110pub use trap::*;
111pub use types::*;
112pub use v128::V128;
113pub use values::*;
114
115#[cfg(feature = "pooling-allocator")]
116pub use vm::{PoolConcurrencyLimitError, PoolingAllocatorMetrics};
117
118#[cfg(feature = "profiling")]
119mod profiling;
120#[cfg(feature = "profiling")]
121pub use profiling::GuestProfiler;
122
123#[cfg(feature = "async")]
124pub(crate) mod stack;
125#[cfg(feature = "async")]
126pub use stack::*;
127
128#[cfg(feature = "coredump")]
129mod coredump;
130#[cfg(feature = "coredump")]
131pub use coredump::*;
132
133#[cfg(feature = "wave")]
134mod wave;
135
136/// Helper method to create a future trait object from the future `F` provided.
137///
138/// This requires that the output of `F` is a result where the error can be
139/// created from `OutOfMemory`. This will handle OOM when allocation of `F` on
140/// the heap fails.
141fn box_future<'a, F, T, E>(future: F) -> Pin<Box<dyn Future<Output = Result<T, E>> + Send + 'a>>
142where
143    F: Future<Output = Result<T, E>> + Send + 'a,
144    T: 'a,
145    E: From<OutOfMemory> + 'a,
146{
147    if let Ok(future) = try_new::<Box<F>>(future) {
148        return Pin::from(future);
149    }
150
151    // Use a custom guaranteed-zero-size struct to implement a future that
152    // returns an OOM error which satisfies the type signature of this function.
153    struct OomFuture<F, T, E>(marker::PhantomData<fn() -> (T, F, E)>);
154
155    impl<F, T, E> Future for OomFuture<F, T, E>
156    where
157        E: From<OutOfMemory>,
158    {
159        type Output = Result<T, E>;
160
161        fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
162            Poll::Ready(Err(OutOfMemory::new(size_of::<F>()).into()))
163        }
164    }
165
166    // Zero-size allocations don't actually allocate memory with a `Box`, so
167    // it's ok to use the standard `Box::pin` here and not worry about OOM.
168    let future = OomFuture::<F, T, E>(marker::PhantomData);
169    assert_eq!(size_of_val(&future), 0);
170    Box::pin(future)
171}
172
173fn _assertions_runtime() {
174    use crate::_assert_send_and_sync;
175
176    #[cfg(feature = "async")]
177    fn _assert_send<T: Send>(_t: T) {}
178
179    _assert_send_and_sync::<Caller<'_, ()>>();
180    _assert_send_and_sync::<ExternRef>();
181    _assert_send_and_sync::<(Func, TypedFunc<(), ()>, Global, Table, Memory)>();
182    _assert_send_and_sync::<Instance>();
183    _assert_send_and_sync::<InstancePre<()>>();
184    _assert_send_and_sync::<InstancePre<*mut u8>>();
185    _assert_send_and_sync::<Linker<()>>();
186    _assert_send_and_sync::<Linker<*mut u8>>();
187    _assert_send_and_sync::<Module>();
188    _assert_send_and_sync::<Store<()>>();
189    _assert_send_and_sync::<StoreContext<'_, ()>>();
190    _assert_send_and_sync::<StoreContextMut<'_, ()>>();
191
192    #[cfg(feature = "async")]
193    fn _call_async(s: &mut Store<()>, f: Func) {
194        _assert_send(f.call_async(&mut *s, &[], &mut []))
195    }
196    #[cfg(feature = "async")]
197    fn _typed_call_async(s: &mut Store<()>, f: TypedFunc<(), ()>) {
198        _assert_send(f.call_async(&mut *s, ()))
199    }
200    #[cfg(feature = "async")]
201    fn _instantiate_async(s: &mut Store<()>, m: &Module) {
202        _assert_send(Instance::new_async(s, m, &[]))
203    }
204}