#[cfg(all(target_os = "linux", feature = "wasi_nn", target_arch = "x86_64"))]
use crate::wasi::WasiNnInstance;
#[cfg(all(target_os = "linux", feature = "wasi_crypto"))]
use crate::wasi::{
WasiCryptoAsymmetricCommonInstance, WasiCryptoCommonInstance, WasiCryptoKxInstance,
WasiCryptoSignaturesInstance, WasiCryptoSymmetricInstance,
};
#[cfg(target_os = "linux")]
use crate::WasmEdgeProcessInstance;
use crate::{
config::Config, error::WasmEdgeError, wasi::WasiInstance, Engine, Func, FuncRef, FuncType,
ImportObject, Instance, Module, Statistics, WasmEdgeResult, WasmValue,
};
use std::{marker::PhantomData, path::Path};
use wasmedge_sys::{self as sys, Engine as sys_engine};
#[derive(Debug, Clone)]
pub struct Vm {
pub(crate) inner: sys::Vm,
active_module: Option<Module>,
}
impl Vm {
pub fn new(config: Option<Config>) -> WasmEdgeResult<Self> {
let inner_config = config.map(|c| c.inner);
let inner = sys::Vm::create(inner_config, None)?;
Ok(Self {
inner,
active_module: None,
})
}
pub fn register_module_from_file(
self,
mod_name: impl AsRef<str>,
file: impl AsRef<Path>,
) -> WasmEdgeResult<Self> {
self.inner
.register_wasm_from_file(mod_name, file.as_ref())?;
Ok(self)
}
pub fn register_module_from_bytes(
self,
mod_name: impl AsRef<str>,
bytes: impl AsRef<[u8]>,
) -> WasmEdgeResult<Self> {
self.inner
.register_wasm_from_bytes(mod_name, bytes.as_ref())?;
Ok(self)
}
pub fn register_import_module(mut self, import: ImportObject) -> WasmEdgeResult<Self> {
self.inner.register_wasm_from_import(import.0)?;
Ok(self)
}
pub fn register_module(self, mod_name: Option<&str>, module: Module) -> WasmEdgeResult<Self> {
match mod_name {
Some(name) => self.register_named_module(module, name),
None => self.register_active_module(module),
}
}
fn register_named_module(
self,
module: Module,
mod_name: impl AsRef<str>,
) -> WasmEdgeResult<Self> {
self.inner
.register_wasm_from_module(mod_name.as_ref(), module.inner)?;
Ok(self)
}
fn register_active_module(mut self, module: Module) -> WasmEdgeResult<Self> {
self.active_module = Some(module);
self.inner
.load_wasm_from_module(&self.active_module.as_ref().unwrap().inner)?;
self.inner.validate()?;
self.inner.instantiate()?;
Ok(self)
}
pub fn reset(&mut self) {
self.inner.reset()
}
pub fn run_func(
&self,
mod_name: Option<&str>,
func_name: impl AsRef<str>,
args: impl IntoIterator<Item = WasmValue>,
) -> WasmEdgeResult<Vec<WasmValue>> {
let returns = match mod_name {
Some(mod_name) => {
self.inner
.run_registered_function(mod_name, func_name.as_ref(), args)?
}
None => {
self.inner.run_function(func_name.as_ref(), args)?
}
};
Ok(returns)
}
#[cfg(feature = "async")]
pub async fn run_func_async<M, N, A>(
&self,
mod_name: Option<M>,
func_name: N,
args: A,
) -> WasmEdgeResult<Vec<WasmValue>>
where
M: AsRef<str> + Send,
N: AsRef<str> + Send,
A: IntoIterator<Item = WasmValue> + Send,
{
match mod_name {
Some(mod_name) => {
self.inner
.run_registered_function_async(mod_name, func_name.as_ref(), args)
.await
}
None => {
self.inner
.run_function_async(func_name.as_ref(), args)
.await
}
}
}
pub fn func_ty(
&mut self,
mod_name: Option<&str>,
func_name: impl AsRef<str>,
) -> WasmEdgeResult<FuncType> {
let func_ty = match mod_name {
Some(mod_name) => self
.inner
.get_registered_function_type(mod_name, func_name.as_ref())?,
None => self.inner.get_function_type(func_name.as_ref())?,
};
Ok(func_ty.into())
}
pub fn run_func_from_file(
&self,
file: impl AsRef<Path>,
func_name: impl AsRef<str>,
args: impl IntoIterator<Item = sys::WasmValue>,
) -> WasmEdgeResult<Vec<WasmValue>> {
match file.as_ref().extension() {
Some(extension) => match extension.to_str() {
Some("wasm") => {
self.inner
.run_wasm_from_file(file.as_ref(), func_name.as_ref(), args)
}
#[cfg(target_os = "macos")]
Some("dylib") => {
self.inner
.run_wasm_from_file(file.as_ref(), func_name.as_ref(), args)
}
#[cfg(target_os = "linux")]
Some("so") => {
self.inner
.run_wasm_from_file(file.as_ref(), func_name.as_ref(), args)
}
#[cfg(target_os = "windows")]
Some("dll") => {
self.inner
.run_wasm_from_file(file.as_ref(), func_name.as_ref(), args)
}
Some("wat") => {
let bytes = wat::parse_file(file.as_ref())
.map_err(|_| WasmEdgeError::Operation("Failed to parse wat file".into()))?;
self.inner.run_wasm_from_bytes(&bytes, func_name, args)
}
_ => Err(Box::new(WasmEdgeError::Operation(
"Invalid file extension".into(),
))),
},
None => Err(Box::new(WasmEdgeError::Operation(
"Invalid file extension".into(),
))),
}
}
#[cfg(feature = "async")]
pub async fn run_func_from_file_async<P, N, A>(
&self,
file: P,
func_name: N,
args: A,
) -> WasmEdgeResult<Vec<WasmValue>>
where
P: AsRef<Path>,
N: AsRef<str> + Send,
A: IntoIterator<Item = WasmValue> + Send,
{
match file.as_ref().extension() {
Some(extension) => match extension.to_str() {
Some("wasm") => {
self.inner
.run_wasm_from_file_async(file.as_ref(), func_name.as_ref(), args)
.await
}
#[cfg(target_os = "macos")]
Some("dylib") => {
self.inner
.run_wasm_from_file_async(file.as_ref(), func_name.as_ref(), args)
.await
}
#[cfg(target_os = "linux")]
Some("so") => {
self.inner
.run_wasm_from_file_async(file.as_ref(), func_name.as_ref(), args)
.await
}
#[cfg(target_os = "windows")]
Some("dll") => {
self.inner
.run_wasm_from_file_async(file.as_ref(), func_name.as_ref(), args)
.await
}
Some("wat") => {
let bytes = wat::parse_file(file.as_ref())
.map_err(|_| WasmEdgeError::Operation("Failed to parse wat file".into()))?;
self.inner
.run_wasm_from_bytes_async(&bytes, func_name.as_ref(), args)
.await
}
_ => Err(Box::new(WasmEdgeError::Operation(
"Invalid file extension".into(),
))),
},
None => Err(Box::new(WasmEdgeError::Operation(
"Invalid file extension".into(),
))),
}
}
pub fn run_func_from_bytes(
&self,
bytes: &[u8],
func_name: impl AsRef<str>,
args: impl IntoIterator<Item = sys::WasmValue>,
) -> WasmEdgeResult<Vec<sys::WasmValue>> {
self.inner
.run_wasm_from_bytes(bytes, func_name.as_ref(), args)
}
#[cfg(feature = "async")]
pub async fn run_func_from_bytes_async<N, A>(
&self,
bytes: &[u8],
func_name: N,
args: A,
) -> WasmEdgeResult<Vec<WasmValue>>
where
N: AsRef<str> + Send,
A: IntoIterator<Item = WasmValue> + Send,
{
self.inner
.run_wasm_from_bytes_async(bytes, func_name.as_ref(), args)
.await
}
pub fn run_func_from_module(
&self,
module: Module,
func_name: impl AsRef<str>,
args: impl IntoIterator<Item = sys::WasmValue>,
) -> WasmEdgeResult<Vec<sys::WasmValue>> {
self.inner
.run_wasm_from_module(module.inner, func_name.as_ref(), args)
}
#[cfg(feature = "async")]
pub async fn run_func_from_module_async<N, A>(
&self,
module: Module,
func_name: N,
params: A,
) -> WasmEdgeResult<Vec<WasmValue>>
where
N: AsRef<str> + Send,
A: IntoIterator<Item = WasmValue> + Send,
{
self.inner
.run_wasm_from_module_async(module.inner, func_name, params)
.await
}
pub fn named_instance_count(&self) -> WasmEdgeResult<u32> {
let count = self.inner.store_mut()?.module_len();
Ok(count)
}
pub fn instance_names(&self) -> WasmEdgeResult<Vec<String>> {
let names = self.inner.store_mut()?.module_names();
match names {
Some(names) => Ok(names),
None => Ok(vec![]),
}
}
pub fn named_module(&self, name: impl AsRef<str>) -> WasmEdgeResult<Instance> {
let mut inner_store = self.inner.store_mut()?;
let inner_instance = inner_store.module(name.as_ref())?;
Ok(Instance {
inner: inner_instance,
})
}
pub fn active_module(&self) -> WasmEdgeResult<Instance> {
let inner_instance = self.inner.active_module()?;
Ok(Instance {
inner: inner_instance,
})
}
pub fn statistics(&self) -> WasmEdgeResult<Statistics> {
let inner_stat = self.inner.statistics_mut()?;
Ok(Statistics {
inner: inner_stat,
_marker: PhantomData,
})
}
pub fn wasi_module(&mut self) -> WasmEdgeResult<WasiInstance> {
let inner_wasi_module = self.inner.wasi_module_mut()?;
Ok(WasiInstance {
inner: inner_wasi_module,
})
}
#[cfg(target_os = "linux")]
pub fn wasmedge_process_module(&mut self) -> WasmEdgeResult<WasmEdgeProcessInstance> {
let inner_process_module = self.inner.wasmedge_process_module_mut()?;
Ok(WasmEdgeProcessInstance {
inner: inner_process_module,
})
}
#[cfg(all(target_os = "linux", feature = "wasi_nn", target_arch = "x86_64"))]
pub fn wasi_nn_module(&mut self) -> WasmEdgeResult<WasiNnInstance> {
let inner_wasi_nn_module = self.inner.wasi_nn_module()?;
Ok(WasiNnInstance {
inner: inner_wasi_nn_module,
})
}
#[cfg(all(target_os = "linux", feature = "wasi_crypto"))]
pub fn wasi_crypto_common_module(&mut self) -> WasmEdgeResult<WasiCryptoCommonInstance> {
let inner_wasi_crypto_common_module = self.inner.wasi_crypto_common_module()?;
Ok(WasiCryptoCommonInstance {
inner: inner_wasi_crypto_common_module,
})
}
#[cfg(all(target_os = "linux", feature = "wasi_crypto"))]
pub fn wasi_crypto_asymmetric_common_module(
&mut self,
) -> WasmEdgeResult<WasiCryptoAsymmetricCommonInstance> {
let inner_wasi_crypto_asymmetric_common_module =
self.inner.wasi_crypto_asymmetric_common_module()?;
Ok(WasiCryptoAsymmetricCommonInstance {
inner: inner_wasi_crypto_asymmetric_common_module,
})
}
#[cfg(all(target_os = "linux", feature = "wasi_crypto"))]
pub fn wasi_crypto_symmetric_module(&mut self) -> WasmEdgeResult<WasiCryptoSymmetricInstance> {
let inner_wasi_crypto_symmetric_module = self.inner.wasi_crypto_symmetric_module()?;
Ok(WasiCryptoSymmetricInstance {
inner: inner_wasi_crypto_symmetric_module,
})
}
#[cfg(all(target_os = "linux", feature = "wasi_crypto"))]
pub fn wasi_crypto_kx_module(&mut self) -> WasmEdgeResult<WasiCryptoKxInstance> {
let inner_wasi_crypto_kx_module = self.inner.wasi_crypto_kx_module()?;
Ok(WasiCryptoKxInstance {
inner: inner_wasi_crypto_kx_module,
})
}
#[cfg(all(target_os = "linux", feature = "wasi_crypto"))]
pub fn wasi_crypto_signatures_module(
&mut self,
) -> WasmEdgeResult<WasiCryptoSignaturesInstance> {
let inner_wasi_crypto_signatures_module = self.inner.wasi_crypto_signatures_module()?;
Ok(WasiCryptoSignaturesInstance {
inner: inner_wasi_crypto_signatures_module,
})
}
pub fn contains_module(&self, mod_name: impl AsRef<str>) -> bool {
self.inner.contains_module(mod_name.as_ref())
}
}
impl Engine for Vm {
fn run_func(
&self,
func: &Func,
params: impl IntoIterator<Item = WasmValue>,
) -> WasmEdgeResult<Vec<WasmValue>> {
let executor = self.inner.executor()?;
let returns = executor.run_func(&func.inner, params)?;
Ok(returns)
}
fn run_func_ref(
&self,
func_ref: &FuncRef,
params: impl IntoIterator<Item = WasmValue>,
) -> WasmEdgeResult<Vec<WasmValue>> {
let executor = self.inner.executor()?;
let returns = executor.run_func_ref(&func_ref.inner, params)?;
Ok(returns)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(target_os = "linux")]
use crate::PluginManager;
use crate::{
config::{
CommonConfigOptions, ConfigBuilder, HostRegistrationConfigOptions,
StatisticsConfigOptions,
},
error::HostFuncError,
io::WasmVal,
params,
types::Val,
wat2wasm, AsInstance, CallingFrame, Global, GlobalType, ImportObjectBuilder, Memory,
MemoryType, Mutability, RefType, Table, TableType, ValType, WasmValue,
};
#[test]
fn test_vm_run_func_from_file() {
let result = Vm::new(None);
assert!(result.is_ok());
let vm = result.unwrap();
let file = std::path::PathBuf::from(env!("WASMEDGE_DIR"))
.join("bindings/rust/wasmedge-sdk/examples/data/fibonacci.wat");
let result = vm.run_func_from_file(file, "fib", params!(10));
assert!(result.is_ok());
let returns = result.unwrap();
assert_eq!(returns.len(), 1);
assert_eq!(returns[0].to_i32(), 89);
}
#[test]
fn test_vm_run_func_from_bytes() {
let result = Vm::new(None);
assert!(result.is_ok());
let vm = result.unwrap();
let result = wat2wasm(
br#"(module
(export "fib" (func $fib))
(func $fib (param $n i32) (result i32)
(if
(i32.lt_s
(get_local $n)
(i32.const 2)
)
(return
(i32.const 1)
)
)
(return
(i32.add
(call $fib
(i32.sub
(get_local $n)
(i32.const 2)
)
)
(call $fib
(i32.sub
(get_local $n)
(i32.const 1)
)
)
)
)
)
)
"#,
);
assert!(result.is_ok());
let wasm_bytes = result.unwrap();
let result = vm.run_func_from_bytes(&wasm_bytes, "fib", params!(10));
assert!(result.is_ok());
let returns = result.unwrap();
assert_eq!(returns.len(), 1);
assert_eq!(returns[0].to_i32(), 89);
}
#[test]
fn test_vm_run_func_from_module() {
let result = Vm::new(None);
assert!(result.is_ok());
let vm = result.unwrap();
let result = wat2wasm(
br#"(module
(export "fib" (func $fib))
(func $fib (param $n i32) (result i32)
(if
(i32.lt_s
(get_local $n)
(i32.const 2)
)
(return
(i32.const 1)
)
)
(return
(i32.add
(call $fib
(i32.sub
(get_local $n)
(i32.const 2)
)
)
(call $fib
(i32.sub
(get_local $n)
(i32.const 1)
)
)
)
)
)
)
"#,
);
assert!(result.is_ok());
let wasm_bytes = result.unwrap();
let result = Module::from_bytes(None, wasm_bytes);
assert!(result.is_ok());
let module = result.unwrap();
let result = vm.run_func_from_module(module, "fib", params!(10));
assert!(result.is_ok());
let returns = result.unwrap();
assert_eq!(returns.len(), 1);
assert_eq!(returns[0].to_i32(), 89);
}
#[test]
fn test_vm_run_func_in_named_module_instance() {
let result = Vm::new(None);
assert!(result.is_ok());
let vm = result.unwrap();
let result = wat2wasm(
br#"(module
(export "fib" (func $fib))
(func $fib (param $n i32) (result i32)
(if
(i32.lt_s
(get_local $n)
(i32.const 2)
)
(return
(i32.const 1)
)
)
(return
(i32.add
(call $fib
(i32.sub
(get_local $n)
(i32.const 2)
)
)
(call $fib
(i32.sub
(get_local $n)
(i32.const 1)
)
)
)
)
)
)
"#,
);
assert!(result.is_ok());
let wasm_bytes = result.unwrap();
let result = vm.register_module_from_bytes("extern", wasm_bytes);
assert!(result.is_ok());
let mut vm = result.unwrap();
let result = vm.func_ty(Some("extern"), "fib");
assert!(result.is_ok());
let func_ty = result.unwrap();
assert_eq!(func_ty.args_len(), 1);
let args = func_ty.args();
assert!(args.is_some());
let args = args.unwrap();
assert_eq!(args, [ValType::I32]);
assert_eq!(func_ty.returns_len(), 1);
let returns = func_ty.returns();
assert!(returns.is_some());
let returns = returns.unwrap();
assert_eq!(returns, [ValType::I32]);
let result = vm.run_func(Some("extern"), "fib", params!(10));
assert!(result.is_ok());
let returns = result.unwrap();
assert_eq!(returns.len(), 1);
assert_eq!(returns[0].to_i32(), 89);
}
#[test]
fn test_vm_run_func_in_active_module_instance() {
let result = Vm::new(None);
assert!(result.is_ok());
let vm = result.unwrap();
let result = wat2wasm(
br#"(module
(export "fib" (func $fib))
(func $fib (param $n i32) (result i32)
(if
(i32.lt_s
(get_local $n)
(i32.const 2)
)
(return
(i32.const 1)
)
)
(return
(i32.add
(call $fib
(i32.sub
(get_local $n)
(i32.const 2)
)
)
(call $fib
(i32.sub
(get_local $n)
(i32.const 1)
)
)
)
)
)
)
"#,
);
assert!(result.is_ok());
let wasm_bytes = result.unwrap();
let result = Module::from_bytes(None, wasm_bytes);
assert!(result.is_ok());
let module = result.unwrap();
let result = vm.register_module(None, module);
assert!(result.is_ok());
let mut vm = result.unwrap();
let result = vm.func_ty(None, "fib");
assert!(result.is_ok());
let func_ty = result.unwrap();
assert_eq!(func_ty.args_len(), 1);
let args = func_ty.args();
assert!(args.is_some());
let args = args.unwrap();
assert_eq!(args, [ValType::I32]);
assert_eq!(func_ty.returns_len(), 1);
let returns = func_ty.returns();
assert!(returns.is_some());
let returns = returns.unwrap();
assert_eq!(returns, [ValType::I32]);
let result = vm.run_func(None, "fib", params!(10));
assert!(result.is_ok());
let returns = result.unwrap();
assert_eq!(returns.len(), 1);
assert_eq!(returns[0].to_i32(), 89);
}
#[test]
#[allow(clippy::assertions_on_result_states)]
fn test_vm_create() {
{
let result = Vm::new(None);
assert!(result.is_ok());
}
{
let result = ConfigBuilder::new(CommonConfigOptions::default()).build();
assert!(result.is_ok());
let config = result.unwrap();
let result = Vm::new(Some(config));
assert!(result.is_ok());
let vm = result.unwrap();
let result = vm.statistics();
assert!(result.is_ok());
}
}
#[test]
fn test_vm_wasi_module() {
let host_reg_options = HostRegistrationConfigOptions::default().wasi(true);
let result = ConfigBuilder::new(CommonConfigOptions::default())
.with_host_registration_config(host_reg_options)
.build();
assert!(result.is_ok());
let config = result.unwrap();
let result = Vm::new(Some(config));
assert!(result.is_ok());
let mut vm = result.unwrap();
let result = vm.wasi_module();
assert!(result.is_ok());
let wasi_instance = result.unwrap();
assert_eq!(wasi_instance.name(), "wasi_snapshot_preview1");
}
#[test]
#[cfg(target_os = "linux")]
fn test_vm_wasmedge_process_module() {
PluginManager::load_from_default_paths();
let host_reg_options = HostRegistrationConfigOptions::default().wasmedge_process(true);
let result = ConfigBuilder::new(CommonConfigOptions::default())
.with_host_registration_config(host_reg_options)
.build();
assert!(result.is_ok());
let config = result.unwrap();
let result = Vm::new(Some(config));
assert!(result.is_ok());
let mut vm = result.unwrap();
let result = vm.wasmedge_process_module();
assert!(result.is_ok());
let wasmedge_process_instance = result.unwrap();
assert_eq!(wasmedge_process_instance.name(), "wasmedge_process");
}
#[test]
fn test_vm_statistics() {
let stat_config_options = StatisticsConfigOptions::new()
.measure_cost(true)
.measure_time(true)
.count_instructions(true);
let result = ConfigBuilder::new(CommonConfigOptions::default())
.with_statistics_config(stat_config_options)
.build();
assert!(result.is_ok());
let config = result.unwrap();
let result = Vm::new(Some(config));
assert!(result.is_ok());
let _vm = result.unwrap();
}
#[test]
#[allow(clippy::assertions_on_result_states)]
fn test_vm_register_module_from_file() {
{
let result = Vm::new(None);
assert!(result.is_ok());
let vm = result.unwrap();
let file = std::path::PathBuf::from(env!("WASMEDGE_DIR"))
.join("bindings/rust/wasmedge-sdk/examples/data/fibonacci.wat");
let result = vm.register_module_from_file("extern", file);
assert!(result.is_ok());
let vm = result.unwrap();
assert_eq!(vm.named_instance_count().unwrap(), 1);
assert!(vm.instance_names().is_ok());
assert_eq!(vm.instance_names().unwrap(), ["extern"]);
}
{
let result = Vm::new(None);
assert!(result.is_ok());
let vm = result.unwrap();
let file = std::path::PathBuf::from(env!("WASMEDGE_DIR"))
.join("bindings/rust/wasmedge-sys/tests/data/fibonacci.wat");
let result = vm.register_module_from_file("extern", file);
assert!(result.is_ok());
let vm = result.unwrap();
assert_eq!(vm.named_instance_count().unwrap(), 1);
assert!(vm.instance_names().is_ok());
assert_eq!(vm.instance_names().unwrap(), ["extern"]);
}
}
#[test]
#[allow(clippy::assertions_on_result_states)]
fn test_vm_register_module_from_bytes() {
let result = Vm::new(None);
assert!(result.is_ok());
let vm = result.unwrap();
let result = wat2wasm(
br#"(module
(export "fib" (func $fib))
(func $fib (param $n i32) (result i32)
(if
(i32.lt_s
(get_local $n)
(i32.const 2)
)
(return
(i32.const 1)
)
)
(return
(i32.add
(call $fib
(i32.sub
(get_local $n)
(i32.const 2)
)
)
(call $fib
(i32.sub
(get_local $n)
(i32.const 1)
)
)
)
)
)
)
"#,
);
assert!(result.is_ok());
let wasm_bytes = result.unwrap();
let result = vm.register_module_from_bytes("extern", wasm_bytes);
assert!(result.is_ok());
let vm = result.unwrap();
assert_eq!(vm.named_instance_count().unwrap(), 1);
assert!(vm.instance_names().is_ok());
assert_eq!(vm.instance_names().unwrap(), ["extern"]);
}
#[test]
#[allow(clippy::assertions_on_result_states)]
fn test_vm_register_import_module() {
let result = Global::new(
GlobalType::new(ValType::F32, Mutability::Const),
Val::F32(3.5),
);
assert!(result.is_ok());
let global_const = result.unwrap();
let result = MemoryType::new(10, None, false);
assert!(result.is_ok());
let memory_type = result.unwrap();
let result = Memory::new(memory_type);
assert!(result.is_ok());
let memory = result.unwrap();
let result = Table::new(TableType::new(RefType::FuncRef, 5, None));
assert!(result.is_ok());
let table = result.unwrap();
let result = ImportObjectBuilder::new()
.with_func::<(i32, i32), i32>("add", real_add)
.expect("failed to add host function")
.with_global("global", global_const)
.expect("failed to add const global")
.with_memory("mem", memory)
.expect("failed to add memory")
.with_table("table", table)
.expect("failed to add table")
.build("extern-module");
assert!(result.is_ok());
let import = result.unwrap();
let result = Vm::new(None);
assert!(result.is_ok());
let vm = result.unwrap();
let result = vm.register_import_module(import);
assert!(result.is_ok());
let vm = result.unwrap();
assert_eq!(vm.named_instance_count().unwrap(), 1);
assert!(vm.instance_names().is_ok());
assert_eq!(vm.instance_names().unwrap(), ["extern-module"]);
let result = vm.named_module("extern-module");
assert!(result.is_ok());
let instance = result.unwrap();
assert!(instance.name().is_some());
assert_eq!(instance.name().unwrap(), "extern-module");
let result = instance.global("global");
assert!(result.is_some());
let global = result.unwrap();
let result = global.ty();
assert!(result.is_ok());
}
#[test]
fn test_vm_register_named_module() {
let result = Vm::new(None);
assert!(result.is_ok());
let vm = result.unwrap();
let result = wat2wasm(
br#"(module
(export "fib" (func $fib))
(func $fib (param $n i32) (result i32)
(if
(i32.lt_s
(get_local $n)
(i32.const 2)
)
(return
(i32.const 1)
)
)
(return
(i32.add
(call $fib
(i32.sub
(get_local $n)
(i32.const 2)
)
)
(call $fib
(i32.sub
(get_local $n)
(i32.const 1)
)
)
)
)
)
)
"#,
);
assert!(result.is_ok());
let wasm_bytes = result.unwrap();
let result = Module::from_bytes(None, wasm_bytes);
assert!(result.is_ok());
let module = result.unwrap();
assert_eq!(vm.named_instance_count().unwrap(), 0);
let result = vm.register_module(Some("extern"), module);
assert!(result.is_ok());
let vm = result.unwrap();
assert_eq!(vm.named_instance_count().unwrap(), 1);
let result = vm.named_module("extern");
assert!(result.is_ok());
let instance = result.unwrap();
assert_eq!(instance.func_count(), 1);
let result = instance.func_names();
assert!(result.is_some());
let func_names = result.unwrap();
assert_eq!(func_names, ["fib"]);
let result = instance.func("fib");
assert!(result.is_some());
let fib = result.unwrap();
let result = fib.ty();
assert!(result.is_ok());
let signature = result.unwrap();
assert!(signature.args().is_some());
assert_eq!(signature.args().unwrap(), [ValType::I32]);
assert!(signature.returns().is_some());
assert_eq!(signature.returns().unwrap(), [ValType::I32]);
}
#[test]
fn test_vm_register_active_module() {
let result = Vm::new(None);
assert!(result.is_ok());
let vm = result.unwrap();
let result = wat2wasm(
br#"(module
(export "fib" (func $fib))
(func $fib (param $n i32) (result i32)
(if
(i32.lt_s
(get_local $n)
(i32.const 2)
)
(return
(i32.const 1)
)
)
(return
(i32.add
(call $fib
(i32.sub
(get_local $n)
(i32.const 2)
)
)
(call $fib
(i32.sub
(get_local $n)
(i32.const 1)
)
)
)
)
)
)
"#,
);
assert!(result.is_ok());
let wasm_bytes = result.unwrap();
let result = Module::from_bytes(None, wasm_bytes);
assert!(result.is_ok());
let module = result.unwrap();
let result = vm.register_module(None, module);
assert!(result.is_ok());
let vm = result.unwrap();
let result = vm.active_module();
assert!(result.is_ok());
let instance = result.unwrap();
assert_eq!(instance.func_count(), 1);
let result = instance.func_names();
assert!(result.is_some());
let func_names = result.unwrap();
assert_eq!(func_names, ["fib"]);
let result = instance.func("fib");
assert!(result.is_some());
let fib = result.unwrap();
let result = fib.ty();
assert!(result.is_ok());
let signature = result.unwrap();
assert!(signature.args().is_some());
assert_eq!(signature.args().unwrap(), [ValType::I32]);
assert!(signature.returns().is_some());
assert_eq!(signature.returns().unwrap(), [ValType::I32]);
}
#[test]
fn test_vm_impl_engine_trait() {
let result = ConfigBuilder::new(CommonConfigOptions::default()).build();
assert!(result.is_ok());
let config = result.unwrap();
let result = Vm::new(Some(config));
assert!(result.is_ok());
let vm = result.unwrap();
let result = wat2wasm(
br#"
(module
(export "fib" (func $fib))
(func $fib (param $n i32) (result i32)
(if
(i32.lt_s
(get_local $n)
(i32.const 2)
)
(return
(i32.const 1)
)
)
(return
(i32.add
(call $fib
(i32.sub
(get_local $n)
(i32.const 2)
)
)
(call $fib
(i32.sub
(get_local $n)
(i32.const 1)
)
)
)
)
)
)
"#,
);
assert!(result.is_ok());
let wasm_bytes = result.unwrap();
let result = vm.register_module_from_bytes("extern", wasm_bytes);
assert!(result.is_ok());
let mut vm = result.unwrap();
let result = vm.named_module("extern");
assert!(result.is_ok());
let instance = result.unwrap();
let result = instance.func("fib");
assert!(result.is_some());
let fib = result.unwrap();
let result = fib.call(&mut vm, params!(5));
assert!(result.is_ok());
let returns = result.unwrap();
assert_eq!(returns[0].to_i32(), 8)
}
fn real_add(
_frame: CallingFrame,
inputs: Vec<WasmValue>,
) -> std::result::Result<Vec<WasmValue>, HostFuncError> {
if inputs.len() != 2 {
return Err(HostFuncError::User(1));
}
let a = if inputs[0].ty() == ValType::I32 {
inputs[0].to_i32()
} else {
return Err(HostFuncError::User(2));
};
let b = if inputs[1].ty() == ValType::I32 {
inputs[1].to_i32()
} else {
return Err(HostFuncError::User(3));
};
let c = a + b;
Ok(vec![WasmValue::from_i32(c)])
}
}