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 /// Installs this store's context for the duration of a coroutine resume.
125 /// The guard removes the context when dropped; hold it for exactly the
126 /// duration of the resume() call.
127 ///
128 /// # Panics
129 /// Panics if the store is anywhere on the current thread's context stack
130 /// (active or suspended).
131 ///
132 /// # Safety
133 /// Exactly one `StorePtrWrapper` derived from this store must be alive on
134 /// the suspended coroutine's stack for the duration of the guard.
135 #[cfg(feature = "unsafe-cothread")]
136 pub unsafe fn coroutine_store_guard(&mut self) -> CoroutineStoreGuard<'_> {
137 unsafe { CoroutineStoreGuard::new(self.inner.as_mut()) }
138 }
139
140 /// Builds an [`Interrupter`] for this store. Calling [`Interrupter::interrupt`]
141 /// will cause running WASM code to terminate immediately with a
142 /// [`HostInterrupt`](crate::backend::sys::vm::TrapCode::HostInterrupt) trap.
143 ///
144 /// Best effort is made to ensure interrupts are handled. However, there is no
145 /// guarantee; under rare circumstances, it is possible for the interrupt to be
146 /// missed. One such case is when the target thread is about to call WASM code
147 /// but has not yet made the call.
148 ///
149 /// To make sure the code is interrupted, the target thread should notify
150 /// the signalling thread that it has finished running in some way, and
151 /// the signalling thread must wait for that notification and retry the
152 /// interrupt if the notification is not received after some time. Embedders
153 /// are expected to implement this logic.
154 ///
155 /// If an interrupt is delivered while an imported function is running,
156 /// the interrupt will simply be stored and processed only when the
157 /// imported function returns control to WASM code. No effort is made
158 /// to interrupt running imported functions. Embedders are expected to
159 /// implement support for interruption of long-running or blocking
160 /// imported functions separately.
161 #[cfg(all(unix, feature = "experimental-host-interrupt"))]
162 pub fn interrupter(&self) -> Interrupter {
163 self.inner.objects.interrupter()
164 }
165
166 #[cfg(feature = "experimental-async")]
167 /// Transforms this store into a [`StoreAsync`] which can be used
168 /// to invoke [`Function::call_async`](crate::Function::call_async).
169 pub fn into_async(self) -> StoreAsync {
170 StoreAsync {
171 id: self.id(),
172 inner: LocalRwLock::new(self.inner),
173 }
174 }
175}
176
177impl PartialEq for Store {
178 fn eq(&self, other: &Self) -> bool {
179 Self::same(self, other)
180 }
181}
182
183impl Default for Store {
184 fn default() -> Self {
185 Self::new(Engine::default())
186 }
187}
188
189impl std::fmt::Debug for Store {
190 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
191 f.debug_struct("Store").finish()
192 }
193}
194
195impl AsEngineRef for Store {
196 fn as_engine_ref(&self) -> EngineRef<'_> {
197 self.inner.store.as_engine_ref()
198 }
199
200 fn maybe_as_store(&self) -> Option<StoreRef<'_>> {
201 Some(self.as_store_ref())
202 }
203}
204
205impl AsStoreRef for Store {
206 fn as_store_ref(&self) -> StoreRef<'_> {
207 StoreRef { inner: &self.inner }
208 }
209}
210impl AsStoreMut for Store {
211 fn as_store_mut(&mut self) -> StoreMut<'_> {
212 StoreMut {
213 inner: &mut self.inner,
214 }
215 }
216
217 fn objects_mut(&mut self) -> &mut StoreObjects {
218 &mut self.inner.objects
219 }
220}