Added basic example of Wasmer-js

This commit is contained in:
Syrus Akbary
2021-06-21 21:14:16 -07:00
parent 7ddf61a3db
commit 430113dbc2
30 changed files with 7558 additions and 0 deletions

334
lib/js-api/tests/export.rs Normal file
View File

@@ -0,0 +1,334 @@
// use anyhow::Result;
// use wasmer::*;
// use wasmer_vm::WeakOrStrongInstanceRef;
// const MEM_WAT: &str = "
// (module
// (func $host_fn (import \"env\" \"host_fn\") (param) (result))
// (func (export \"call_host_fn\") (param) (result)
// (call $host_fn))
// (memory $mem 0)
// (export \"memory\" (memory $mem))
// )
// ";
// const GLOBAL_WAT: &str = "
// (module
// (func $host_fn (import \"env\" \"host_fn\") (param) (result))
// (func (export \"call_host_fn\") (param) (result)
// (call $host_fn))
// (global $global i32 (i32.const 11))
// (export \"global\" (global $global))
// )
// ";
// const TABLE_WAT: &str = "
// (module
// (func $host_fn (import \"env\" \"host_fn\") (param) (result))
// (func (export \"call_host_fn\") (param) (result)
// (call $host_fn))
// (table $table 4 4 funcref)
// (export \"table\" (table $table))
// )
// ";
// const FUNCTION_WAT: &str = "
// (module
// (func $host_fn (import \"env\" \"host_fn\") (param) (result))
// (func (export \"call_host_fn\") (param) (result)
// (call $host_fn))
// )
// ";
// fn is_memory_instance_ref_strong(memory: &Memory) -> Option<bool> {
// // This is safe because we're calling it from a test to test the internals
// unsafe {
// memory
// .get_vm_memory()
// .instance_ref
// .as_ref()
// .map(|v| matches!(v, WeakOrStrongInstanceRef::Strong(_)))
// }
// }
// fn is_table_instance_ref_strong(table: &Table) -> Option<bool> {
// // This is safe because we're calling it from a test to test the internals
// unsafe {
// table
// .get_vm_table()
// .instance_ref
// .as_ref()
// .map(|v| matches!(v, WeakOrStrongInstanceRef::Strong(_)))
// }
// }
// fn is_global_instance_ref_strong(global: &Global) -> Option<bool> {
// // This is safe because we're calling it from a test to test the internals
// unsafe {
// global
// .get_vm_global()
// .instance_ref
// .as_ref()
// .map(|v| matches!(v, WeakOrStrongInstanceRef::Strong(_)))
// }
// }
// fn is_function_instance_ref_strong(f: &Function) -> Option<bool> {
// // This is safe because we're calling it from a test to test the internals
// unsafe {
// f.get_vm_function()
// .instance_ref
// .as_ref()
// .map(|v| matches!(v, WeakOrStrongInstanceRef::Strong(_)))
// }
// }
// fn is_native_function_instance_ref_strong<Args, Rets>(f: &NativeFunc<Args, Rets>) -> Option<bool>
// where
// Args: WasmTypeList,
// Rets: WasmTypeList,
// {
// // This is safe because we're calling it from a test to test the internals
// unsafe {
// f.get_vm_function()
// .instance_ref
// .as_ref()
// .map(|v| matches!(v, WeakOrStrongInstanceRef::Strong(_)))
// }
// }
// #[test]
// fn strong_weak_behavior_works_memory() -> Result<()> {
// #[derive(Clone, Debug, WasmerEnv, Default)]
// struct MemEnv {
// #[wasmer(export)]
// memory: LazyInit<Memory>,
// }
// let host_fn = |env: &MemEnv| {
// let mem = env.memory_ref().unwrap();
// assert_eq!(is_memory_instance_ref_strong(&mem), Some(false));
// let mem_clone = mem.clone();
// assert_eq!(is_memory_instance_ref_strong(&mem_clone), Some(true));
// assert_eq!(is_memory_instance_ref_strong(&mem), Some(false));
// };
// let f: NativeFunc<(), ()> = {
// let store = Store::default();
// let module = Module::new(&store, MEM_WAT)?;
// let env = MemEnv::default();
// let instance = Instance::new(
// &module,
// &imports! {
// "env" => {
// "host_fn" => Function::new_native_with_env(&store, env, host_fn)
// }
// },
// )?;
// {
// let mem = instance.exports.get_memory("memory")?;
// assert_eq!(is_memory_instance_ref_strong(&mem), Some(true));
// }
// let f: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_fn")?;
// f.call()?;
// f
// };
// f.call()?;
// Ok(())
// }
// #[test]
// fn strong_weak_behavior_works_global() -> Result<()> {
// #[derive(Clone, Debug, WasmerEnv, Default)]
// struct GlobalEnv {
// #[wasmer(export)]
// global: LazyInit<Global>,
// }
// let host_fn = |env: &GlobalEnv| {
// let global = env.global_ref().unwrap();
// assert_eq!(is_global_instance_ref_strong(&global), Some(false));
// let global_clone = global.clone();
// assert_eq!(is_global_instance_ref_strong(&global_clone), Some(true));
// assert_eq!(is_global_instance_ref_strong(&global), Some(false));
// };
// let f: NativeFunc<(), ()> = {
// let store = Store::default();
// let module = Module::new(&store, GLOBAL_WAT)?;
// let env = GlobalEnv::default();
// let instance = Instance::new(
// &module,
// &imports! {
// "env" => {
// "host_fn" => Function::new_native_with_env(&store, env, host_fn)
// }
// },
// )?;
// {
// let global = instance.exports.get_global("global")?;
// assert_eq!(is_global_instance_ref_strong(&global), Some(true));
// }
// let f: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_fn")?;
// f.call()?;
// f
// };
// f.call()?;
// Ok(())
// }
// #[test]
// fn strong_weak_behavior_works_table() -> Result<()> {
// #[derive(Clone, WasmerEnv, Default)]
// struct TableEnv {
// #[wasmer(export)]
// table: LazyInit<Table>,
// }
// let host_fn = |env: &TableEnv| {
// let table = env.table_ref().unwrap();
// assert_eq!(is_table_instance_ref_strong(&table), Some(false));
// let table_clone = table.clone();
// assert_eq!(is_table_instance_ref_strong(&table_clone), Some(true));
// assert_eq!(is_table_instance_ref_strong(&table), Some(false));
// };
// let f: NativeFunc<(), ()> = {
// let store = Store::default();
// let module = Module::new(&store, TABLE_WAT)?;
// let env = TableEnv::default();
// let instance = Instance::new(
// &module,
// &imports! {
// "env" => {
// "host_fn" => Function::new_native_with_env(&store, env, host_fn)
// }
// },
// )?;
// {
// let table = instance.exports.get_table("table")?;
// assert_eq!(is_table_instance_ref_strong(&table), Some(true));
// }
// let f: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_fn")?;
// f.call()?;
// f
// };
// f.call()?;
// Ok(())
// }
// #[test]
// fn strong_weak_behavior_works_function() -> Result<()> {
// #[derive(Clone, WasmerEnv, Default)]
// struct FunctionEnv {
// #[wasmer(export)]
// call_host_fn: LazyInit<Function>,
// }
// let host_fn = |env: &FunctionEnv| {
// let function = env.call_host_fn_ref().unwrap();
// assert_eq!(is_function_instance_ref_strong(&function), Some(false));
// let function_clone = function.clone();
// assert_eq!(is_function_instance_ref_strong(&function_clone), Some(true));
// assert_eq!(is_function_instance_ref_strong(&function), Some(false));
// };
// let f: NativeFunc<(), ()> = {
// let store = Store::default();
// let module = Module::new(&store, FUNCTION_WAT)?;
// let env = FunctionEnv::default();
// let instance = Instance::new(
// &module,
// &imports! {
// "env" => {
// "host_fn" => Function::new_native_with_env(&store, env, host_fn)
// }
// },
// )?;
// {
// let function = instance.exports.get_function("call_host_fn")?;
// assert_eq!(is_function_instance_ref_strong(&function), Some(true));
// }
// let f: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_fn")?;
// f.call()?;
// f
// };
// f.call()?;
// Ok(())
// }
// #[test]
// fn strong_weak_behavior_works_native_function() -> Result<()> {
// #[derive(Clone, WasmerEnv, Default)]
// struct FunctionEnv {
// #[wasmer(export)]
// call_host_fn: LazyInit<NativeFunc<(), ()>>,
// }
// let host_fn = |env: &FunctionEnv| {
// let function = env.call_host_fn_ref().unwrap();
// assert_eq!(
// is_native_function_instance_ref_strong(&function),
// Some(false)
// );
// let function_clone = function.clone();
// assert_eq!(
// is_native_function_instance_ref_strong(&function_clone),
// Some(true)
// );
// assert_eq!(
// is_native_function_instance_ref_strong(&function),
// Some(false)
// );
// };
// let f: NativeFunc<(), ()> = {
// let store = Store::default();
// let module = Module::new(&store, FUNCTION_WAT)?;
// let env = FunctionEnv::default();
// let instance = Instance::new(
// &module,
// &imports! {
// "env" => {
// "host_fn" => Function::new_native_with_env(&store, env, host_fn)
// }
// },
// )?;
// {
// let function: NativeFunc<(), ()> =
// instance.exports.get_native_function("call_host_fn")?;
// assert_eq!(
// is_native_function_instance_ref_strong(&function),
// Some(true)
// );
// }
// let f: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_fn")?;
// f.call()?;
// f
// };
// f.call()?;
// Ok(())
// }

