Skip to main content

wasmer/entities/store/
mod.rs

1//! Defines the [`Store`] data type and various useful traits and data types to interact with a
2//! store.
3
4/// Defines the [`AsStoreAsync`] trait and its supporting types.
5#[cfg(feature = "experimental-async")]
6mod async_;
7#[cfg(feature = "experimental-async")]
8pub use async_::*;
9
10/// Defines the [`StoreContext`] type.
11mod context;
12
13/// Defines the [`StoreInner`] data type.
14mod inner;
15
16/// Create temporary handles to engines.
17mod store_ref;
18
19/// Single-threaded async-aware RwLock.
20#[cfg(feature = "experimental-async")]
21mod local_rwlock;
22#[cfg(feature = "experimental-async")]
23pub(crate) use local_rwlock::*;
24
25use std::{
26    boxed::Box,
27    ops::{Deref, DerefMut},
28};
29
30pub use store_ref::*;
31
32mod obj;
33pub use obj::*;
34
35use crate::{AsEngineRef, BackendEngine, Engine, EngineRef};
36#[cfg(feature = "unsafe-cothread")]
37pub use context::CoroutineStoreGuard;
38pub(crate) use context::*;
39pub(crate) use inner::*;
40use wasmer_types::StoreId;
41
42#[cfg(feature = "sys")]
43use wasmer_vm::TrapHandlerFn;
44
45/// The store represents all global state that can be manipulated by
46/// WebAssembly programs. It consists of the runtime representation
47/// of all instances of functions, tables, memories, and globals that
48/// have been allocated during the lifetime of the abstract machine.
49///
50/// The [`Store`] is tied to the underlying [`Engine`] that is — among many things — used to
51/// compile the Wasm bytes into a valid module artifact.
52///
53/// For more information, check out the [related WebAssembly specification]
54/// [related WebAssembly specification]: <https://webassembly.github.io/spec/core/exec/runtime.html#store>
55pub struct Store {
56    pub(crate) inner: Box<StoreInner>,
57}
58
59impl Store {
60    /// Creates a new `Store` with a specific [`Engine`].
61    pub fn new(engine: impl Into<Engine>) -> Self {
62        let engine: Engine = engine.into();
63
64        let store = match engine.be {
65            #[cfg(feature = "sys")]
66            BackendEngine::Sys(_) => {
67                BackendStore::Sys(crate::backend::sys::entities::store::Store::new(engine))
68            }
69            #[cfg(feature = "v8")]
70            BackendEngine::V8(_) => {
71                BackendStore::V8(crate::backend::v8::entities::store::Store::new(engine))
72            }
73            #[cfg(feature = "js")]
74            BackendEngine::Js(_) => {
75                BackendStore::Js(crate::backend::js::entities::store::Store::new(engine))
76            }
77        };
78
79        Self {
80            inner: Box::new(StoreInner {
81                objects: StoreObjects::from_store_ref(&store),
82                on_called: None,
83                store,
84            }),
85        }
86    }
87
88    #[cfg(feature = "sys")]
89    /// Set the [`TrapHandlerFn`] for this store.
90    ///
91    /// # Note
92    ///
93    /// Not every implementor allows changing the trap handler. In those store that
94    /// don't allow it, this function has no effect.
95    pub fn set_trap_handler(&mut self, handler: Option<Box<TrapHandlerFn<'static>>>) {
96        use crate::backend::sys::entities::store::NativeStoreExt;
97        #[allow(irrefutable_let_patterns)]
98        if let BackendStore::Sys(ref mut s) = self.inner.store {
99            s.set_trap_handler(handler)
100        }
101    }
102
103    /// Returns the [`Engine`].
104    pub fn engine(&self) -> &Engine {
105        self.inner.store.engine()
106    }
107
108    /// Returns mutable reference to [`Engine`].
109    pub fn engine_mut(&mut self) -> &mut Engine {
110        self.inner.store.engine_mut()
111    }
112
113    /// Checks whether two stores are identical. A store is considered
114    /// equal to another store if both have the same engine.
115    pub fn same(a: &Self, b: &Self) -> bool {
116        a.id() == b.id()
117    }
118
119    /// Returns the ID of this store
120    pub fn id(&self) -> StoreId {
121        self.inner.objects.id()
122    }
123
124    /// Runs `f` with the store this thread is currently executing, if that
125    /// store has been lent out with [`StoreMut::parked`].
126    ///
127    /// Host code called from Wasm normally receives the store as a
128    /// [`FunctionEnvMut`](crate::FunctionEnvMut), but code the host in turn
129    /// calls into cannot always be handed one: an embedded engine invoking a
130    /// callback, a C library's allocator hook, anything reached through frames
131    /// that carry no Rust references. This is how such code gets the store the
132    /// current call is running under, so it can use the ordinary store-taking
133    /// APIs — [`Memory::grow`](crate::Memory::grow) and friends — instead of
134    /// reaching around them.
135    ///
136    /// Returns `None` unless a store is executing on this thread *and* every
137    /// borrow of it on this thread's stack has been parked. Holding a
138    /// [`StoreMut`] and calling this would alias that borrow, so the answer
139    /// there is `None` rather than a second handle to the same store; parking
140    /// is what makes the outstanding borrow provably unreachable.
141    ///
142    /// A store starts executing when a call enters it, which only the `sys`
143    /// backend tracks — so on the others this is `None` inside a host function.
144    /// [`StoreMut::parked`] works everywhere, though, so an embedder can always
145    /// lend a store it owns, whether or not a call is running.
146    ///
147    /// Nothing guarantees the store is the one the caller expects — a thread
148    /// may run several — so check any handle before using it, with
149    /// [`Memory::is_from_store`](crate::Memory::is_from_store) or by comparing
150    /// [`StoreObjects::id`]. Using a handle from another store panics.
151    pub fn with_current<R>(f: impl FnOnce(&mut StoreMut<'_>) -> R) -> Option<R> {
152        let mut store = StoreContext::try_get_current_unborrowed()?;
153        Some(f(&mut store.as_mut()))
154    }
155
156    /// Installs this store's context for the duration of a coroutine resume.
157    /// The guard removes the context when dropped; hold it for exactly the
158    /// duration of the resume() call.
159    ///
160    /// # Panics
161    /// Panics if the store is anywhere on the current thread's context stack
162    /// (active or suspended).
163    ///
164    /// # Safety
165    /// Exactly one `StorePtrWrapper` derived from this store must be alive on
166    /// the suspended coroutine's stack for the duration of the guard.
167    #[cfg(feature = "unsafe-cothread")]
168    pub unsafe fn coroutine_store_guard(&mut self) -> CoroutineStoreGuard<'_> {
169        unsafe { CoroutineStoreGuard::new(self.inner.as_mut()) }
170    }
171
172    /// Builds an [`Interrupter`] for this store. Calling [`Interrupter::interrupt`]
173    /// will cause running WASM code to terminate immediately with a
174    /// [`HostInterrupt`](crate::backend::sys::vm::TrapCode::HostInterrupt) trap.
175    ///
176    /// Best effort is made to ensure interrupts are handled. However, there is no
177    /// guarantee; under rare circumstances, it is possible for the interrupt to be
178    /// missed. One such case is when the target thread is about to call WASM code
179    /// but has not yet made the call.
180    ///
181    /// To make sure the code is interrupted, the target thread should notify
182    /// the signalling thread that it has finished running in some way, and
183    /// the signalling thread must wait for that notification and retry the
184    /// interrupt if the notification is not received after some time. Embedders
185    /// are expected to implement this logic.
186    ///
187    /// If an interrupt is delivered while an imported function is running,
188    /// the interrupt will simply be stored and processed only when the
189    /// imported function returns control to WASM code. No effort is made
190    /// to interrupt running imported functions. Embedders are expected to
191    /// implement support for interruption of long-running or blocking
192    /// imported functions separately.
193    #[cfg(all(unix, feature = "experimental-host-interrupt"))]
194    pub fn interrupter(&self) -> Interrupter {
195        self.inner.objects.interrupter()
196    }
197
198    #[cfg(feature = "experimental-async")]
199    /// Transforms this store into a [`StoreAsync`] which can be used
200    /// to invoke [`Function::call_async`](crate::Function::call_async).
201    pub fn into_async(self) -> StoreAsync {
202        StoreAsync {
203            id: self.id(),
204            inner: LocalRwLock::new(self.inner),
205        }
206    }
207}
208
209impl PartialEq for Store {
210    fn eq(&self, other: &Self) -> bool {
211        Self::same(self, other)
212    }
213}
214
215impl Default for Store {
216    fn default() -> Self {
217        Self::new(Engine::default())
218    }
219}
220
221impl std::fmt::Debug for Store {
222    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
223        f.debug_struct("Store").finish()
224    }
225}
226
227impl AsEngineRef for Store {
228    fn as_engine_ref(&self) -> EngineRef<'_> {
229        self.inner.store.as_engine_ref()
230    }
231
232    fn maybe_as_store(&self) -> Option<StoreRef<'_>> {
233        Some(self.as_store_ref())
234    }
235}
236
237impl AsStoreRef for Store {
238    fn as_store_ref(&self) -> StoreRef<'_> {
239        StoreRef { inner: &self.inner }
240    }
241}
242impl AsStoreMut for Store {
243    fn as_store_mut(&mut self) -> StoreMut<'_> {
244        StoreMut {
245            inner: &mut self.inner,
246        }
247    }
248
249    fn objects_mut(&mut self) -> &mut StoreObjects {
250        &mut self.inner.objects
251    }
252}