wasmer_vm/resolver.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 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
use std::sync::Arc;
use crate::{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)]
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 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
pub import_init_function_ptr: Option<ImportInitializerFuncPtr>,
/// A function analogous to `Clone::clone` that returns a leaked `Box`.
pub 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.
pub 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)]
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)
}
}
///
/// Import resolver connects imports with available exported values.
pub trait Resolver {
/// Resolves an import a WebAssembly module to an export it's hooked up to.
///
/// The `index` provided is the index of the import in the wasm module
/// that's being resolved. For example 1 means that it's the second import
/// listed in the wasm module.
///
/// The `module` and `field` arguments provided are the module/field names
/// listed on the import itself.
///
/// # Notes:
///
/// The index is useful because some WebAssembly modules may rely on that
/// for resolving ambiguity in their imports. Such as:
/// ```ignore
/// (module
/// (import "" "" (func))
/// (import "" "" (func (param i32) (result i32)))
/// )
/// ```
fn resolve(&self, _index: u32, module: &str, field: &str) -> Option<Export>;
}
/// Import resolver connects imports with available exported values.
///
/// This is a specific subtrait for [`Resolver`] for those users who don't
/// care about the `index`, but only about the `module` and `field` for
/// the resolution.
pub trait NamedResolver {
/// Resolves an import a WebAssembly module to an export it's hooked up to.
///
/// It receives the `module` and `field` names and return the [`Export`] in
/// case it's found.
fn resolve_by_name(&self, module: &str, field: &str) -> Option<Export>;
}
// All NamedResolvers should extend `Resolver`.
impl<T: NamedResolver> Resolver for T {
/// By default this method will be calling [`NamedResolver::resolve_by_name`],
/// dismissing the provided `index`.
fn resolve(&self, _index: u32, module: &str, field: &str) -> Option<Export> {
self.resolve_by_name(module, field)
}
}
impl<T: NamedResolver> NamedResolver for &T {
fn resolve_by_name(&self, module: &str, field: &str) -> Option<Export> {
(**self).resolve_by_name(module, field)
}
}
impl NamedResolver for Box<dyn NamedResolver + Send + Sync> {
fn resolve_by_name(&self, module: &str, field: &str) -> Option<Export> {
(**self).resolve_by_name(module, field)
}
}
impl NamedResolver for () {
/// Always returns `None`.
fn resolve_by_name(&self, _module: &str, _field: &str) -> Option<Export> {
None
}
}
/// `Resolver` implementation that always resolves to `None`. Equivalent to `()`.
pub struct NullResolver {}
impl Resolver for NullResolver {
fn resolve(&self, _idx: u32, _module: &str, _field: &str) -> Option<Export> {
None
}
}
/// A [`Resolver`] that links two resolvers together in a chain.
pub struct NamedResolverChain<A: NamedResolver + Send + Sync, B: NamedResolver + Send + Sync> {
a: A,
b: B,
}
/// A trait for chaining resolvers together.
///
/// ```
/// # use wasmer_vm::{ChainableNamedResolver, NamedResolver};
/// # fn chainable_test<A, B>(imports1: A, imports2: B)
/// # where A: NamedResolver + Sized + Send + Sync,
/// # B: NamedResolver + Sized + Send + Sync,
/// # {
/// // override duplicates with imports from `imports2`
/// imports1.chain_front(imports2);
/// # }
/// ```
pub trait ChainableNamedResolver: NamedResolver + Sized + Send + Sync {
/// Chain a resolver in front of the current resolver.
///
/// This will cause the second resolver to override the first.
///
/// ```
/// # use wasmer_vm::{ChainableNamedResolver, NamedResolver};
/// # fn chainable_test<A, B>(imports1: A, imports2: B)
/// # where A: NamedResolver + Sized + Send + Sync,
/// # B: NamedResolver + Sized + Send + Sync,
/// # {
/// // override duplicates with imports from `imports2`
/// imports1.chain_front(imports2);
/// # }
/// ```
fn chain_front<U>(self, other: U) -> NamedResolverChain<U, Self>
where
U: NamedResolver + Send + Sync,
{
NamedResolverChain { a: other, b: self }
}
/// Chain a resolver behind the current resolver.
///
/// This will cause the first resolver to override the second.
///
/// ```
/// # use wasmer_vm::{ChainableNamedResolver, NamedResolver};
/// # fn chainable_test<A, B>(imports1: A, imports2: B)
/// # where A: NamedResolver + Sized + Send + Sync,
/// # B: NamedResolver + Sized + Send + Sync,
/// # {
/// // override duplicates with imports from `imports1`
/// imports1.chain_back(imports2);
/// # }
/// ```
fn chain_back<U>(self, other: U) -> NamedResolverChain<Self, U>
where
U: NamedResolver + Send + Sync,
{
NamedResolverChain { a: self, b: other }
}
}
// We give these chain methods to all types implementing NamedResolver
impl<T: NamedResolver + Send + Sync> ChainableNamedResolver for T {}
impl<A, B> NamedResolver for NamedResolverChain<A, B>
where
A: NamedResolver + Send + Sync,
B: NamedResolver + Send + Sync,
{
fn resolve_by_name(&self, module: &str, field: &str) -> Option<Export> {
self.a
.resolve_by_name(module, field)
.or_else(|| self.b.resolve_by_name(module, field))
}
}
impl<A, B> Clone for NamedResolverChain<A, B>
where
A: NamedResolver + Clone + Send + Sync,
B: NamedResolver + Clone + Send + Sync,
{
fn clone(&self) -> Self {
Self {
a: self.a.clone(),
b: self.b.clone(),
}
}
}