View File

@@ -0,0 +1,458 @@
use wasm_bindgen_test::*;
// use anyhow::Result;
use wasmer_js::*;
// #[test]
// fn global_new() -> Result<()> {
// let store = Store::default();
// let global = Global::new(&store, Value::I32(10));
// assert_eq!(
// *global.ty(),
// GlobalType {
// ty: Type::I32,
// mutability: Mutability::Const
// }
// );
// let global_mut = Global::new_mut(&store, Value::I32(10));
// assert_eq!(
// *global_mut.ty(),
// GlobalType {
// ty: Type::I32,
// mutability: Mutability::Var
// }
// );
// Ok(())
// }
// #[test]
// fn global_get() -> Result<()> {
// let store = Store::default();
// let global_i32 = Global::new(&store, Value::I32(10));
// assert_eq!(global_i32.get(), Value::I32(10));
// let global_i64 = Global::new(&store, Value::I64(20));
// assert_eq!(global_i64.get(), Value::I64(20));
// let global_f32 = Global::new(&store, Value::F32(10.0));
// assert_eq!(global_f32.get(), Value::F32(10.0));
// let global_f64 = Global::new(&store, Value::F64(20.0));
// assert_eq!(global_f64.get(), Value::F64(20.0));
// Ok(())
// }
// #[test]
// fn global_set() -> Result<()> {
// let store = Store::default();
// let global_i32 = Global::new(&store, Value::I32(10));
// // Set on a constant should error
// assert!(global_i32.set(Value::I32(20)).is_err());
// let global_i32_mut = Global::new_mut(&store, Value::I32(10));
// // Set on different type should error
// assert!(global_i32_mut.set(Value::I64(20)).is_err());
// // Set on same type should succeed
// global_i32_mut.set(Value::I32(20))?;
// assert_eq!(global_i32_mut.get(), Value::I32(20));
// Ok(())
// }
// #[test]
// fn table_new() -> Result<()> {
// let store = Store::default();
// let table_type = TableType {
// ty: Type::FuncRef,
// minimum: 0,
// maximum: None,
// };
// let f = Function::new_native(&store, || {});
// let table = Table::new(&store, table_type, Value::FuncRef(Some(f)))?;
// assert_eq!(*table.ty(), table_type);
// // Anyrefs not yet supported
// // let table_type = TableType {
// // ty: Type::ExternRef,
// // minimum: 0,
// // maximum: None,
// // };
// // let table = Table::new(&store, table_type, Value::ExternRef(ExternRef::Null))?;
// // assert_eq!(*table.ty(), table_type);
// Ok(())
// }
// #[test]
// #[ignore]
// fn table_get() -> Result<()> {
// let store = Store::default();
// let table_type = TableType {
// ty: Type::FuncRef,
// minimum: 0,
// maximum: Some(1),
// };
// let f = Function::new_native(&store, |num: i32| num + 1);
// let table = Table::new(&store, table_type, Value::FuncRef(Some(f.clone())))?;
// assert_eq!(*table.ty(), table_type);
// let _elem = table.get(0).unwrap();
// // assert_eq!(elem.funcref().unwrap(), f);
// Ok(())
// }
// #[test]
// #[ignore]
// fn table_set() -> Result<()> {
// // Table set not yet tested
// Ok(())
// }
// #[test]
// fn table_grow() -> Result<()> {
// let store = Store::default();
// let table_type = TableType {
// ty: Type::FuncRef,
// minimum: 0,
// maximum: Some(10),
// };
// let f = Function::new_native(&store, |num: i32| num + 1);
// let table = Table::new(&store, table_type, Value::FuncRef(Some(f.clone())))?;
// // Growing to a bigger maximum should return None
// let old_len = table.grow(12, Value::FuncRef(Some(f.clone())));
// assert!(old_len.is_err());
// // Growing to a bigger maximum should return None
// let old_len = table.grow(5, Value::FuncRef(Some(f.clone())))?;
// assert_eq!(old_len, 0);
// Ok(())
// }
// #[test]
// #[ignore]
// fn table_copy() -> Result<()> {
// // TODO: table copy test not yet implemented
// Ok(())
// }
#[wasm_bindgen_test]
fn memory_new() {
let store = Store::default();
let memory_type = MemoryType {
shared: false,
minimum: Pages(0),
maximum: Some(Pages(10)),
};
let memory = Memory::new(&store, memory_type).unwrap();
assert_eq!(memory.size(), Pages(0));
assert_eq!(memory.ty(), memory_type);
}
#[wasm_bindgen_test]
fn memory_grow() {
let store = Store::default();
let desc = MemoryType::new(Pages(10), Some(Pages(16)), false);
let memory = Memory::new(&store, desc).unwrap();
assert_eq!(memory.size(), Pages(10));
let result = memory.grow(Pages(2)).unwrap();
assert_eq!(result, Pages(10));
assert_eq!(memory.size(), Pages(12));
// let result = memory.grow(Pages(10));
// assert!(result.is_err());
// assert_eq!(
// result,
// Err(MemoryError::CouldNotGrow {
// current: 12.into(),
// attempted_delta: 10.into()
// })
// );
// let bad_desc = MemoryType::new(Pages(15), Some(Pages(10)), false);
// let bad_result = Memory::new(&store, bad_desc);
// // assert!(matches!(bad_result, Err(MemoryError::InvalidMemory { .. })));
// assert!(bad_result.is_err());
}
// #[test]
// fn function_new() -> Result<()> {
// let store = Store::default();
// let function = Function::new_native(&store, || {});
// assert_eq!(function.ty().clone(), FunctionType::new(vec![], vec![]));
// let function = Function::new_native(&store, |_a: i32| {});
// assert_eq!(
// function.ty().clone(),
// FunctionType::new(vec![Type::I32], vec![])
// );
// let function = Function::new_native(&store, |_a: i32, _b: i64, _c: f32, _d: f64| {});
// assert_eq!(
// function.ty().clone(),
// FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![])
// );
// let function = Function::new_native(&store, || -> i32 { 1 });
// assert_eq!(
// function.ty().clone(),
// FunctionType::new(vec![], vec![Type::I32])
// );
// let function = Function::new_native(&store, || -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) });
// assert_eq!(
// function.ty().clone(),
// FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64])
// );
// Ok(())
// }
// #[test]
// fn function_new_env() -> Result<()> {
// let store = Store::default();
// #[derive(Clone, WasmerEnv)]
// struct MyEnv {}
// let my_env = MyEnv {};
// let function = Function::new_native_with_env(&store, my_env.clone(), |_env: &MyEnv| {});
// assert_eq!(function.ty().clone(), FunctionType::new(vec![], vec![]));
// let function =
// Function::new_native_with_env(&store, my_env.clone(), |_env: &MyEnv, _a: i32| {});
// assert_eq!(
// function.ty().clone(),
// FunctionType::new(vec![Type::I32], vec![])
// );
// let function = Function::new_native_with_env(
// &store,
// my_env.clone(),
// |_env: &MyEnv, _a: i32, _b: i64, _c: f32, _d: f64| {},
// );
// assert_eq!(
// function.ty().clone(),
// FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![])
// );
// let function =
// Function::new_native_with_env(&store, my_env.clone(), |_env: &MyEnv| -> i32 { 1 });
// assert_eq!(
// function.ty().clone(),
// FunctionType::new(vec![], vec![Type::I32])
// );
// let function = Function::new_native_with_env(
// &store,
// my_env.clone(),
// |_env: &MyEnv| -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) },
// );
// assert_eq!(
// function.ty().clone(),
// FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64])
// );
// Ok(())
// }
// #[test]
// fn function_new_dynamic() -> Result<()> {
// let store = Store::default();
// // Using &FunctionType signature
// let function_type = FunctionType::new(vec![], vec![]);
// let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
// assert_eq!(function.ty().clone(), function_type);
// let function_type = FunctionType::new(vec![Type::I32], vec![]);
// let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
// assert_eq!(function.ty().clone(), function_type);
// let function_type = FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]);
// let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
// assert_eq!(function.ty().clone(), function_type);
// let function_type = FunctionType::new(vec![], vec![Type::I32]);
// let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
// assert_eq!(function.ty().clone(), function_type);
// let function_type = FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]);
// let function = Function::new(&store, &function_type, |_values: &[Value]| unimplemented!());
// assert_eq!(function.ty().clone(), function_type);
// // Using array signature
// let function_type = ([Type::V128], [Type::I32, Type::F32, Type::F64]);
// let function = Function::new(&store, function_type, |_values: &[Value]| unimplemented!());
// assert_eq!(function.ty().params(), [Type::V128]);
// assert_eq!(function.ty().results(), [Type::I32, Type::F32, Type::F64]);
// Ok(())
// }
// #[test]
// fn function_new_dynamic_env() -> Result<()> {
// let store = Store::default();
// #[derive(Clone, WasmerEnv)]
// struct MyEnv {}
// let my_env = MyEnv {};
// // Using &FunctionType signature
// let function_type = FunctionType::new(vec![], vec![]);
// let function = Function::new_with_env(
// &store,
// &function_type,
// my_env.clone(),
// |_env: &MyEnv, _values: &[Value]| unimplemented!(),
// );
// assert_eq!(function.ty().clone(), function_type);
// let function_type = FunctionType::new(vec![Type::I32], vec![]);
// let function = Function::new_with_env(
// &store,
// &function_type,
// my_env.clone(),
// |_env: &MyEnv, _values: &[Value]| unimplemented!(),
// );
// assert_eq!(function.ty().clone(), function_type);
// let function_type = FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]);
// let function = Function::new_with_env(
// &store,
// &function_type,
// my_env.clone(),
// |_env: &MyEnv, _values: &[Value]| unimplemented!(),
// );
// assert_eq!(function.ty().clone(), function_type);
// let function_type = FunctionType::new(vec![], vec![Type::I32]);
// let function = Function::new_with_env(
// &store,
// &function_type,
// my_env.clone(),
// |_env: &MyEnv, _values: &[Value]| unimplemented!(),
// );
// assert_eq!(function.ty().clone(), function_type);
// let function_type = FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]);
// let function = Function::new_with_env(
// &store,
// &function_type,
// my_env.clone(),
// |_env: &MyEnv, _values: &[Value]| unimplemented!(),
// );
// assert_eq!(function.ty().clone(), function_type);
// // Using array signature
// let function_type = ([Type::V128], [Type::I32, Type::F32, Type::F64]);
// let function = Function::new_with_env(
// &store,
// function_type,
// my_env.clone(),
// |_env: &MyEnv, _values: &[Value]| unimplemented!(),
// );
// assert_eq!(function.ty().params(), [Type::V128]);
// assert_eq!(function.ty().results(), [Type::I32, Type::F32, Type::F64]);
// Ok(())
// }
// #[test]
// fn native_function_works() -> Result<()> {
// let store = Store::default();
// let function = Function::new_native(&store, || {});
// let native_function: NativeFunc<(), ()> = function.native().unwrap();
// let result = native_function.call();
// assert!(result.is_ok());
// let function = Function::new_native(&store, |a: i32| -> i32 { a + 1 });
// let native_function: NativeFunc<i32, i32> = function.native().unwrap();
// assert_eq!(native_function.call(3).unwrap(), 4);
// fn rust_abi(a: i32, b: i64, c: f32, d: f64) -> u64 {
// (a as u64 * 1000) + (b as u64 * 100) + (c as u64 * 10) + (d as u64)
// }
// let function = Function::new_native(&store, rust_abi);
// let native_function: NativeFunc<(i32, i64, f32, f64), u64> = function.native().unwrap();
// assert_eq!(native_function.call(8, 4, 1.5, 5.).unwrap(), 8415);
// let function = Function::new_native(&store, || -> i32 { 1 });
// let native_function: NativeFunc<(), i32> = function.native().unwrap();
// assert_eq!(native_function.call().unwrap(), 1);
// let function = Function::new_native(&store, |_a: i32| {});
// let native_function: NativeFunc<i32, ()> = function.native().unwrap();
// assert!(native_function.call(4).is_ok());
// let function = Function::new_native(&store, || -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) });
// let native_function: NativeFunc<(), (i32, i64, f32, f64)> = function.native().unwrap();
// assert_eq!(native_function.call().unwrap(), (1, 2, 3.0, 4.0));
// Ok(())
// }
// #[test]
// fn function_outlives_instance() -> Result<()> {
// let store = Store::default();
// let wat = r#"(module
// (type $sum_t (func (param i32 i32) (result i32)))
// (func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)
// local.get $x
// local.get $y
// i32.add)
// (export "sum" (func $sum_f)))
// "#;
// let f = {
// let module = Module::new(&store, wat)?;
// let instance = Instance::new(&module, &imports! {})?;
// let f: NativeFunc<(i32, i32), i32> = instance.exports.get_native_function("sum")?;
// assert_eq!(f.call(4, 5)?, 9);
// f
// };
// assert_eq!(f.call(4, 5)?, 9);
// Ok(())
// }
// #[test]
// fn weak_instance_ref_externs_after_instance() -> Result<()> {
// let store = Store::default();
// let wat = r#"(module
// (memory (export "mem") 1)
// (type $sum_t (func (param i32 i32) (result i32)))
// (func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)
// local.get $x
// local.get $y
// i32.add)
// (export "sum" (func $sum_f)))
// "#;
// let f = {
// let module = Module::new(&store, wat)?;
// let instance = Instance::new(&module, &imports! {})?;
// let f: NativeFunc<(i32, i32), i32> = instance.exports.get_with_generics_weak("sum")?;
// assert_eq!(f.call(4, 5)?, 9);
// f
// };
// assert_eq!(f.call(4, 5)?, 9);
// Ok(())
// }
// #[test]
// fn manually_generate_wasmer_env() -> Result<()> {
// let store = Store::default();
// #[derive(WasmerEnv, Clone)]
// struct MyEnv {
// val: u32,
// memory: LazyInit<Memory>,
// }
// fn host_function(env: &mut MyEnv, arg1: u32, arg2: u32) -> u32 {
// env.val + arg1 + arg2
// }
// let mut env = MyEnv {
// val: 5,
// memory: LazyInit::new(),
// };
// let result = host_function(&mut env, 7, 9);
// assert_eq!(result, 21);
// let memory = Memory::new(&store, MemoryType::new(0, None, false))?;
// env.memory.initialize(memory);
// let result = host_function(&mut env, 1, 2);
// assert_eq!(result, 8);
// Ok(())
// }

