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