Skip to main content

wasmer/entities/store/
store_ref.rs

1use std::ops::{Deref, DerefMut};
2
3use super::{StoreObjects, inner::StoreInner};
4use crate::entities::engine::{AsEngineRef, Engine, EngineRef};
5#[cfg(feature = "experimental-async")]
6use crate::{AsStoreAsync, StoreAsync};
7use wasmer_types::{ExternType, OnCalledAction};
8//use wasmer_vm::{StoreObjects, TrapHandlerFn};
9
10#[cfg(feature = "sys")]
11use wasmer_vm::TrapHandlerFn;
12
13/// A temporary handle to a [`crate::Store`].
14#[derive(Debug)]
15pub struct StoreRef<'a> {
16    pub(crate) inner: &'a StoreInner,
17}
18
19impl<'a> StoreRef<'a> {
20    pub(crate) fn objects(&self) -> &'a StoreObjects {
21        &self.inner.objects
22    }
23
24    /// Returns the [`Engine`].
25    pub fn engine(&self) -> &Engine {
26        self.inner.store.engine()
27    }
28
29    /// Checks whether two stores are identical. A store is considered
30    /// equal to another store if both have the same engine.
31    pub fn same(a: &Self, b: &Self) -> bool {
32        StoreObjects::same(&a.inner.objects, &b.inner.objects)
33    }
34
35    /// The signal handler
36    #[cfg(feature = "sys")]
37    #[inline]
38    pub fn signal_handler(&self) -> Option<*const TrapHandlerFn<'static>> {
39        use crate::backend::sys::entities::store::NativeStoreExt;
40        self.inner.store.as_sys().signal_handler()
41    }
42}
43
44/// A temporary handle to a [`crate::Store`].
45pub struct StoreMut<'a> {
46    pub(crate) inner: &'a mut StoreInner,
47}
48
49impl StoreMut<'_> {
50    /// Returns the [`Engine`].
51    pub fn engine(&self) -> &Engine {
52        self.inner.store.engine()
53    }
54
55    /// Checks whether two stores are identical. A store is considered
56    /// equal to another store if both have the same engine.
57    pub fn same(a: &Self, b: &Self) -> bool {
58        StoreObjects::same(&a.inner.objects, &b.inner.objects)
59    }
60
61    #[allow(unused)]
62    pub(crate) fn as_raw(&self) -> *mut StoreInner {
63        self.inner as *const StoreInner as *mut StoreInner
64    }
65
66    #[allow(unused)]
67    pub(crate) unsafe fn from_raw(raw: *mut StoreInner) -> Self {
68        Self {
69            inner: unsafe { &mut *raw },
70        }
71    }
72
73    #[allow(unused)]
74    pub(crate) fn engine_and_objects_mut(&mut self) -> (&Engine, &mut StoreObjects) {
75        (self.inner.store.engine(), &mut self.inner.objects)
76    }
77
78    /// Parks this borrow of the store for the duration of `f`, lending the
79    /// store to code that runs inside `f` without reaching it through Rust:
80    /// [`Store::with_current`](crate::Store::with_current) hands the store back to any frame `f` reaches,
81    /// however many foreign frames deep.
82    ///
83    /// This is how host code lends the store across an FFI boundary. An
84    /// embedded engine that calls back into the host — a JS engine's allocator
85    /// hook, say — cannot be handed a Rust reference through its own C frames,
86    /// and cannot be given one out of band either, because the imported
87    /// function it was called from is still holding the only borrow. Parking
88    /// that borrow, which the `&mut self` receiver here makes unreachable for
89    /// exactly as long as `f` runs, is what makes lending it sound rather than
90    /// aliasing.
91    ///
92    /// Parks nest, and a store nobody parked stays unlendable:
93    /// [`Store::with_current`](crate::Store::with_current) returns `None`
94    /// unless every borrow on this thread's stack has been parked this way.
95    ///
96    /// ```
97    /// use wasmer::{AsStoreMut, FunctionEnvMut, Store};
98    ///
99    /// // A host function lending its store to code it calls into.
100    /// fn host_call(mut env: FunctionEnvMut<'_, ()>) {
101    ///     // `env` holds the store, so nobody else may have it.
102    ///     assert!(Store::with_current(|_| ()).is_none());
103    ///
104    ///     env.as_store_mut().parked(|| {
105    ///         // ...but code reached from here can pick it back up.
106    ///         assert!(Store::with_current(|_| ()).is_some());
107    ///     });
108    /// }
109    /// ```
110    pub fn parked<R>(&mut self, f: impl FnOnce() -> R) -> R {
111        // This is the same thing `Function::call` does before entering Wasm:
112        // install this borrow as the store executing on the thread, so that
113        // code which reaches the store through the context — rather than
114        // through a reference it was handed — picks up a borrow derived from
115        // *this* one. The new entry starts unborrowed, which is what makes the
116        // store lendable for as long as it is on top.
117        let ptr: *mut StoreInner = &mut *self.inner;
118        // SAFETY: `ptr` comes from `&mut *self.inner`, which `&mut self` keeps
119        // alive and unreachable for every frame on this thread until `f`
120        // returns and the guard is dropped.
121        let _guard = unsafe { super::StoreContext::install(ptr) };
122        f()
123    }
124
125    // TODO: OnCalledAction is needed for asyncify. It will be refactored with https://github.com/wasmerio/wasmer/issues/3451
126    /// Sets the unwind callback which will be invoked when the call finishes
127    pub fn on_called<F>(&mut self, callback: F)
128    where
129        F: FnOnce(StoreMut<'_>) -> Result<OnCalledAction, Box<dyn std::error::Error + Send + Sync>>
130            + Send
131            + Sync
132            + 'static,
133    {
134        self.inner.on_called.replace(Box::new(callback));
135    }
136}
137
138/// Helper trait for a value that is convertible to a [`StoreRef`].
139pub trait AsStoreRef {
140    /// Returns a `StoreRef` pointing to the underlying context.
141    fn as_store_ref(&self) -> StoreRef<'_>;
142
143    /// Returns a [`StoreAsync`] if the current
144    /// context is asynchronous. The store will be locked since
145    /// it's already active in the current context, but can be used
146    /// to spawn new coroutines via
147    /// [`Function::call_async`](crate::Function::call_async).
148    #[cfg(feature = "experimental-async")]
149    fn as_store_async(&self) -> Option<impl AsStoreAsync + 'static> {
150        let id = self.as_store_ref().inner.objects.id();
151        StoreAsync::from_context(id)
152    }
153}
154
155/// Helper trait for a value that is convertible to a [`StoreMut`].
156pub trait AsStoreMut: AsStoreRef {
157    /// Returns a `StoreMut` pointing to the underlying context.
158    fn as_store_mut(&mut self) -> StoreMut<'_>;
159
160    /// Returns the ObjectMutable
161    fn objects_mut(&mut self) -> &mut StoreObjects;
162}
163
164impl AsStoreRef for StoreRef<'_> {
165    fn as_store_ref(&self) -> StoreRef<'_> {
166        StoreRef { inner: self.inner }
167    }
168}
169
170impl AsEngineRef for StoreRef<'_> {
171    fn as_engine_ref(&self) -> EngineRef<'_> {
172        self.inner.store.as_engine_ref()
173    }
174}
175
176impl AsStoreRef for StoreMut<'_> {
177    fn as_store_ref(&self) -> StoreRef<'_> {
178        StoreRef { inner: self.inner }
179    }
180}
181impl AsStoreMut for StoreMut<'_> {
182    fn as_store_mut(&mut self) -> StoreMut<'_> {
183        StoreMut { inner: self.inner }
184    }
185
186    fn objects_mut(&mut self) -> &mut StoreObjects {
187        &mut self.inner.objects
188    }
189}
190
191impl<P> AsStoreRef for P
192where
193    P: Deref,
194    P::Target: AsStoreRef,
195{
196    fn as_store_ref(&self) -> StoreRef<'_> {
197        (**self).as_store_ref()
198    }
199}
200
201impl<P> AsStoreMut for P
202where
203    P: DerefMut,
204    P::Target: AsStoreMut,
205{
206    fn as_store_mut(&mut self) -> StoreMut<'_> {
207        (**self).as_store_mut()
208    }
209
210    fn objects_mut(&mut self) -> &mut StoreObjects {
211        (**self).objects_mut()
212    }
213}
214
215impl AsEngineRef for StoreMut<'_> {
216    fn as_engine_ref(&self) -> EngineRef<'_> {
217        self.inner.store.as_engine_ref()
218    }
219}