View File

@@ -0,0 +1,87 @@
use anyhow::Result;
use wasm_bindgen_test::*;
use wasmer_js::*;
// #[test]
// fn exports_work_after_multiple_instances_have_been_freed() -> Result<()> {
// let store = Store::default();
// let module = Module::new(
// &store,
// "
// (module
// (type $sum_t (func (param i32 i32) (result i32)))
// (func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)
// local.get $x
// local.get $y
// i32.add)
// (export \"sum\" (func $sum_f)))
// ",
// )?;
// let import_object = ImportObject::new();
// let instance = Instance::new(&module, &import_object)?;
// let instance2 = instance.clone();
// let instance3 = instance.clone();
// // The function is cloned to “break” the connection with `instance`.
// let sum = instance.exports.get_function("sum")?.clone();
// drop(instance);
// drop(instance2);
// drop(instance3);
// // All instances have been dropped, but `sum` continues to work!
// assert_eq!(
// sum.call(&[Value::I32(1), Value::I32(2)])?.into_vec(),
// vec![Value::I32(3)],
// );
// Ok(())
// }
#[wasm_bindgen_test]
fn test_exported_memory() {
// Let's declare the Wasm module with the text representation.
let wasm_bytes = wat2wasm(
br#"
(module
(memory (export "mem") 1)
)
"#,
)
.unwrap();
// Create a Store.
// Note that we don't need to specify the engine/compiler if we want to use
// the default provided by Wasmer.
// You can use `Store::default()` for that.
let store = Store::default();
println!("Compiling module...");
// Let's compile the Wasm module.
let module = Module::new(&store, wasm_bytes).unwrap();
// Create an empty import object.
let import_object = imports! {};
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&module, &import_object).unwrap();
// let load = instance
// .exports
// .get_native_function::<(), (WasmPtr<u8, Array>, i32)>("load")?;
// Here we go.
//
// The Wasm module exports a memory under "mem". Let's get it.
let memory = instance.exports.get_memory("mem").unwrap();
// Now that we have the exported memory, let's get some
// information about it.
//
// The first thing we might be intersted in is the size of the memory.
// Let's get it!
println!("Memory size (pages) {:?}", memory.size());
println!("Memory size (bytes) {:?}", memory.data_size());
}

