wasmer_engine/
export.rs

1use loupe::MemoryUsage;
2use std::sync::Arc;
3use wasmer_vm::{ImportInitializerFuncPtr, VMExtern, VMFunction, VMGlobal, VMMemory, VMTable};
4
5/// The value of an export passed from one instance to another.
6#[derive(Debug, Clone)]
7pub enum Export {
8    /// A function export value.
9    Function(ExportFunction),
10
11    /// A table export value.
12    Table(VMTable),
13
14    /// A memory export value.
15    Memory(VMMemory),
16
17    /// A global export value.
18    Global(VMGlobal),
19}
20
21impl From<Export> for VMExtern {
22    fn from(other: Export) -> Self {
23        match other {
24            Export::Function(ExportFunction { vm_function, .. }) => Self::Function(vm_function),
25            Export::Memory(vm_memory) => Self::Memory(vm_memory),
26            Export::Table(vm_table) => Self::Table(vm_table),
27            Export::Global(vm_global) => Self::Global(vm_global),
28        }
29    }
30}
31
32impl From<VMExtern> for Export {
33    fn from(other: VMExtern) -> Self {
34        match other {
35            VMExtern::Function(vm_function) => Self::Function(ExportFunction {
36                vm_function,
37                metadata: None,
38            }),
39            VMExtern::Memory(vm_memory) => Self::Memory(vm_memory),
40            VMExtern::Table(vm_table) => Self::Table(vm_table),
41            VMExtern::Global(vm_global) => Self::Global(vm_global),
42        }
43    }
44}
45
46/// Extra metadata about `ExportFunction`s.
47///
48/// The metadata acts as a kind of manual virtual dispatch. We store the
49/// user-supplied `WasmerEnv` as a void pointer and have methods on it
50/// that have been adapted to accept a void pointer.
51///
52/// This struct owns the original `host_env`, thus when it gets dropped
53/// it calls the `drop` function on it.
54#[derive(Debug, PartialEq, MemoryUsage)]
55pub struct ExportFunctionMetadata {
56    /// This field is stored here to be accessible by `Drop`.
57    ///
58    /// At the time it was added, it's not accessed anywhere outside of
59    /// the `Drop` implementation. This field is the "master copy" of the env,
60    /// that is, the original env passed in by the user. Every time we create
61    /// an `Instance` we clone this with the `host_env_clone_fn` field.
62    ///
63    /// Thus, we only bother to store the master copy at all here so that
64    /// we can free it.
65    ///
66    /// See `wasmer_vm::export::VMFunction::vmctx` for the version of
67    /// this pointer that is used by the VM when creating an `Instance`.
68    pub(crate) host_env: *mut std::ffi::c_void,
69
70    /// Function pointer to `WasmerEnv::init_with_instance(&mut self, instance: &Instance)`.
71    ///
72    /// This function is called to finish setting up the environment after
73    /// we create the `api::Instance`.
74    // This one is optional for now because dynamic host envs need the rest
75    // of this without the init fn
76    #[loupe(skip)]
77    pub(crate) import_init_function_ptr: Option<ImportInitializerFuncPtr>,
78
79    /// A function analogous to `Clone::clone` that returns a leaked `Box`.
80    #[loupe(skip)]
81    pub(crate) host_env_clone_fn: fn(*mut std::ffi::c_void) -> *mut std::ffi::c_void,
82
83    /// The destructor to free the host environment.
84    ///
85    /// # Safety
86    /// - This function should only be called in when properly synchronized.
87    /// For example, in the `Drop` implementation of this type.
88    #[loupe(skip)]
89    pub(crate) host_env_drop_fn: unsafe fn(*mut std::ffi::c_void),
90}
91
92/// This can be `Send` because `host_env` comes from `WasmerEnv` which is
93/// `Send`. Therefore all operations should work on any thread.
94unsafe impl Send for ExportFunctionMetadata {}
95/// This data may be shared across threads, `drop` is an unsafe function
96/// pointer, so care must be taken when calling it.
97unsafe impl Sync for ExportFunctionMetadata {}
98
99impl ExportFunctionMetadata {
100    /// Create an `ExportFunctionMetadata` type with information about
101    /// the exported function.
102    ///
103    /// # Safety
104    /// - the `host_env` must be `Send`.
105    /// - all function pointers must work on any thread.
106    pub unsafe fn new(
107        host_env: *mut std::ffi::c_void,
108        import_init_function_ptr: Option<ImportInitializerFuncPtr>,
109        host_env_clone_fn: fn(*mut std::ffi::c_void) -> *mut std::ffi::c_void,
110        host_env_drop_fn: fn(*mut std::ffi::c_void),
111    ) -> Self {
112        Self {
113            host_env,
114            import_init_function_ptr,
115            host_env_clone_fn,
116            host_env_drop_fn,
117        }
118    }
119}
120
121// We have to free `host_env` here because we always clone it before using it
122// so all the `host_env`s freed at the `Instance` level won't touch the original.
123impl Drop for ExportFunctionMetadata {
124    fn drop(&mut self) {
125        if !self.host_env.is_null() {
126            // # Safety
127            // - This is correct because we know no other references
128            //   to this data can exist if we're dropping it.
129            unsafe {
130                (self.host_env_drop_fn)(self.host_env);
131            }
132        }
133    }
134}
135
136/// A function export value with an extra function pointer to initialize
137/// host environments.
138#[derive(Debug, Clone, PartialEq, MemoryUsage)]
139pub struct ExportFunction {
140    /// The VM function, containing most of the data.
141    pub vm_function: VMFunction,
142    /// Contains functions necessary to create and initialize host envs
143    /// with each `Instance` as well as being responsible for the
144    /// underlying memory of the host env.
145    pub metadata: Option<Arc<ExportFunctionMetadata>>,
146}
147
148impl From<ExportFunction> for Export {
149    fn from(func: ExportFunction) -> Self {
150        Self::Function(func)
151    }
152}
153
154impl From<VMTable> for Export {
155    fn from(table: VMTable) -> Self {
156        Self::Table(table)
157    }
158}
159
160impl From<VMMemory> for Export {
161    fn from(memory: VMMemory) -> Self {
162        Self::Memory(memory)
163    }
164}
165
166impl From<VMGlobal> for Export {
167    fn from(global: VMGlobal) -> Self {
168        Self::Global(global)
169    }
170}