near_vm_vm/instance/
ref.rs

1use super::Instance;
2use std::alloc::Layout;
3use std::convert::TryFrom;
4use std::ptr::{self, NonNull};
5use std::sync::{Arc, Weak};
6
7/// Dynamic instance allocation.
8///
9/// This structure has a C representation because `Instance` is
10/// dynamically-sized, and the `instance` field must be last.
11///
12/// This `InstanceRef` must be freed with [`InstanceInner::deallocate_instance`]
13/// if and only if it has been set correctly. The `Drop` implementation of
14/// [`InstanceInner`] calls its `deallocate_instance` method without
15/// checking if this property holds, only when `Self.strong` is equal to 1.
16#[derive(Debug)]
17#[repr(C)]
18struct InstanceInner {
19    /// The layout of `Instance` (which can vary).
20    instance_layout: Layout,
21
22    /// The `Instance` itself. It must be the last field of
23    /// `InstanceRef` since `Instance` is dynamically-sized.
24    ///
25    /// `Instance` must not be dropped manually by Rust, because it's
26    /// allocated manually with `alloc` and a specific layout (Rust
27    /// would be able to drop `Instance` itself but it will imply a
28    /// memory leak because of `alloc`).
29    ///
30    /// No one in the code has a copy of the `Instance`'s
31    /// pointer. `Self` is the only one.
32    instance: NonNull<Instance>,
33}
34
35impl InstanceInner {
36    /// Deallocate `Instance`.
37    ///
38    /// # Safety
39    ///
40    /// `Self.instance` must be correctly set and filled before being
41    /// dropped and deallocated.
42    unsafe fn deallocate_instance(&mut self) {
43        let instance_ptr = self.instance.as_ptr();
44
45        unsafe {
46            ptr::drop_in_place(instance_ptr);
47            std::alloc::dealloc(instance_ptr as *mut u8, self.instance_layout);
48        }
49    }
50
51    /// Get a reference to the `Instance`.
52    #[inline]
53    pub(crate) fn as_ref(&self) -> &Instance {
54        // SAFETY: The pointer is properly aligned, it is
55        // “dereferencable”, it points to an initialized memory of
56        // `Instance`, and the reference has the lifetime `'a`.
57        unsafe { self.instance.as_ref() }
58    }
59
60    #[inline]
61    pub(super) fn as_mut(&mut self) -> &mut Instance {
62        unsafe { self.instance.as_mut() }
63    }
64}
65
66impl PartialEq for InstanceInner {
67    /// Two `InstanceInner` are equal if and only if
68    /// `Self.instance` points to the same location.
69    fn eq(&self, other: &Self) -> bool {
70        self.instance == other.instance
71    }
72}
73
74impl Drop for InstanceInner {
75    /// Drop the `InstanceInner`.
76    fn drop(&mut self) {
77        unsafe { Self::deallocate_instance(self) };
78    }
79}
80
81// TODO: These implementations have been added to enable instances to contain `Arc`s, however it
82// isn’t exactly clear that the `InstanceInner` contents are `Send` or `Sync`, thus effectively
83// lying to the compiler. Fortunately in actual use this is not a big deal as the near runtime is
84// single-threaded anyway (and `Arc` is only necessary to facilitate caching of the loaded
85// modules IIRC; an attempt to remove this cache has been made in the past, but had to be
86// restored.)
87unsafe impl Send for InstanceInner {}
88unsafe impl Sync for InstanceInner {}
89
90/// An `InstanceRef` is responsible to properly deallocate,
91/// and to give access to an `Instance`, in such a way that `Instance`
92/// is unique, can be shared, safely, across threads, without
93/// duplicating the pointer in multiple locations. `InstanceRef`
94/// must be the only “owner” of an `Instance`.
95///
96/// Consequently, one must not share `Instance` but
97/// `InstanceRef`. It acts like an Atomically Reference Counter
98/// to `Instance`. In short, `InstanceRef` is roughly a
99/// simplified version of `std::sync::Arc`.
100///
101/// Note for the curious reader: [`InstanceAllocator::new`]
102/// and [`InstanceHandle::new`] will respectively allocate a proper
103/// `Instance` and will fill it correctly.
104///
105/// A little bit of background: The initial goal was to be able to
106/// share an [`Instance`] between an [`InstanceHandle`] and the module
107/// exports, so that one can drop a [`InstanceHandle`] but still being
108/// able to use the exports properly.
109#[derive(Debug, PartialEq, Clone)]
110pub struct InstanceRef(Arc<InstanceInner>);
111
112impl InstanceRef {
113    /// Create a new `InstanceRef`. It allocates nothing. It fills
114    /// nothing. The `Instance` must be already valid and
115    /// filled.
116    ///
117    /// # Safety
118    ///
119    /// `instance` must a non-null, non-dangling, properly aligned,
120    /// and correctly initialized pointer to `Instance`. See
121    /// [`InstanceAllocator`] for an example of how to correctly use
122    /// this API.
123    pub(super) unsafe fn new(instance: NonNull<Instance>, instance_layout: Layout) -> Self {
124        Self(Arc::new(InstanceInner { instance_layout, instance }))
125    }
126
127    /// Get a reference to the `Instance`.
128    #[inline]
129    pub fn as_ref(&self) -> &Instance {
130        (&*self.0).as_ref()
131    }
132
133    /// Only succeeds if ref count is 1.
134    #[inline]
135    pub(super) fn as_mut(&mut self) -> Option<&mut Instance> {
136        Some(Arc::get_mut(&mut self.0)?.as_mut())
137    }
138
139    /// Like [`InstanceRef::as_mut`] but always succeeds.
140    /// May cause undefined behavior if used improperly.
141    ///
142    /// # Safety
143    /// It is the caller's responsibility to ensure exclusivity and synchronization of the
144    /// instance before calling this function. No other pointers to any Instance data
145    /// should be dereferenced for the lifetime of the returned `&mut Instance`.
146    #[inline]
147    pub(super) unsafe fn as_mut_unchecked(&mut self) -> &mut Instance {
148        let ptr: *mut InstanceInner = Arc::as_ptr(&self.0) as *mut _;
149        unsafe { (&mut *ptr).as_mut() }
150    }
151}
152
153/// A weak instance ref. This type does not keep the underlying `Instance` alive
154/// but can be converted into a full `InstanceRef` if the underlying `Instance` hasn't
155/// been deallocated.
156#[derive(Debug, Clone)]
157pub struct WeakInstanceRef(Weak<InstanceInner>);
158
159impl PartialEq for WeakInstanceRef {
160    fn eq(&self, other: &Self) -> bool {
161        self.0.ptr_eq(&other.0)
162    }
163}
164
165impl WeakInstanceRef {
166    /// Try to convert into a strong, `InstanceRef`.
167    pub fn upgrade(&self) -> Option<InstanceRef> {
168        let inner = self.0.upgrade()?;
169        Some(InstanceRef(inner))
170    }
171}
172
173/// An `InstanceRef` that may or may not be keeping the `Instance` alive.
174///
175/// This type is useful for types that conditionally must keep / not keep the
176/// underlying `Instance` alive. For example, to prevent cycles in `WasmerEnv`s.
177#[derive(Debug, Clone, PartialEq)]
178pub enum WeakOrStrongInstanceRef {
179    /// A weak instance ref.
180    Weak(WeakInstanceRef),
181    /// A strong instance ref.
182    Strong(InstanceRef),
183}
184
185impl WeakOrStrongInstanceRef {
186    /// Tries to upgrade weak references to a strong reference, returning None
187    /// if it can't be done.
188    pub fn upgrade(&self) -> Option<Self> {
189        match self {
190            Self::Weak(weak) => weak.upgrade().map(Self::Strong),
191            Self::Strong(strong) => Some(Self::Strong(strong.clone())),
192        }
193    }
194
195    /// Clones self into a weak reference.
196    pub fn downgrade(&self) -> Self {
197        match self {
198            Self::Weak(weak) => Self::Weak(weak.clone()),
199            Self::Strong(strong) => Self::Weak(WeakInstanceRef(Arc::downgrade(&strong.0))),
200        }
201    }
202}
203
204impl TryFrom<WeakOrStrongInstanceRef> for InstanceRef {
205    type Error = &'static str;
206    fn try_from(value: WeakOrStrongInstanceRef) -> Result<Self, Self::Error> {
207        match value {
208            WeakOrStrongInstanceRef::Strong(strong) => Ok(strong),
209            WeakOrStrongInstanceRef::Weak(weak) => {
210                weak.upgrade().ok_or("Failed to upgrade weak reference")
211            }
212        }
213    }
214}
215
216impl From<WeakOrStrongInstanceRef> for WeakInstanceRef {
217    fn from(value: WeakOrStrongInstanceRef) -> Self {
218        match value {
219            WeakOrStrongInstanceRef::Strong(strong) => Self(Arc::downgrade(&strong.0)),
220            WeakOrStrongInstanceRef::Weak(weak) => weak,
221        }
222    }
223}
224
225impl From<WeakInstanceRef> for WeakOrStrongInstanceRef {
226    fn from(value: WeakInstanceRef) -> Self {
227        Self::Weak(value)
228    }
229}
230
231impl From<InstanceRef> for WeakOrStrongInstanceRef {
232    fn from(value: InstanceRef) -> Self {
233        Self::Strong(value)
234    }
235}