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
use crate::externals::Function;
use crate::store::{Store, StoreObject};
use crate::RuntimeError;
use std::ptr;
use wasmer_types::Value;
pub use wasmer_types::{
    ExportType, ExternRef, ExternType, FunctionType, GlobalType, HostInfo, HostRef, ImportType,
    MemoryType, Mutability, TableType, Type as ValType,
};

/// WebAssembly computations manipulate values of basic value types:
/// * Integers (32 or 64 bit width)
/// * Floating-point (32 or 64 bit width)
/// * Vectors (128 bits, with 32 or 64 bit lanes)
///
/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#values>
pub type Val = Value<Function>;

impl StoreObject for Val {
    fn comes_from_same_store(&self, store: &Store) -> bool {
        match self {
            Self::FuncRef(f) => Store::same(store, f.store()),
            Self::ExternRef(ExternRef::Ref(_)) | Self::ExternRef(ExternRef::Other(_)) => false,
            Self::ExternRef(ExternRef::Null) => true,
            Self::I32(_) | Self::I64(_) | Self::F32(_) | Self::F64(_) | Self::V128(_) => true,
        }
    }
}

impl From<Function> for Val {
    fn from(val: Function) -> Self {
        Self::FuncRef(val)
    }
}

/// It provides useful functions for converting back and forth
/// from [`Val`] into `FuncRef`.
pub trait ValFuncRef {
    fn into_checked_anyfunc(
        &self,
        store: &Store,
    ) -> Result<wasmer_vm::VMCallerCheckedAnyfunc, RuntimeError>;

    fn from_checked_anyfunc(item: wasmer_vm::VMCallerCheckedAnyfunc, store: &Store) -> Self;
}

impl ValFuncRef for Val {
    fn into_checked_anyfunc(
        &self,
        store: &Store,
    ) -> Result<wasmer_vm::VMCallerCheckedAnyfunc, RuntimeError> {
        if !self.comes_from_same_store(store) {
            return Err(RuntimeError::new("cross-`Store` values are not supported"));
        }
        Ok(match self {
            Self::ExternRef(ExternRef::Null) => wasmer_vm::VMCallerCheckedAnyfunc {
                func_ptr: ptr::null(),
                type_index: wasmer_vm::VMSharedSignatureIndex::default(),
                vmctx: wasmer_vm::VMFunctionEnvironment {
                    host_env: ptr::null_mut(),
                },
            },
            Self::FuncRef(f) => f.checked_anyfunc(),
            _ => return Err(RuntimeError::new("val is not funcref")),
        })
    }

    fn from_checked_anyfunc(item: wasmer_vm::VMCallerCheckedAnyfunc, store: &Store) -> Self {
        if item.type_index == wasmer_vm::VMSharedSignatureIndex::default() {
            return Self::ExternRef(ExternRef::Null);
        }
        let signature = store
            .engine()
            .lookup_signature(item.type_index)
            .expect("Signature not found in store");
        let export = wasmer_engine::ExportFunction {
            // TODO:
            // figure out if we ever need a value here: need testing with complicated import patterns
            metadata: None,
            vm_function: wasmer_vm::VMExportFunction {
                address: item.func_ptr,
                signature,
                // All functions in tables are already Static (as dynamic functions
                // are converted to use the trampolines with static signatures).
                kind: wasmer_vm::VMFunctionKind::Static,
                vmctx: item.vmctx,
                call_trampoline: None,
                instance_ref: None,
            },
        };
        let f = Function::from_vm_export(store, export);
        Self::FuncRef(f)
    }
}