use wasmtime::*;
#[test]
fn smoke() -> anyhow::Result<()> {
let mut store = Store::<()>::default();
let g = Global::new(
&mut store,
GlobalType::new(ValType::I32, Mutability::Const),
0.into(),
)?;
assert_eq!(g.get(&mut store).i32(), Some(0));
assert!(g.set(&mut store, 0.into()).is_err());
let g = Global::new(
&mut store,
GlobalType::new(ValType::I32, Mutability::Const),
1i32.into(),
)?;
assert_eq!(g.get(&mut store).i32(), Some(1));
let g = Global::new(
&mut store,
GlobalType::new(ValType::I64, Mutability::Const),
2i64.into(),
)?;
assert_eq!(g.get(&mut store).i64(), Some(2));
let g = Global::new(
&mut store,
GlobalType::new(ValType::F32, Mutability::Const),
3.0f32.into(),
)?;
assert_eq!(g.get(&mut store).f32(), Some(3.0));
let g = Global::new(
&mut store,
GlobalType::new(ValType::F64, Mutability::Const),
4.0f64.into(),
)?;
assert_eq!(g.get(&mut store).f64(), Some(4.0));
Ok(())
}
#[test]
fn mutability() -> anyhow::Result<()> {
let mut store = Store::<()>::default();
let g = Global::new(
&mut store,
GlobalType::new(ValType::I32, Mutability::Var),
0.into(),
)?;
assert_eq!(g.get(&mut store).i32(), Some(0));
g.set(&mut store, 1.into())?;
assert_eq!(g.get(&mut store).i32(), Some(1));
Ok(())
}
#[test]
fn use_after_drop() -> anyhow::Result<()> {
let mut store = Store::<()>::default();
let module = Module::new(
store.engine(),
r#"
(module
(global (export "foo") (mut i32) (i32.const 100)))
"#,
)?;
let instance = Instance::new(&mut store, &module, &[])?;
let g = instance.get_global(&mut store, "foo").unwrap();
assert_eq!(g.get(&mut store).i32(), Some(100));
g.set(&mut store, 101.into())?;
assert_eq!(g.get(&mut store).i32(), Some(101));
Instance::new(&mut store, &module, &[])?;
assert_eq!(g.get(&mut store).i32(), Some(101));
drop(module);
assert_eq!(g.get(&mut store).i32(), Some(101));
let mut x = Vec::new();
for _ in 0..100 {
x.push("xy".to_string());
}
drop(x);
assert_eq!(g.get(&mut store).i32(), Some(101));
Ok(())
}
#[test]
fn v128() -> anyhow::Result<()> {
let mut store = Store::<()>::default();
let g = Global::new(
&mut store,
GlobalType::new(ValType::V128, Mutability::Var),
0u128.into(),
)?;
assert_eq!(g.get(&mut store).v128(), Some(V128::from(0)));
g.set(&mut store, 1u128.into())?;
assert_eq!(g.get(&mut store).v128(), Some(V128::from(1)));
Ok(())
}
#[test]
fn i31ref_global_new() -> Result<()> {
let mut config = Config::new();
config.wasm_function_references(true);
config.wasm_gc(true);
let engine = Engine::new(&config)?;
let mut store = Store::new(&engine, ());
for mutability in [Mutability::Const, Mutability::Var] {
for val in [
Some(AnyRef::from_i31(&mut store, I31::new_u32(42).unwrap())),
None,
] {
Global::new(
&mut store,
GlobalType::new(ValType::I31REF, mutability),
val.into(),
)?;
}
}
Ok(())
}
#[test]
fn i31ref_global_get() -> Result<()> {
let mut config = Config::new();
config.wasm_function_references(true);
config.wasm_gc(true);
let engine = Engine::new(&config)?;
let mut store = Store::new(&engine, ());
for mutability in [Mutability::Const, Mutability::Var] {
for val in [
Some(AnyRef::from_i31(&mut store, I31::new_u32(42).unwrap())),
None,
] {
let val = Val::from(val);
let global = Global::new(
&mut store,
GlobalType::new(ValType::I31REF, mutability),
val,
)?;
let got = global.get(&mut store);
let val = val
.anyref()
.and_then(|a| a.and_then(|a| a.as_i31(&store).unwrap()));
let got = got
.anyref()
.and_then(|a| a.and_then(|a| a.as_i31(&store).unwrap()));
assert_eq!(val, got);
}
}
Ok(())
}
#[test]
fn i31ref_global_set() -> Result<()> {
let mut config = Config::new();
config.wasm_function_references(true);
config.wasm_gc(true);
let engine = Engine::new(&config)?;
let mut store = Store::new(&engine, ());
for init in [
Some(AnyRef::from_i31(&mut store, I31::new_u32(42).unwrap())),
None,
] {
for new_val in [
Some(AnyRef::from_i31(&mut store, I31::new_u32(36).unwrap())),
None,
] {
let global = Global::new(
&mut store,
GlobalType::new(ValType::I31REF, Mutability::Var),
init.into(),
)?;
let new_val = Val::from(new_val);
global.set(&mut store, new_val)?;
let got = global.get(&mut store);
let new_val = new_val
.anyref()
.and_then(|a| a.and_then(|a| a.as_i31(&store).unwrap()));
let got = got
.anyref()
.and_then(|a| a.and_then(|a| a.as_i31(&store).unwrap()));
assert_eq!(new_val, got);
}
}
Ok(())
}
#[test]
fn i31ref_global_ty() -> Result<()> {
let mut config = Config::new();
config.wasm_function_references(true);
config.wasm_gc(true);
let engine = Engine::new(&config)?;
let mut store = Store::new(&engine, ());
for mutability in [Mutability::Const, Mutability::Var] {
for val in [
Some(AnyRef::from_i31(&mut store, I31::new_u32(42).unwrap())),
None,
] {
let expected_ty = GlobalType::new(ValType::I31REF, mutability);
let global = Global::new(&mut store, expected_ty.clone(), val.into())?;
let actual_ty = global.ty(&store);
assert_eq!(expected_ty.mutability(), actual_ty.mutability());
assert!(ValType::eq(expected_ty.content(), actual_ty.content()));
}
}
Ok(())
}
#[test]
fn i31ref_as_anyref_global_new() -> Result<()> {
let mut config = Config::new();
config.wasm_function_references(true);
config.wasm_gc(true);
let engine = Engine::new(&config)?;
let mut store = Store::new(&engine, ());
for mutability in [Mutability::Const, Mutability::Var] {
for val in [
Some(AnyRef::from_i31(&mut store, I31::new_u32(42).unwrap())),
None,
] {
Global::new(
&mut store,
GlobalType::new(ValType::ANYREF, mutability),
val.into(),
)?;
}
}
Ok(())
}
#[test]
fn i31ref_as_anyref_global_get() -> Result<()> {
let mut config = Config::new();
config.wasm_function_references(true);
config.wasm_gc(true);
let engine = Engine::new(&config)?;
let mut store = Store::new(&engine, ());
for mutability in [Mutability::Const, Mutability::Var] {
for val in [
Some(AnyRef::from_i31(&mut store, I31::new_u32(42).unwrap())),
None,
] {
let val = Val::from(val);
let global = Global::new(
&mut store,
GlobalType::new(ValType::ANYREF, mutability),
val,
)?;
let got = global.get(&mut store);
let val = val
.anyref()
.and_then(|a| a.and_then(|a| a.as_i31(&store).unwrap()));
let got = got
.anyref()
.and_then(|a| a.and_then(|a| a.as_i31(&store).unwrap()));
assert_eq!(val, got);
}
}
Ok(())
}
#[test]
fn i31ref_as_anyref_global_set() -> Result<()> {
let mut config = Config::new();
config.wasm_function_references(true);
config.wasm_gc(true);
let engine = Engine::new(&config)?;
let mut store = Store::new(&engine, ());
for init in [
Some(AnyRef::from_i31(&mut store, I31::new_u32(42).unwrap())),
None,
] {
for new_val in [
Some(AnyRef::from_i31(&mut store, I31::new_u32(36).unwrap())),
None,
] {
let global = Global::new(
&mut store,
GlobalType::new(ValType::ANYREF, Mutability::Var),
init.into(),
)?;
let new_val = Val::from(new_val);
global.set(&mut store, new_val)?;
let got = global.get(&mut store);
let new_val = new_val
.anyref()
.and_then(|a| a.and_then(|a| a.as_i31(&store).unwrap()));
let got = got
.anyref()
.and_then(|a| a.and_then(|a| a.as_i31(&store).unwrap()));
assert_eq!(new_val, got);
}
}
Ok(())
}
#[test]
fn i31ref_as_anyref_global_ty() -> Result<()> {
let mut config = Config::new();
config.wasm_function_references(true);
config.wasm_gc(true);
let engine = Engine::new(&config)?;
let mut store = Store::new(&engine, ());
for mutability in [Mutability::Const, Mutability::Var] {
for val in [
Some(AnyRef::from_i31(&mut store, I31::new_u32(42).unwrap())),
None,
] {
let expected_ty = GlobalType::new(ValType::ANYREF, mutability);
let global = Global::new(&mut store, expected_ty.clone(), val.into())?;
let actual_ty = global.ty(&store);
assert_eq!(expected_ty.mutability(), actual_ty.mutability());
assert!(ValType::eq(expected_ty.content(), actual_ty.content()));
}
}
Ok(())
}
#[test]
#[cfg_attr(miri, ignore)]
fn instantiate_global_with_subtype() -> Result<()> {
let mut config = Config::new();
config.wasm_function_references(true);
config.wasm_gc(true);
let engine = Engine::new(&config)?;
let module = Module::new(
&engine,
r#"
(module
(type $func_ty (sub (func)))
(import "" "" (global (ref null $func_ty)))
)
"#,
)?;
{
let func_ty =
FuncType::with_finality_and_supertype(&engine, Finality::NonFinal, None, [], [])?;
let sub_func_ty = FuncType::with_finality_and_supertype(
&engine,
Finality::NonFinal,
Some(&func_ty),
[],
[],
)?;
let global_ty = GlobalType::new(
RefType::new(true, HeapType::ConcreteFunc(sub_func_ty.clone())).into(),
Mutability::Const,
);
assert!(
global_ty.content().matches(
module
.imports()
.nth(0)
.unwrap()
.ty()
.unwrap_global()
.content()
)
);
let mut store = Store::new(&engine, ());
let func = Func::new(&mut store, sub_func_ty, |_caller, _args, _rets| Ok(()));
let global = Global::new(&mut store, global_ty, func.into())?;
let _ = Instance::new(&mut store, &module, &[global.into()])?;
}
{
let func_ty = FuncType::new(&engine, [], []);
let global_ty = GlobalType::new(
RefType::new(true, HeapType::ConcreteFunc(func_ty.clone())).into(),
Mutability::Const,
);
assert!(
!global_ty.content().matches(
module
.imports()
.nth(0)
.unwrap()
.ty()
.unwrap_global()
.content()
)
);
let mut store = Store::new(&engine, ());
let func = Func::new(&mut store, func_ty, |_caller, _args, _rets| Ok(()));
let global = Global::new(&mut store, global_ty, func.into())?;
assert!(Instance::new(&mut store, &module, &[global.into()]).is_err());
}
Ok(())
}
#[test]
fn host_globals_keep_type_registration() -> Result<()> {
let engine = Engine::default();
let mut store = Store::new(&engine, ());
let ty = FuncType::new(&engine, [], []);
let g = Global::new(
&mut store,
GlobalType::new(
RefType::new(true, HeapType::ConcreteFunc(ty)).into(),
Mutability::Const,
),
Val::FuncRef(None),
)?;
{
let _ty2 = FuncType::new(&engine, [ValType::I32], [ValType::I32]);
let ty = g.ty(&store);
let fty = ty.content().unwrap_ref().heap_type().unwrap_concrete_func();
assert!(fty.params().len() == 0);
assert!(fty.results().len() == 0);
}
let ty = g.ty(&store);
let fty = ty.content().unwrap_ref().heap_type().unwrap_concrete_func();
assert!(fty.params().len() == 0);
assert!(fty.results().len() == 0);
Ok(())
}