248
lib/js-api/tests/module.rs Normal file
View File

@@ -0,0 +1,248 @@
use anyhow::Result;
use wasm_bindgen_test::*;
use wasmer_js::*;
#[wasm_bindgen_test]
fn module_get_name() {
let store = Store::default();
let wat = r#"(module)"#;
let module = Module::new(&store, wat).unwrap();
assert_eq!(module.name(), None);
}
#[wasm_bindgen_test]
fn module_set_name() {
let store = Store::default();
let wat = r#"(module $name)"#;
let mut module = Module::new(&store, wat).unwrap();
// We explicitly don't test the wasm name from the name section
// because it adds unnecessary overhead for really little gain.
// assert_eq!(module.name(), Some("name"));
module.set_name("new_name");
assert_eq!(module.name(), Some("new_name"));
}
#[wasm_bindgen_test]
fn imports() {
let store = Store::default();
let wat = r#"(module
(import "host" "func" (func))
(import "host" "memory" (memory 1))
(import "host" "table" (table 1 anyfunc))
(import "host" "global" (global i32))
)"#;
let module = Module::new(&store, wat).unwrap();
assert_eq!(
module.imports().collect::<Vec<_>>(),
vec![
ImportType::new(
"host",
"func",
ExternType::Function(FunctionType::new(vec![], vec![]))
),
ImportType::new(
"host",
"memory",
ExternType::Memory(MemoryType::new(Pages(1), None, false))
),
ImportType::new(
"host",
"table",
ExternType::Table(TableType::new(Type::FuncRef, 1, None))
),
ImportType::new(
"host",
"global",
ExternType::Global(GlobalType::new(Type::I32, Mutability::Const))
)
]
);
// Now we test the iterators
assert_eq!(
module.imports().functions().collect::<Vec<_>>(),
vec![ImportType::new(
"host",
"func",
FunctionType::new(vec![], vec![])
),]
);
assert_eq!(
module.imports().memories().collect::<Vec<_>>(),
vec![ImportType::new(
"host",
"memory",
MemoryType::new(Pages(1), None, false)
),]
);
assert_eq!(
module.imports().tables().collect::<Vec<_>>(),
vec![ImportType::new(
"host",
"table",
TableType::new(Type::FuncRef, 1, None)
),]
);
assert_eq!(
module.imports().globals().collect::<Vec<_>>(),
vec![ImportType::new(
"host",
"global",
GlobalType::new(Type::I32, Mutability::Const)
),]
);
// Ok(())
}
#[wasm_bindgen_test]
fn exports() {
let store = Store::default();
let wat = r#"(module
(func (export "func") nop)
(memory (export "memory") 1)
(table (export "table") 1 funcref)
(global (export "global") i32 (i32.const 0))
)"#;
let module = Module::new(&store, wat).unwrap();
assert_eq!(
module.exports().collect::<Vec<_>>(),
vec![
ExportType::new(
"func",
ExternType::Function(FunctionType::new(vec![], vec![]))
),
ExportType::new(
"memory",
ExternType::Memory(MemoryType::new(Pages(1), None, false))
),
ExportType::new(
"table",
ExternType::Table(TableType::new(Type::FuncRef, 1, None))
),
ExportType::new(
"global",
ExternType::Global(GlobalType::new(Type::I32, Mutability::Const))
)
]
);
// Now we test the iterators
assert_eq!(
module.exports().functions().collect::<Vec<_>>(),
vec![ExportType::new("func", FunctionType::new(vec![], vec![])),]
);
assert_eq!(
module.exports().memories().collect::<Vec<_>>(),
vec![ExportType::new(
"memory",
MemoryType::new(Pages(1), None, false)
),]
);
assert_eq!(
module.exports().tables().collect::<Vec<_>>(),
vec![ExportType::new(
"table",
TableType::new(Type::FuncRef, 1, None)
),]
);
assert_eq!(
module.exports().globals().collect::<Vec<_>>(),
vec![ExportType::new(
"global",
GlobalType::new(Type::I32, Mutability::Const)
),]
);
// Ok(())
}
// #[test]
// fn calling_host_functions_with_negative_values_works() -> Result<()> {
// let store = Store::default();
// let wat = r#"(module
// (import "host" "host_func1" (func (param i64)))
// (import "host" "host_func2" (func (param i32)))
// (import "host" "host_func3" (func (param i64)))
// (import "host" "host_func4" (func (param i32)))
// (import "host" "host_func5" (func (param i32)))
// (import "host" "host_func6" (func (param i32)))
// (import "host" "host_func7" (func (param i32)))
// (import "host" "host_func8" (func (param i32)))
// (func (export "call_host_func1")
// (call 0 (i64.const -1)))
// (func (export "call_host_func2")
// (call 1 (i32.const -1)))
// (func (export "call_host_func3")
// (call 2 (i64.const -1)))
// (func (export "call_host_func4")
// (call 3 (i32.const -1)))
// (func (export "call_host_func5")
// (call 4 (i32.const -1)))
// (func (export "call_host_func6")
// (call 5 (i32.const -1)))
// (func (export "call_host_func7")
// (call 6 (i32.const -1)))
// (func (export "call_host_func8")
// (call 7 (i32.const -1)))
// )"#;
// let module = Module::new(&store, wat)?;
// let imports = imports! {
// "host" => {
// "host_func1" => Function::new_native(&store, |p: u64| {
// println!("host_func1: Found number {}", p);
// assert_eq!(p, u64::max_value());
// }),
// "host_func2" => Function::new_native(&store, |p: u32| {
// println!("host_func2: Found number {}", p);
// assert_eq!(p, u32::max_value());
// }),
// "host_func3" => Function::new_native(&store, |p: i64| {
// println!("host_func3: Found number {}", p);
// assert_eq!(p, -1);
// }),
// "host_func4" => Function::new_native(&store, |p: i32| {
// println!("host_func4: Found number {}", p);
// assert_eq!(p, -1);
// }),
// "host_func5" => Function::new_native(&store, |p: i16| {
// println!("host_func5: Found number {}", p);
// assert_eq!(p, -1);
// }),
// "host_func6" => Function::new_native(&store, |p: u16| {
// println!("host_func6: Found number {}", p);
// assert_eq!(p, u16::max_value());
// }),
// "host_func7" => Function::new_native(&store, |p: i8| {
// println!("host_func7: Found number {}", p);
// assert_eq!(p, -1);
// }),
// "host_func8" => Function::new_native(&store, |p: u8| {
// println!("host_func8: Found number {}", p);
// assert_eq!(p, u8::max_value());
// }),
// }
// };
// let instance = Instance::new(&module, &imports)?;
// let f1: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func1")?;
// let f2: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func2")?;
// let f3: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func3")?;
// let f4: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func4")?;
// let f5: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func5")?;
// let f6: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func6")?;
// let f7: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func7")?;
// let f8: NativeFunc<(), ()> = instance.exports.get_native_function("call_host_func8")?;
// f1.call()?;
// f2.call()?;
// f3.call()?;
// f4.call()?;
// f5.call()?;
// f6.call()?;
// f7.call()?;
// f8.call()?;
// Ok(())
// }

