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
//! Utility module to create trampolines in/out WebAssembly module.

mod create_handle;
mod func;
mod global;
mod memory;
mod table;

pub(crate) use memory::MemoryCreatorProxy;

use self::func::create_handle_with_function;
use self::global::create_global;
use self::memory::create_handle_with_memory;
use self::table::create_handle_with_table;
use crate::{FuncType, GlobalType, MemoryType, Store, TableType, Trap, Val};
use anyhow::Result;
use std::any::Any;
use std::ops::Deref;
use wasmtime_runtime::{InstanceHandle, VMContext, VMFunctionBody, VMTrampoline};

/// A wrapper around `wasmtime_runtime::InstanceHandle` which pairs it with the
/// `Store` that it's rooted within. The instance is deallocated when `Store` is
/// deallocated, so this is a safe handle in terms of memory management for the
/// `Store`.
pub struct StoreInstanceHandle {
    pub store: Store,
    pub handle: InstanceHandle,
}

impl Clone for StoreInstanceHandle {
    fn clone(&self) -> StoreInstanceHandle {
        StoreInstanceHandle {
            store: self.store.clone(),
            // Note should be safe because the lifetime of the instance handle
            // is tied to the `Store` which this is paired with.
            handle: unsafe { self.handle.clone() },
        }
    }
}

impl Deref for StoreInstanceHandle {
    type Target = InstanceHandle;
    fn deref(&self) -> &InstanceHandle {
        &self.handle
    }
}

pub fn generate_func_export(
    ft: &FuncType,
    func: Box<dyn Fn(*mut VMContext, *mut u128) -> Result<(), Trap>>,
    store: &Store,
) -> Result<(
    StoreInstanceHandle,
    wasmtime_runtime::ExportFunction,
    VMTrampoline,
)> {
    let (instance, trampoline) = create_handle_with_function(ft, func, store)?;
    match instance.lookup("").expect("trampoline export") {
        wasmtime_runtime::Export::Function(f) => Ok((instance, f, trampoline)),
        _ => unreachable!(),
    }
}

/// Note that this is `unsafe` since `func` must be a valid function pointer and
/// have a signature which matches `ft`, otherwise the returned
/// instance/export/etc may exhibit undefined behavior.
pub unsafe fn generate_raw_func_export(
    ft: &FuncType,
    func: *mut [VMFunctionBody],
    trampoline: VMTrampoline,
    store: &Store,
    state: Box<dyn Any>,
) -> Result<(StoreInstanceHandle, wasmtime_runtime::ExportFunction)> {
    let instance = func::create_handle_with_raw_function(ft, func, trampoline, store, state)?;
    match instance.lookup("").expect("trampoline export") {
        wasmtime_runtime::Export::Function(f) => Ok((instance, f)),
        _ => unreachable!(),
    }
}

pub fn generate_global_export(
    store: &Store,
    gt: &GlobalType,
    val: Val,
) -> Result<(StoreInstanceHandle, wasmtime_runtime::ExportGlobal)> {
    let instance = create_global(store, gt, val)?;
    match instance.lookup("").expect("global export") {
        wasmtime_runtime::Export::Global(g) => Ok((instance, g)),
        _ => unreachable!(),
    }
}

pub fn generate_memory_export(
    store: &Store,
    m: &MemoryType,
) -> Result<(StoreInstanceHandle, wasmtime_runtime::ExportMemory)> {
    let instance = create_handle_with_memory(store, m)?;
    match instance.lookup("").expect("memory export") {
        wasmtime_runtime::Export::Memory(m) => Ok((instance, m)),
        _ => unreachable!(),
    }
}

pub fn generate_table_export(
    store: &Store,
    t: &TableType,
) -> Result<(StoreInstanceHandle, wasmtime_runtime::ExportTable)> {
    let instance = create_handle_with_table(store, t)?;
    match instance.lookup("").expect("table export") {
        wasmtime_runtime::Export::Table(t) => Ok((instance, t)),
        _ => unreachable!(),
    }
}