wasmer_vm/
store.rs

1use crate::{
2    VMExceptionObj, VMExternObj, VMFunction, VMFunctionEnvironment, VMGlobal, VMInstance, VMMemory,
3    VMTable, VMTag,
4};
5use core::slice::Iter;
6use std::{cell::UnsafeCell, fmt, marker::PhantomData, num::NonZeroUsize, ptr::NonNull};
7use wasmer_types::StoreId;
8
9/// Trait to represent an object managed by a context. This is implemented on
10/// the VM types managed by the context.
11pub trait StoreObject: Sized {
12    /// List the objects in the store.
13    fn list(ctx: &StoreObjects) -> &Vec<Self>;
14
15    /// List the objects in the store, mutably.
16    fn list_mut(ctx: &mut StoreObjects) -> &mut Vec<Self>;
17}
18macro_rules! impl_context_object {
19    ($($field:ident => $ty:ty,)*) => {
20        $(
21            impl StoreObject for $ty {
22                fn list(ctx: &StoreObjects) -> &Vec<Self> {
23                    &ctx.$field
24                }
25                fn list_mut(ctx: &mut StoreObjects) -> &mut Vec<Self> {
26                    &mut ctx.$field
27                }
28            }
29        )*
30    };
31}
32impl_context_object! {
33    functions => VMFunction,
34    tables => VMTable,
35    globals => VMGlobal,
36    instances => VMInstance,
37    memories => VMMemory,
38    extern_objs => VMExternObj,
39    exceptions => VMExceptionObj,
40    tags => VMTag,
41    function_environments => VMFunctionEnvironment,
42}
43
44/// Set of objects managed by a context.
45#[derive(Debug, Default)]
46pub struct StoreObjects {
47    id: StoreId,
48    memories: Vec<VMMemory>,
49    tables: Vec<VMTable>,
50    globals: Vec<VMGlobal>,
51    functions: Vec<VMFunction>,
52    instances: Vec<VMInstance>,
53    extern_objs: Vec<VMExternObj>,
54    exceptions: Vec<VMExceptionObj>,
55    tags: Vec<VMTag>,
56    function_environments: Vec<VMFunctionEnvironment>,
57}
58
59impl StoreObjects {
60    /// Create a new instance of [`Self`]
61    #[allow(clippy::too_many_arguments)]
62    pub fn new(
63        id: StoreId,
64        memories: Vec<VMMemory>,
65        tables: Vec<VMTable>,
66        globals: Vec<VMGlobal>,
67        functions: Vec<VMFunction>,
68        instances: Vec<VMInstance>,
69        extern_objs: Vec<VMExternObj>,
70        exceptions: Vec<VMExceptionObj>,
71        tags: Vec<VMTag>,
72        function_environments: Vec<VMFunctionEnvironment>,
73    ) -> Self {
74        Self {
75            id,
76            memories,
77            tables,
78            globals,
79            functions,
80            instances,
81            extern_objs,
82            function_environments,
83            exceptions,
84            tags,
85        }
86    }
87
88    /// Returns the ID of this context.
89    pub fn id(&self) -> StoreId {
90        self.id
91    }
92
93    /// Sets the ID of this store
94    pub fn set_id(&mut self, id: StoreId) {
95        self.id = id;
96    }
97
98    /// Returns a pair of mutable references from two handles.
99    ///
100    /// Panics if both handles point to the same object.
101    pub fn get_2_mut<T: StoreObject>(
102        &mut self,
103        a: InternalStoreHandle<T>,
104        b: InternalStoreHandle<T>,
105    ) -> (&mut T, &mut T) {
106        assert_ne!(a.index(), b.index());
107        let list = T::list_mut(self);
108        if a.index() < b.index() {
109            let (low, high) = list.split_at_mut(b.index());
110            (&mut low[a.index()], &mut high[0])
111        } else {
112            let (low, high) = list.split_at_mut(a.index());
113            (&mut high[0], &mut low[a.index()])
114        }
115    }
116
117    /// Return an immutable iterator over all globals
118    pub fn iter_globals(&self) -> Iter<VMGlobal> {
119        self.globals.iter()
120    }
121
122    /// Return an vector of all globals and converted to u128
123    pub fn as_u128_globals(&self) -> Vec<u128> {
124        self.iter_globals()
125            .map(|v| unsafe { v.vmglobal().as_ref().val.u128 })
126            .collect()
127    }
128
129    /// Set a global, at index idx. Will panic if idx is out of range
130    /// Safety: the caller should check taht the raw value is compatible
131    /// with destination VMGlobal type
132    pub fn set_global_unchecked(&self, idx: usize, val: u128) {
133        assert!(idx < self.globals.len());
134        unsafe {
135            self.globals[idx].vmglobal().as_mut().val.u128 = val;
136        }
137    }
138}
139
140/// Handle to an object managed by a context.
141///
142/// Internally this is just an integer index into a context. A reference to the
143/// context must be passed in separately to access the actual object.
144#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
145pub struct StoreHandle<T> {
146    id: StoreId,
147    internal: InternalStoreHandle<T>,
148}
149
150impl<T> Clone for StoreHandle<T> {
151    fn clone(&self) -> Self {
152        Self {
153            id: self.id,
154            internal: self.internal,
155        }
156    }
157}
158
159impl<T> std::hash::Hash for StoreHandle<T> {
160    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
161        self.id.hash(state);
162        self.internal.idx.hash(state);
163    }
164}
165
166impl<T: StoreObject> fmt::Debug for StoreHandle<T> {
167    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168        f.debug_struct("StoreHandle")
169            .field("id", &self.id)
170            .field("internal", &self.internal.index())
171            .finish()
172    }
173}
174
175impl<T: StoreObject> PartialEq for StoreHandle<T> {
176    fn eq(&self, other: &Self) -> bool {
177        self.id == other.id && self.internal == other.internal
178    }
179}
180
181impl<T: StoreObject> Eq for StoreHandle<T> {}
182
183impl<T: StoreObject> StoreHandle<T> {
184    /// Moves the given object into a context and returns a handle to it.
185    pub fn new(ctx: &mut StoreObjects, val: T) -> Self {
186        Self {
187            id: ctx.id,
188            internal: InternalStoreHandle::new(ctx, val),
189        }
190    }
191
192    /// Returns a reference to the object that this handle points to.
193    pub fn get<'a>(&self, ctx: &'a StoreObjects) -> &'a T {
194        assert_eq!(self.id, ctx.id, "object used with the wrong context");
195        self.internal.get(ctx)
196    }
197
198    /// Returns a mutable reference to the object that this handle points to.
199    pub fn get_mut<'a>(&self, ctx: &'a mut StoreObjects) -> &'a mut T {
200        assert_eq!(self.id, ctx.id, "object used with the wrong context");
201        self.internal.get_mut(ctx)
202    }
203
204    /// Returns the internal handle contains within this handle.
205    pub fn internal_handle(&self) -> InternalStoreHandle<T> {
206        self.internal
207    }
208
209    /// Returns the ID of the context associated with the handle.
210    pub fn store_id(&self) -> StoreId {
211        self.id
212    }
213
214    /// Overrides the store id with a new ID
215    pub fn set_store_id(&mut self, id: StoreId) {
216        self.id = id;
217    }
218
219    /// Constructs a `StoreHandle` from a `StoreId` and an `InternalStoreHandle`.
220    ///
221    /// # Safety
222    /// Handling `InternalStoreHandle` values is unsafe because they do not track context ID.
223    pub unsafe fn from_internal(id: StoreId, internal: InternalStoreHandle<T>) -> Self {
224        Self { id, internal }
225    }
226}
227
228/// Internal handle to an object owned by the current context.
229///
230/// Unlike `StoreHandle` this does not track the context ID: it is only
231/// intended to be used within objects already owned by a context.
232#[repr(transparent)]
233pub struct InternalStoreHandle<T> {
234    // Use a NonZero here to reduce the size of Option<InternalStoreHandle>.
235    idx: NonZeroUsize,
236    marker: PhantomData<fn() -> T>,
237}
238
239#[cfg(feature = "artifact-size")]
240impl<T> loupe::MemoryUsage for InternalStoreHandle<T> {
241    fn size_of_val(&self, _tracker: &mut dyn loupe::MemoryUsageTracker) -> usize {
242        std::mem::size_of_val(&self)
243    }
244}
245
246impl<T> Clone for InternalStoreHandle<T> {
247    fn clone(&self) -> Self {
248        *self
249    }
250}
251impl<T> Copy for InternalStoreHandle<T> {}
252
253impl<T> fmt::Debug for InternalStoreHandle<T> {
254    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255        f.debug_struct("InternalStoreHandle")
256            .field("idx", &self.idx)
257            .finish()
258    }
259}
260impl<T> PartialEq for InternalStoreHandle<T> {
261    fn eq(&self, other: &Self) -> bool {
262        self.idx == other.idx
263    }
264}
265impl<T> Eq for InternalStoreHandle<T> {}
266
267impl<T: StoreObject> InternalStoreHandle<T> {
268    /// Moves the given object into a context and returns a handle to it.
269    pub fn new(ctx: &mut StoreObjects, val: T) -> Self {
270        let list = T::list_mut(ctx);
271        let idx = NonZeroUsize::new(list.len() + 1).unwrap();
272        list.push(val);
273        Self {
274            idx,
275            marker: PhantomData,
276        }
277    }
278
279    /// Returns a reference to the object that this handle points to.
280    pub fn get<'a>(&self, ctx: &'a StoreObjects) -> &'a T {
281        &T::list(ctx)[self.idx.get() - 1]
282    }
283
284    /// Returns a mutable reference to the object that this handle points to.
285    pub fn get_mut<'a>(&self, ctx: &'a mut StoreObjects) -> &'a mut T {
286        &mut T::list_mut(ctx)[self.idx.get() - 1]
287    }
288
289    pub(crate) fn index(&self) -> usize {
290        self.idx.get()
291    }
292
293    pub(crate) fn from_index(idx: usize) -> Option<Self> {
294        NonZeroUsize::new(idx).map(|idx| Self {
295            idx,
296            marker: PhantomData,
297        })
298    }
299}
300
301/// Data used by the generated code is generally located inline within the
302/// `VMContext` for items defined in an instance. Host-defined objects are
303/// allocated separately and owned directly by the context.
304pub enum MaybeInstanceOwned<T> {
305    /// The data is owned here.
306    Host(Box<UnsafeCell<T>>),
307
308    /// The data is stored inline in the `VMContext` of an instance.
309    Instance(NonNull<T>),
310}
311
312impl<T> MaybeInstanceOwned<T> {
313    /// Returns underlying pointer to the VM data.
314    pub fn as_ptr(&self) -> NonNull<T> {
315        match self {
316            Self::Host(p) => unsafe { NonNull::new_unchecked(p.get()) },
317            Self::Instance(p) => *p,
318        }
319    }
320}
321
322impl<T> std::fmt::Debug for MaybeInstanceOwned<T>
323where
324    T: std::fmt::Debug,
325{
326    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
327        match self {
328            Self::Host(p) => {
329                write!(f, "host(")?;
330                p.as_ref().fmt(f)?;
331                write!(f, ")")
332            }
333            Self::Instance(p) => {
334                write!(f, "instance(")?;
335                unsafe { p.as_ref().fmt(f)? };
336                write!(f, ")")
337            }
338        }
339    }
340}