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}
18
19macro_rules! impl_context_object {
20 ($($field:ident => $ty:ty,)*) => {
21 $(
22 impl StoreObject for $ty {
23 fn list(ctx: &StoreObjects) -> &Vec<Self> {
24 &ctx.$field
25 }
26 fn list_mut(ctx: &mut StoreObjects) -> &mut Vec<Self> {
27 &mut ctx.$field
28 }
29 }
30 )*
31 };
32}
33
34impl_context_object! {
35 functions => VMFunction,
36 tables => VMTable,
37 globals => VMGlobal,
38 instances => VMInstance,
39 memories => VMMemory,
40 extern_objs => VMExternObj,
41 exceptions => VMExceptionObj,
42 tags => VMTag,
43 function_environments => VMFunctionEnvironment,
44}
45
46#[derive(Debug, Default)]
48pub struct StoreObjects {
49 id: StoreId,
50 memories: Vec<VMMemory>,
51 tables: Vec<VMTable>,
52 globals: Vec<VMGlobal>,
53 functions: Vec<VMFunction>,
54 instances: Vec<VMInstance>,
55 extern_objs: Vec<VMExternObj>,
56 exceptions: Vec<VMExceptionObj>,
57 tags: Vec<VMTag>,
58 function_environments: Vec<VMFunctionEnvironment>,
59}
60
61impl StoreObjects {
62 #[allow(clippy::too_many_arguments)]
64 pub fn new(
65 id: StoreId,
66 memories: Vec<VMMemory>,
67 tables: Vec<VMTable>,
68 globals: Vec<VMGlobal>,
69 functions: Vec<VMFunction>,
70 instances: Vec<VMInstance>,
71 extern_objs: Vec<VMExternObj>,
72 exceptions: Vec<VMExceptionObj>,
73 tags: Vec<VMTag>,
74 function_environments: Vec<VMFunctionEnvironment>,
75 ) -> Self {
76 Self {
77 id,
78 memories,
79 tables,
80 globals,
81 functions,
82 instances,
83 extern_objs,
84 function_environments,
85 exceptions,
86 tags,
87 }
88 }
89
90 pub fn id(&self) -> StoreId {
92 self.id
93 }
94
95 pub fn set_id(&mut self, id: StoreId) {
97 self.id = id;
98 }
99
100 pub fn get_2_mut<T: StoreObject>(
104 &mut self,
105 a: InternalStoreHandle<T>,
106 b: InternalStoreHandle<T>,
107 ) -> (&mut T, &mut T) {
108 assert_ne!(a.index(), b.index());
109 let list = T::list_mut(self);
110 if a.index() < b.index() {
111 let (low, high) = list.split_at_mut(b.index());
112 (&mut low[a.index()], &mut high[0])
113 } else {
114 let (low, high) = list.split_at_mut(a.index());
115 (&mut high[0], &mut low[a.index()])
116 }
117 }
118
119 pub fn iter_globals(&self) -> Iter<'_, VMGlobal> {
121 self.globals.iter()
122 }
123
124 pub fn as_u128_globals(&self) -> Vec<u128> {
126 self.iter_globals()
127 .map(|v| unsafe { v.vmglobal().as_ref().val.u128 })
128 .collect()
129 }
130
131 pub fn set_global_unchecked(&self, idx: usize, val: u128) {
135 assert!(idx < self.globals.len());
136 unsafe {
137 self.globals[idx].vmglobal().as_mut().val.u128 = val;
138 }
139 }
140}
141
142#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
147pub struct StoreHandle<T> {
148 id: StoreId,
149 internal: InternalStoreHandle<T>,
150}
151
152impl<T> Clone for StoreHandle<T> {
153 fn clone(&self) -> Self {
154 Self {
155 id: self.id,
156 internal: self.internal,
157 }
158 }
159}
160
161impl<T> std::hash::Hash for StoreHandle<T> {
162 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
163 self.id.hash(state);
164 self.internal.idx.hash(state);
165 }
166}
167
168impl<T: StoreObject> fmt::Debug for StoreHandle<T> {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 f.debug_struct("StoreHandle")
171 .field("id", &self.id)
172 .field("internal", &self.internal.index())
173 .finish()
174 }
175}
176
177impl<T: StoreObject> PartialEq for StoreHandle<T> {
178 fn eq(&self, other: &Self) -> bool {
179 self.id == other.id && self.internal == other.internal
180 }
181}
182
183impl<T: StoreObject> Eq for StoreHandle<T> {}
184
185impl<T: StoreObject> StoreHandle<T> {
186 pub fn new(ctx: &mut StoreObjects, val: T) -> Self {
188 Self {
189 id: ctx.id,
190 internal: InternalStoreHandle::new(ctx, val),
191 }
192 }
193
194 pub fn get<'a>(&self, ctx: &'a StoreObjects) -> &'a T {
196 assert_eq!(self.id, ctx.id, "object used with the wrong context");
197 self.internal.get(ctx)
198 }
199
200 pub fn get_mut<'a>(&self, ctx: &'a mut StoreObjects) -> &'a mut T {
202 assert_eq!(self.id, ctx.id, "object used with the wrong context");
203 self.internal.get_mut(ctx)
204 }
205
206 pub fn internal_handle(&self) -> InternalStoreHandle<T> {
208 self.internal
209 }
210
211 pub fn store_id(&self) -> StoreId {
213 self.id
214 }
215
216 pub fn set_store_id(&mut self, id: StoreId) {
218 self.id = id;
219 }
220
221 pub unsafe fn from_internal(id: StoreId, internal: InternalStoreHandle<T>) -> Self {
226 Self { id, internal }
227 }
228}
229
230#[repr(transparent)]
235pub struct InternalStoreHandle<T> {
236 idx: NonZeroUsize,
238 marker: PhantomData<fn() -> T>,
239}
240
241#[cfg(feature = "artifact-size")]
242impl<T> loupe::MemoryUsage for InternalStoreHandle<T> {
243 fn size_of_val(&self, _tracker: &mut dyn loupe::MemoryUsageTracker) -> usize {
244 std::mem::size_of_val(&self)
245 }
246}
247
248impl<T> Clone for InternalStoreHandle<T> {
249 fn clone(&self) -> Self {
250 *self
251 }
252}
253impl<T> Copy for InternalStoreHandle<T> {}
254
255impl<T> fmt::Debug for InternalStoreHandle<T> {
256 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
257 f.debug_struct("InternalStoreHandle")
258 .field("idx", &self.idx)
259 .finish()
260 }
261}
262impl<T> PartialEq for InternalStoreHandle<T> {
263 fn eq(&self, other: &Self) -> bool {
264 self.idx == other.idx
265 }
266}
267impl<T> Eq for InternalStoreHandle<T> {}
268
269impl<T: StoreObject> InternalStoreHandle<T> {
270 pub fn new(ctx: &mut StoreObjects, val: T) -> Self {
272 let list = T::list_mut(ctx);
273 let idx = NonZeroUsize::new(list.len() + 1).unwrap();
274 list.push(val);
275 Self {
276 idx,
277 marker: PhantomData,
278 }
279 }
280
281 pub fn get<'a>(&self, ctx: &'a StoreObjects) -> &'a T {
283 &T::list(ctx)[self.idx.get() - 1]
284 }
285
286 pub fn get_mut<'a>(&self, ctx: &'a mut StoreObjects) -> &'a mut T {
288 &mut T::list_mut(ctx)[self.idx.get() - 1]
289 }
290
291 pub(crate) fn index(&self) -> usize {
292 self.idx.get()
293 }
294
295 pub(crate) fn from_index(idx: usize) -> Option<Self> {
296 NonZeroUsize::new(idx).map(|idx| Self {
297 idx,
298 marker: PhantomData,
299 })
300 }
301}
302
303pub enum MaybeInstanceOwned<T> {
307 Host(Box<UnsafeCell<T>>),
309
310 Instance(NonNull<T>),
312}
313
314impl<T> MaybeInstanceOwned<T> {
315 pub fn as_ptr(&self) -> NonNull<T> {
317 match self {
318 Self::Host(p) => unsafe { NonNull::new_unchecked(p.get()) },
319 Self::Instance(p) => *p,
320 }
321 }
322}
323
324impl<T> std::fmt::Debug for MaybeInstanceOwned<T>
325where
326 T: std::fmt::Debug,
327{
328 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
329 match self {
330 Self::Host(p) => {
331 write!(f, "host(")?;
332 p.as_ref().fmt(f)?;
333 write!(f, ")")
334 }
335 Self::Instance(p) => {
336 write!(f, "instance(")?;
337 unsafe { p.as_ref().fmt(f)? };
338 write!(f, ")")
339 }
340 }
341 }
342}