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
9pub trait StoreObject: Sized {
12 fn list(ctx: &StoreObjects) -> &Vec<Self>;
14
15 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#[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 #[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 pub fn id(&self) -> StoreId {
90 self.id
91 }
92
93 pub fn set_id(&mut self, id: StoreId) {
95 self.id = id;
96 }
97
98 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 pub fn iter_globals(&self) -> Iter<VMGlobal> {
119 self.globals.iter()
120 }
121
122 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 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#[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 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 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 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 pub fn internal_handle(&self) -> InternalStoreHandle<T> {
206 self.internal
207 }
208
209 pub fn store_id(&self) -> StoreId {
211 self.id
212 }
213
214 pub fn set_store_id(&mut self, id: StoreId) {
216 self.id = id;
217 }
218
219 pub unsafe fn from_internal(id: StoreId, internal: InternalStoreHandle<T>) -> Self {
224 Self { id, internal }
225 }
226}
227
228#[repr(transparent)]
233pub struct InternalStoreHandle<T> {
234 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 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 pub fn get<'a>(&self, ctx: &'a StoreObjects) -> &'a T {
281 &T::list(ctx)[self.idx.get() - 1]
282 }
283
284 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
301pub enum MaybeInstanceOwned<T> {
305 Host(Box<UnsafeCell<T>>),
307
308 Instance(NonNull<T>),
310}
311
312impl<T> MaybeInstanceOwned<T> {
313 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}