View File

@@ -0,0 +1,497 @@
// use anyhow::Result;
// use std::collections::HashMap;
// use std::sync::atomic::{AtomicBool, Ordering};
// use std::sync::Arc;
// use wasmer::*;
// #[test]
// fn func_ref_passed_and_returned() -> Result<()> {
// let store = Store::default();
// let wat = r#"(module
// (import "env" "func_ref_identity" (func (param funcref) (result funcref)))
// (type $ret_i32_ty (func (result i32)))
// (table $table (export "table") 2 2 funcref)
// (func (export "run") (param) (result funcref)
// (call 0 (ref.null func)))
// (func (export "call_set_value") (param $fr funcref) (result i32)
// (table.set $table (i32.const 0) (local.get $fr))
// (call_indirect $table (type $ret_i32_ty) (i32.const 0)))
// )"#;
// let module = Module::new(&store, wat)?;
// let imports = imports! {
// "env" => {
// "func_ref_identity" => Function::new(&store, FunctionType::new([Type::FuncRef], [Type::FuncRef]), |values| -> Result<Vec<_>, _> {
// Ok(vec![values[0].clone()])
// })
// },
// };
// let instance = Instance::new(&module, &imports)?;
// let f: &Function = instance.exports.get_function("run")?;
// let results = f.call(&[]).unwrap();
// if let Value::FuncRef(fr) = &results[0] {
// assert!(fr.is_none());
// } else {
// panic!("funcref not found!");
// }
// #[derive(Clone, Debug, WasmerEnv)]
// pub struct Env(Arc<AtomicBool>);
// let env = Env(Arc::new(AtomicBool::new(false)));
// let func_to_call = Function::new_native_with_env(&store, env.clone(), |env: &Env| -> i32 {
// env.0.store(true, Ordering::SeqCst);
// 343
// });
// let call_set_value: &Function = instance.exports.get_function("call_set_value")?;
// let results: Box<[Value]> = call_set_value.call(&[Value::FuncRef(Some(func_to_call))])?;
// assert!(env.0.load(Ordering::SeqCst));
// assert_eq!(&*results, &[Value::I32(343)]);
// Ok(())
// }
// #[test]
// fn func_ref_passed_and_called() -> Result<()> {
// let store = Store::default();
// let wat = r#"(module
// (func $func_ref_call (import "env" "func_ref_call") (param funcref) (result i32))
// (type $ret_i32_ty (func (result i32)))
// (table $table (export "table") 2 2 funcref)
// (func $product (param $x i32) (param $y i32) (result i32)
// (i32.mul (local.get $x) (local.get $y)))
// ;; TODO: figure out exactly why this statement is needed
// (elem declare func $product)
// (func (export "call_set_value") (param $fr funcref) (result i32)
// (table.set $table (i32.const 0) (local.get $fr))
// (call_indirect $table (type $ret_i32_ty) (i32.const 0)))
// (func (export "call_func") (param $fr funcref) (result i32)
// (call $func_ref_call (local.get $fr)))
// (func (export "call_host_func_with_wasm_func") (result i32)
// (call $func_ref_call (ref.func $product)))
// )"#;
// let module = Module::new(&store, wat)?;
// fn func_ref_call(values: &[Value]) -> Result<Vec<Value>, RuntimeError> {
// // TODO: look into `Box<[Value]>` being returned breakage
// let f = values[0].unwrap_funcref().as_ref().unwrap();
// let f: NativeFunc<(i32, i32), i32> = f.native()?;
// Ok(vec![Value::I32(f.call(7, 9)?)])
// }
// let imports = imports! {
// "env" => {
// "func_ref_call" => Function::new(
// &store,
// FunctionType::new([Type::FuncRef], [Type::I32]),
// func_ref_call
// ),
// // TODO(reftypes): this should work
// /*
// "func_ref_call_native" => Function::new_native(&store, |f: Function| -> Result<i32, RuntimeError> {
// let f: NativeFunc::<(i32, i32), i32> = f.native()?;
// f.call(7, 9)
// })
// */
// },
// };
// let instance = Instance::new(&module, &imports)?;
// {
// fn sum(a: i32, b: i32) -> i32 {
// a + b
// }
// let sum_func = Function::new_native(&store, sum);
// let call_func: &Function = instance.exports.get_function("call_func")?;
// let result = call_func.call(&[Value::FuncRef(Some(sum_func))])?;
// assert_eq!(result[0].unwrap_i32(), 16);
// }
// {
// let f: NativeFunc<(), i32> = instance
// .exports
// .get_native_function("call_host_func_with_wasm_func")?;
// let result = f.call()?;
// assert_eq!(result, 63);
// }
// Ok(())
// }
// #[cfg(feature = "experimental-reference-types-extern-ref")]
// #[test]
// fn extern_ref_passed_and_returned() -> Result<()> {
// let store = Store::default();
// let wat = r#"(module
// (func $extern_ref_identity (import "env" "extern_ref_identity") (param externref) (result externref))
// (func $extern_ref_identity_native (import "env" "extern_ref_identity_native") (param externref) (result externref))
// (func $get_new_extern_ref (import "env" "get_new_extern_ref") (result externref))
// (func $get_new_extern_ref_native (import "env" "get_new_extern_ref_native") (result externref))
// (func (export "run") (param) (result externref)
// (call $extern_ref_identity (ref.null extern)))
// (func (export "run_native") (param) (result externref)
// (call $extern_ref_identity_native (ref.null extern)))
// (func (export "get_hashmap") (param) (result externref)
// (call $get_new_extern_ref))
// (func (export "get_hashmap_native") (param) (result externref)
// (call $get_new_extern_ref_native))
// )"#;
// let module = Module::new(&store, wat)?;
// let imports = imports! {
// "env" => {
// "extern_ref_identity" => Function::new(&store, FunctionType::new([Type::ExternRef], [Type::ExternRef]), |values| -> Result<Vec<_>, _> {
// Ok(vec![values[0].clone()])
// }),
// "extern_ref_identity_native" => Function::new_native(&store, |er: ExternRef| -> ExternRef {
// er
// }),
// "get_new_extern_ref" => Function::new(&store, FunctionType::new([], [Type::ExternRef]), |_| -> Result<Vec<_>, _> {
// let inner =
// [("hello".to_string(), "world".to_string()),
// ("color".to_string(), "orange".to_string())]
// .iter()
// .cloned()
// .collect::<HashMap<String, String>>();
// let new_extern_ref = ExternRef::new(inner);
// Ok(vec![Value::ExternRef(new_extern_ref)])
// }),
// "get_new_extern_ref_native" => Function::new_native(&store, || -> ExternRef {
// let inner =
// [("hello".to_string(), "world".to_string()),
// ("color".to_string(), "orange".to_string())]
// .iter()
// .cloned()
// .collect::<HashMap<String, String>>();
// ExternRef::new(inner)
// })
// },
// };
// let instance = Instance::new(&module, &imports)?;
// for run in &["run", "run_native"] {
// let f: &Function = instance.exports.get_function(run)?;
// let results = f.call(&[]).unwrap();
// if let Value::ExternRef(er) = &results[0] {
// assert!(er.is_null());
// } else {
// panic!("result is not an extern ref!");
// }
// let f: NativeFunc<(), ExternRef> = instance.exports.get_native_function(run)?;
// let result: ExternRef = f.call()?;
// assert!(result.is_null());
// }
// for get_hashmap in &["get_hashmap", "get_hashmap_native"] {
// let f: &Function = instance.exports.get_function(get_hashmap)?;
// let results = f.call(&[]).unwrap();
// if let Value::ExternRef(er) = &results[0] {
// let inner: &HashMap<String, String> = er.downcast().unwrap();
// assert_eq!(inner["hello"], "world");
// assert_eq!(inner["color"], "orange");
// } else {
// panic!("result is not an extern ref!");
// }
// let f: NativeFunc<(), ExternRef> = instance.exports.get_native_function(get_hashmap)?;
// let result: ExternRef = f.call()?;
// let inner: &HashMap<String, String> = result.downcast().unwrap();
// assert_eq!(inner["hello"], "world");
// assert_eq!(inner["color"], "orange");
// }
// Ok(())
// }
// #[cfg(feature = "experimental-reference-types-extern-ref")]
// #[test]
// // TODO(reftypes): reenable this test
// #[ignore]
// fn extern_ref_ref_counting_basic() -> Result<()> {
// let store = Store::default();
// let wat = r#"(module
// (func (export "drop") (param $er externref) (result)
// (drop (local.get $er)))
// )"#;
// let module = Module::new(&store, wat)?;
// let instance = Instance::new(&module, &imports! {})?;
// let f: NativeFunc<ExternRef, ()> = instance.exports.get_native_function("drop")?;
// let er = ExternRef::new(3u32);
// f.call(er.clone())?;
// assert_eq!(er.downcast::<u32>().unwrap(), &3);
// assert_eq!(er.strong_count(), 1);
// Ok(())
// }
// #[cfg(feature = "experimental-reference-types-extern-ref")]
// #[test]
// fn refs_in_globals() -> Result<()> {
// let store = Store::default();
// let wat = r#"(module
// (global $er_global (export "er_global") (mut externref) (ref.null extern))
// (global $fr_global (export "fr_global") (mut funcref) (ref.null func))
// (global $fr_immutable_global (export "fr_immutable_global") funcref (ref.func $hello))
// (func $hello (param) (result i32)
// (i32.const 73))
// )"#;
// let module = Module::new(&store, wat)?;
// let instance = Instance::new(&module, &imports! {})?;
// {
// let er_global: &Global = instance.exports.get_global("er_global")?;
// if let Value::ExternRef(er) = er_global.get() {
// assert!(er.is_null());
// } else {
// panic!("Did not find extern ref in the global");
// }
// er_global.set(Val::ExternRef(ExternRef::new(3u32)))?;
// if let Value::ExternRef(er) = er_global.get() {
// assert_eq!(er.downcast::<u32>().unwrap(), &3);
// assert_eq!(er.strong_count(), 1);
// } else {
// panic!("Did not find extern ref in the global");
// }
// }
// {
// let fr_global: &Global = instance.exports.get_global("fr_immutable_global")?;
// if let Value::FuncRef(Some(f)) = fr_global.get() {
// let native_func: NativeFunc<(), u32> = f.native()?;
// assert_eq!(native_func.call()?, 73);
// } else {
// panic!("Did not find non-null func ref in the global");
// }
// }
// {
// let fr_global: &Global = instance.exports.get_global("fr_global")?;
// if let Value::FuncRef(None) = fr_global.get() {
// } else {
// panic!("Did not find a null func ref in the global");
// }
// let f = Function::new_native(&store, |arg1: i32, arg2: i32| -> i32 { arg1 + arg2 });
// fr_global.set(Val::FuncRef(Some(f)))?;
// if let Value::FuncRef(Some(f)) = fr_global.get() {
// let native: NativeFunc<(i32, i32), i32> = f.native()?;
// assert_eq!(native.call(5, 7)?, 12);
// } else {
// panic!("Did not find extern ref in the global");
// }
// }
// Ok(())
// }
// #[cfg(feature = "experimental-reference-types-extern-ref")]
// #[test]
// fn extern_ref_ref_counting_table_basic() -> Result<()> {
// let store = Store::default();
// let wat = r#"(module
// (global $global (export "global") (mut externref) (ref.null extern))
// (table $table (export "table") 4 4 externref)
// (func $insert (param $er externref) (param $idx i32)
// (table.set $table (local.get $idx) (local.get $er)))
// (func $intermediate (param $er externref) (param $idx i32)
// (call $insert (local.get $er) (local.get $idx)))
// (func $insert_into_table (export "insert_into_table") (param $er externref) (param $idx i32) (result externref)
// (call $intermediate (local.get $er) (local.get $idx))
// (local.get $er))
// )"#;
// let module = Module::new(&store, wat)?;
// let instance = Instance::new(&module, &imports! {})?;
// let f: NativeFunc<(ExternRef, i32), ExternRef> =
// instance.exports.get_native_function("insert_into_table")?;
// let er = ExternRef::new(3usize);
// let er = f.call(er, 1)?;
// assert_eq!(er.strong_count(), 2);
// let table: &Table = instance.exports.get_table("table")?;
// {
// let er2 = table.get(1).unwrap().externref().unwrap();
// assert_eq!(er2.strong_count(), 3);
// }
// assert_eq!(er.strong_count(), 2);
// table.set(1, Val::ExternRef(ExternRef::null()))?;
// assert_eq!(er.strong_count(), 1);
// Ok(())
// }
// #[cfg(feature = "experimental-reference-types-extern-ref")]
// #[test]
// // TODO(reftypes): reenable this test
// #[ignore]
// fn extern_ref_ref_counting_global_basic() -> Result<()> {
// let store = Store::default();
// let wat = r#"(module
// (global $global (export "global") (mut externref) (ref.null extern))
// (func $get_from_global (export "get_from_global") (result externref)
// (drop (global.get $global))
// (global.get $global))
// )"#;
// let module = Module::new(&store, wat)?;
// let instance = Instance::new(&module, &imports! {})?;
// let global: &Global = instance.exports.get_global("global")?;
// {
// let er = ExternRef::new(3usize);
// global.set(Val::ExternRef(er.clone()))?;
// assert_eq!(er.strong_count(), 2);
// }
// let get_from_global: NativeFunc<(), ExternRef> =
// instance.exports.get_native_function("get_from_global")?;
// let er = get_from_global.call()?;
// assert_eq!(er.strong_count(), 2);
// global.set(Val::ExternRef(ExternRef::null()))?;
// assert_eq!(er.strong_count(), 1);
// Ok(())
// }
// #[cfg(feature = "experimental-reference-types-extern-ref")]
// #[test]
// // TODO(reftypes): reenable this test
// #[ignore]
// fn extern_ref_ref_counting_traps() -> Result<()> {
// let store = Store::default();
// let wat = r#"(module
// (func $pass_er (export "pass_extern_ref") (param externref)
// (local.get 0)
// (unreachable))
// )"#;
// let module = Module::new(&store, wat)?;
// let instance = Instance::new(&module, &imports! {})?;
// let pass_extern_ref: NativeFunc<ExternRef, ()> =
// instance.exports.get_native_function("pass_extern_ref")?;
// let er = ExternRef::new(3usize);
// assert_eq!(er.strong_count(), 1);
// let result = pass_extern_ref.call(er.clone());
// assert!(result.is_err());
// assert_eq!(er.strong_count(), 1);
// Ok(())
// }
// #[cfg(feature = "experimental-reference-types-extern-ref")]
// #[test]
// fn extern_ref_ref_counting_table_instructions() -> Result<()> {
// let store = Store::default();
// let wat = r#"(module
// (table $table1 (export "table1") 2 12 externref)
// (table $table2 (export "table2") 6 12 externref)
// (func $grow_table_with_ref (export "grow_table_with_ref") (param $er externref) (param $size i32) (result i32)
// (table.grow $table1 (local.get $er) (local.get $size)))
// (func $fill_table_with_ref (export "fill_table_with_ref") (param $er externref) (param $start i32) (param $end i32)
// (table.fill $table1 (local.get $start) (local.get $er) (local.get $end)))
// (func $copy_into_table2 (export "copy_into_table2")
// (table.copy $table2 $table1 (i32.const 0) (i32.const 0) (i32.const 4)))
// )"#;
// let module = Module::new(&store, wat)?;
// let instance = Instance::new(&module, &imports! {})?;
// let grow_table_with_ref: NativeFunc<(ExternRef, i32), i32> = instance
// .exports
// .get_native_function("grow_table_with_ref")?;
// let fill_table_with_ref: NativeFunc<(ExternRef, i32, i32), ()> = instance
// .exports
// .get_native_function("fill_table_with_ref")?;
// let copy_into_table2: NativeFunc<(), ()> =
// instance.exports.get_native_function("copy_into_table2")?;
// let table1: &Table = instance.exports.get_table("table1")?;
// let table2: &Table = instance.exports.get_table("table2")?;
// let er1 = ExternRef::new(3usize);
// let er2 = ExternRef::new(5usize);
// let er3 = ExternRef::new(7usize);
// {
// let result = grow_table_with_ref.call(er1.clone(), 0)?;
// assert_eq!(result, 2);
// assert_eq!(er1.strong_count(), 1);
// let result = grow_table_with_ref.call(er1.clone(), 10_000)?;
// assert_eq!(result, -1);
// assert_eq!(er1.strong_count(), 1);
// let result = grow_table_with_ref.call(er1.clone(), 8)?;
// assert_eq!(result, 2);
// assert_eq!(er1.strong_count(), 9);
// for i in 2..10 {
// let e = table1.get(i).unwrap().unwrap_externref();
// assert_eq!(*e.downcast::<usize>().unwrap(), 3);
// assert_eq!(&e, &er1);
// }
// assert_eq!(er1.strong_count(), 9);
// }
// {
// fill_table_with_ref.call(er2.clone(), 0, 2)?;
// assert_eq!(er2.strong_count(), 3);
// }
// {
// table2.set(0, Val::ExternRef(er3.clone()))?;
// table2.set(1, Val::ExternRef(er3.clone()))?;
// table2.set(2, Val::ExternRef(er3.clone()))?;
// table2.set(3, Val::ExternRef(er3.clone()))?;
// table2.set(4, Val::ExternRef(er3.clone()))?;
// assert_eq!(er3.strong_count(), 6);
// }
// {
// copy_into_table2.call()?;
// assert_eq!(er3.strong_count(), 2);
// assert_eq!(er2.strong_count(), 5);
// assert_eq!(er1.strong_count(), 11);
// for i in 1..5 {
// let e = table2.get(i).unwrap().unwrap_externref();
// let value = e.downcast::<usize>().unwrap();
// match i {
// 0 | 1 => assert_eq!(*value, 5),
// 4 => assert_eq!(*value, 7),
// _ => assert_eq!(*value, 3),
// }
// }
// }
// {
// for i in 0..table1.size() {
// table1.set(i, Val::ExternRef(ExternRef::null()))?;
// }
// for i in 0..table2.size() {
// table2.set(i, Val::ExternRef(ExternRef::null()))?;
// }
// }
// assert_eq!(er1.strong_count(), 1);
// assert_eq!(er2.strong_count(), 1);
// assert_eq!(er3.strong_count(), 1);
// Ok(())
// }