wasmer_vm/
store.rs

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