diff --git a/lib/api/tests/sys_reference_types.rs b/lib/api/tests/sys_reference_types.rs index ca063dbf084..b481a07d8f9 100644 --- a/lib/api/tests/sys_reference_types.rs +++ b/lib/api/tests/sys_reference_types.rs @@ -130,12 +130,11 @@ mod sys { Ok(()) } - /* - #[test] - fn extern_ref_passed_and_returned() -> Result<()> { - let mut store = Store::default(); - let env = FunctionEnv::new(&mut store, ()); - let wat = r#"(module + #[test] + fn extern_ref_passed_and_returned() -> Result<()> { + use std::collections::HashMap; + let mut 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)) @@ -150,167 +149,168 @@ mod sys { (func (export "get_hashmap_native") (param) (result externref) (call $get_new_extern_ref_native)) )"#; - let module = Module::new(&store, wat)?; - let env = FunctionEnv::new(&mut store, ()); - let imports = imports! { - "env" => { - "extern_ref_identity" => Function::new(&mut store, &env, FunctionType::new([Type::ExternRef], [Type::ExternRef]), |_env, values| -> Result, _> { - Ok(vec![values[0].clone()]) - }), - "extern_ref_identity_native" => Function::new_typed(&mut store, |er: ExternRef| -> ExternRef { - er - }), - "get_new_extern_ref" => Function::new(&mut store, &env, FunctionType::new([], [Type::ExternRef]), |_env, _| -> Result, _> { - let inner = - [("hello".to_string(), "world".to_string()), - ("color".to_string(), "orange".to_string())] - .iter() - .cloned() - .collect::>(); - let new_extern_ref = ExternRef::new(&mut env, inner); - Ok(vec![Value::ExternRef(new_extern_ref)]) - }), - "get_new_extern_ref_native" => Function::new_native(&mut store, || -> ExternRef { - let inner = - [("hello".to_string(), "world".to_string()), - ("color".to_string(), "orange".to_string())] - .iter() - .cloned() - .collect::>(); - 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 module = Module::new(&store, wat)?; + let env = FunctionEnv::new(&mut store, ()); + let imports = imports! { + "env" => { + "extern_ref_identity" => Function::new_with_env(&mut store, &env, FunctionType::new([Type::ExternRef], [Type::ExternRef]), |_env, values| -> Result, _> { + Ok(vec![values[0].clone()]) + }), + "extern_ref_identity_native" => Function::new_typed(&mut store, |er: Option| -> Option { + er + }), + "get_new_extern_ref" => Function::new_with_env(&mut store, &env, FunctionType::new([], [Type::ExternRef]), |mut env, _| -> Result, _> { + let inner = + [("hello".to_string(), "world".to_string()), + ("color".to_string(), "orange".to_string())] + .iter() + .cloned() + .collect::>(); + let new_extern_ref = ExternRef::new(&mut env, inner); + Ok(vec![Value::ExternRef(Some(new_extern_ref))]) + }), + "get_new_extern_ref_native" => Function::new_typed_with_env(&mut store, &env, |mut env: FunctionEnvMut<()>| -> Option { + let inner = + [("hello".to_string(), "world".to_string()), + ("color".to_string(), "orange".to_string())] + .iter() + .cloned() + .collect::>(); + Some(ExternRef::new(&mut env.as_store_mut(), inner)) + }) + }, + }; - let f: TypedFunction<(), ExternRef> = instance.exports.get_typed_function(run)?; - let result: ExternRef = f.call()?; - assert!(result.is_null()); + let instance = Instance::new(&mut store, &module, &imports)?; + for run in &["run", "run_native"] { + let f: &Function = instance.exports.get_function(run)?; + let results = f.call(&mut store, &[]).unwrap(); + if let Value::ExternRef(er) = &results[0] { + assert!(er.is_none()); + } else { + panic!("result is not an extern ref!"); } - 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 = er.downcast().unwrap(); - assert_eq!(inner["hello"], "world"); - assert_eq!(inner["color"], "orange"); - } else { - panic!("result is not an extern ref!"); - } - - let f: TypedFunction<(), ExternRef> = - instance.exports.get_typed_function(get_hashmap)?; + let f: TypedFunction<(), Option> = + instance.exports.get_typed_function(&store, run)?; + let result: Option = f.call(&mut store)?; + assert!(result.is_none()); + } - let result: ExternRef = f.call()?; - let inner: &HashMap = result.downcast().unwrap(); + for get_hashmap in &["get_hashmap", "get_hashmap_native"] { + let f: &Function = instance.exports.get_function(get_hashmap)?; + let results = f.call(&mut store, &[]).unwrap(); + if let Value::ExternRef(er) = &results[0] { + let inner: &HashMap = + er.as_ref().unwrap().downcast(&mut store).unwrap(); assert_eq!(inner["hello"], "world"); assert_eq!(inner["color"], "orange"); + } else { + panic!("result is not an extern ref!"); } - Ok(()) + let f: TypedFunction<(), Option> = + instance.exports.get_typed_function(&store, get_hashmap)?; + + let result: Option = f.call(&mut store)?; + let inner: &HashMap = result.unwrap().downcast(&mut store).unwrap(); + assert_eq!(inner["hello"], "world"); + assert_eq!(inner["color"], "orange"); } + Ok(()) + } + #[test] - // TODO(reftypes): reenable this test - #[ignore] - fn extern_ref_ref_counting_basic() -> Result<()> { - let mut store = Store::default(); - let wat = r#"(module + fn extern_ref_ref_counting_basic() -> Result<()> { + let mut 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: TypedFunction = instance.exports.get_typed_function("drop")?; + let module = Module::new(&store, wat)?; + let instance = Instance::new(&mut store, &module, &imports! {})?; + let f: TypedFunction, ()> = + instance.exports.get_typed_function(&store, "drop")?; - let er = ExternRef::new(3u32); - f.call(er.clone())?; + let er = ExternRef::new(&mut store, 3u32); + f.call(&mut store, Some(er.clone()))?; - assert_eq!(er.downcast::().unwrap(), &3); - assert_eq!(er.strong_count(), 1); + let tmp: Option<&u32> = er.downcast(&mut store); + assert_eq!(tmp.unwrap(), &3); - Ok(()) - } + Ok(()) + } - #[test] - fn refs_in_globals() -> Result<()> { - let mut store = Store::default(); - let wat = r#"(module + #[test] + fn refs_in_globals() -> Result<()> { + let mut 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(Value::ExternRef(ExternRef::new(3u32)))?; + let module = Module::new(&store, wat)?; + let instance = Instance::new(&mut store, &module, &imports! {})?; + { + let er_global: &Global = instance.exports.get_global("er_global")?; - if let Value::ExternRef(er) = er_global.get() { - assert_eq!(er.downcast::().unwrap(), &3); - assert_eq!(er.strong_count(), 1); - } else { - panic!("Did not find extern ref in the global"); - } + if let Value::ExternRef(er) = er_global.get(&mut store) { + assert!(er.is_none()); + } else { + panic!("Did not find extern ref in the global"); + } + let extref = Some(ExternRef::new(&mut store, 3u32)); + er_global.set(&mut store, Value::ExternRef(extref))?; + + if let Value::ExternRef(er) = er_global.get(&mut store) { + let tmp: Option<&u32> = er.unwrap().downcast(&mut store); + assert_eq!(tmp.unwrap(), &3); + } else { + panic!("Did not find extern ref in the global"); } + } - { - let fr_global: &Global = instance.exports.get_global("fr_immutable_global")?; + { + let fr_global: &Global = instance.exports.get_global("fr_immutable_global")?; - if let Value::FuncRef(Some(f)) = fr_global.get() { - let native_func: TypedFunction<(), u32> = f.native()?; - assert_eq!(native_func.call()?, 73); - } else { - panic!("Did not find non-null func ref in the global"); - } + if let Value::FuncRef(Some(f)) = fr_global.get(&mut store) { + let native_func: TypedFunction<(), u32> = f.typed(&mut store)?; + assert_eq!(native_func.call(&mut store)?, 73); + } else { + panic!("Did not find non-null func ref in the global"); } + } - { - let fr_global: &Global = instance.exports.get_global("fr_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"); - } + if let Value::FuncRef(None) = fr_global.get(&mut store) { + } else { + panic!("Did not find a null func ref in the global"); + } - let f = Function::new_typed(&store, |arg1: i32, arg2: i32| -> i32 { arg1 + arg2 }); + let f = Function::new_typed(&mut store, |arg1: i32, arg2: i32| -> i32 { arg1 + arg2 }); - fr_global.set(Value::FuncRef(Some(f)))?; + fr_global.set(&mut store, Value::FuncRef(Some(f)))?; - if let Value::FuncRef(Some(f)) = fr_global.get() { - let native: TypedFunction<(i32, i32), i32> = f.native()?; - assert_eq!(native.call(5, 7)?, 12); - } else { - panic!("Did not find extern ref in the global"); - } + if let Value::FuncRef(Some(f)) = fr_global.get(&mut store) { + let native: TypedFunction<(i32, i32), i32> = f.typed(&mut store)?; + assert_eq!(native.call(&mut store, 5, 7)?, 12); + } else { + panic!("Did not find extern ref in the global"); } - - Ok(()) } - #[test] - fn extern_ref_ref_counting_table_basic() -> Result<()> { - let mut store = Store::default(); - let wat = r#"(module + Ok(()) + } + + #[test] + fn extern_ref_ref_counting_table_basic() -> Result<()> { + let mut 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) @@ -321,93 +321,90 @@ mod sys { (call $intermediate (local.get $er) (local.get $idx)) (local.get $er)) )"#; - let module = Module::new(&store, wat)?; - let instance = Instance::new(&module, &imports! {})?; + let module = Module::new(&store, wat)?; + let instance = Instance::new(&mut store, &module, &imports! {})?; - let f: TypedFunction<(ExternRef, i32), ExternRef> = - instance.exports.get_typed_function("insert_into_table")?; + let f: TypedFunction<(Option, i32), Option> = instance + .exports + .get_typed_function(&mut store, "insert_into_table")?; - let er = ExternRef::new(3usize); + let er = ExternRef::new(&mut store, 3usize); - let er = f.call(er, 1)?; - assert_eq!(er.strong_count(), 2); + let er = f.call(&mut store, Some(er), 1)?; + assert!(er.is_some()); - let table: &Table = instance.exports.get_table("table")?; + let table: &Table = instance.exports.get_table("table")?; - { - let er2 = table.get(1).unwrap().externref().unwrap(); - assert_eq!(er2.strong_count(), 3); - } + { + let er2 = table.get(&mut store, 1).unwrap(); + let er2 = er2.externref().unwrap(); + assert!(er2.is_some()); + } - assert_eq!(er.strong_count(), 2); - table.set(1, Value::ExternRef(ExternRef::null()))?; + assert!(er.is_some()); + table.set(&mut store, 1, Value::ExternRef(None))?; - assert_eq!(er.strong_count(), 1); + assert!(er.is_some()); - Ok(()) - } + Ok(()) + } - #[test] - // TODO(reftypes): reenable this test - #[ignore] - fn extern_ref_ref_counting_global_basic() -> Result<()> { - let mut store = Store::default(); - let wat = r#"(module + #[test] + fn extern_ref_ref_counting_global_basic() -> Result<()> { + let mut 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(Value::ExternRef(er.clone()))?; - assert_eq!(er.strong_count(), 2); - } - let get_from_global: TypedFunction<(), ExternRef> = - instance.exports.get_typed_function("get_from_global")?; - - let er = get_from_global.call()?; - assert_eq!(er.strong_count(), 2); - global.set(Value::ExternRef(ExternRef::null()))?; - assert_eq!(er.strong_count(), 1); + let module = Module::new(&store, wat)?; + let instance = Instance::new(&mut store, &module, &imports! {})?; - Ok(()) + let global: &Global = instance.exports.get_global("global")?; + { + let er = ExternRef::new(&mut store, 3usize); + global.set(&mut store, Value::ExternRef(Some(er.clone())))?; } + let get_from_global: TypedFunction<(), Option> = instance + .exports + .get_typed_function(&mut store, "get_from_global")?; - #[test] - // TODO(reftypes): reenable this test - #[ignore] - fn extern_ref_ref_counting_traps() -> Result<()> { - let mut store = Store::default(); - let wat = r#"(module + let er = get_from_global.call(&mut store)?; + assert!(er.is_some()); + global.set(&mut store, Value::ExternRef(None))?; + assert!(er.is_some()); + + Ok(()) + } + + #[test] + fn extern_ref_ref_counting_traps() -> Result<()> { + let mut 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 module = Module::new(&store, wat)?; + let instance = Instance::new(&mut store, &module, &imports! {})?; - let pass_extern_ref: TypedFunction = - instance.exports.get_typed_function("pass_extern_ref")?; + let pass_extern_ref: TypedFunction, ()> = instance + .exports + .get_typed_function(&mut store, "pass_extern_ref")?; - let er = ExternRef::new(3usize); - assert_eq!(er.strong_count(), 1); + let er = ExternRef::new(&mut store, 3usize); - let result = pass_extern_ref.call(er.clone()); - assert!(result.is_err()); - assert_eq!(er.strong_count(), 1); + let result = pass_extern_ref.call(&mut store, Some(er.clone())); + assert!(result.is_err()); - Ok(()) - } + Ok(()) + } - #[test] - fn extern_ref_ref_counting_table_instructions() -> Result<()> { - let mut store = Store::default(); - let wat = r#"(module + #[test] + fn extern_ref_ref_counting_table_instructions() -> Result<()> { + let mut 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) @@ -417,86 +414,77 @@ mod sys { (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: TypedFunction<(ExternRef, i32), i32> = - instance.exports.get_typed_function("grow_table_with_ref")?; - let fill_table_with_ref: TypedFunction<(ExternRef, i32, i32), ()> = - instance.exports.get_typed_function("fill_table_with_ref")?; - let copy_into_table2: TypedFunction<(), ()> = - instance.exports.get_typed_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::().unwrap(), 3); - assert_eq!(&e, &er1); - } - assert_eq!(er1.strong_count(), 9); - } + let module = Module::new(&store, wat)?; + let instance = Instance::new(&mut store, &module, &imports! {})?; + + let grow_table_with_ref: TypedFunction<(Option, i32), i32> = instance + .exports + .get_typed_function(&mut store, "grow_table_with_ref")?; + let fill_table_with_ref: TypedFunction<(Option, i32, i32), ()> = instance + .exports + .get_typed_function(&mut store, "fill_table_with_ref")?; + let copy_into_table2: TypedFunction<(), ()> = instance + .exports + .get_typed_function(&mut store, "copy_into_table2")?; + let table1: &Table = instance.exports.get_table("table1")?; + let table2: &Table = instance.exports.get_table("table2")?; + + let er1 = ExternRef::new(&mut store, 3usize); + let er2 = ExternRef::new(&mut store, 5usize); + let er3 = ExternRef::new(&mut store, 7usize); + { + let result = grow_table_with_ref.call(&mut store, Some(er1.clone()), 0)?; + assert_eq!(result, 2); - { - fill_table_with_ref.call(er2.clone(), 0, 2)?; - assert_eq!(er2.strong_count(), 3); - } + let result = grow_table_with_ref.call(&mut store, Some(er1.clone()), 10_000)?; + assert_eq!(result, -1); - { - table2.set(0, Value::ExternRef(er3.clone()))?; - table2.set(1, Value::ExternRef(er3.clone()))?; - table2.set(2, Value::ExternRef(er3.clone()))?; - table2.set(3, Value::ExternRef(er3.clone()))?; - table2.set(4, Value::ExternRef(er3.clone()))?; - assert_eq!(er3.strong_count(), 6); - } + let result = grow_table_with_ref.call(&mut store, Some(er1.clone()), 8)?; + assert_eq!(result, 2); - { - 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::().unwrap(); - match i { - 0 | 1 => assert_eq!(*value, 5), - 4 => assert_eq!(*value, 7), - _ => assert_eq!(*value, 3), - } - } + for i in 2..10 { + let v = table1.get(&mut store, i); + let e = v.as_ref().unwrap().unwrap_externref(); + let e_val: Option<&usize> = e.as_ref().unwrap().downcast(&mut store); + assert_eq!(*e_val.unwrap(), 3); } + } - { - for i in 0..table1.size() { - table1.set(i, Value::ExternRef(ExternRef::null()))?; - } - for i in 0..table2.size() { - table2.set(i, Value::ExternRef(ExternRef::null()))?; + { + fill_table_with_ref.call(&mut store, Some(er2.clone()), 0, 2)?; + } + + { + table2.set(&mut store, 0, Value::ExternRef(Some(er3.clone())))?; + table2.set(&mut store, 1, Value::ExternRef(Some(er3.clone())))?; + table2.set(&mut store, 2, Value::ExternRef(Some(er3.clone())))?; + table2.set(&mut store, 3, Value::ExternRef(Some(er3.clone())))?; + table2.set(&mut store, 4, Value::ExternRef(Some(er3.clone())))?; + } + + { + copy_into_table2.call(&mut store)?; + for i in 1..5 { + let v = table2.get(&mut store, i); + let e = v.as_ref().unwrap().unwrap_externref(); + let value: &usize = e.as_ref().unwrap().downcast(&mut store).unwrap(); + match i { + 0 | 1 => assert_eq!(*value, 5), + 4 => assert_eq!(*value, 7), + _ => assert_eq!(*value, 3), } } + } - assert_eq!(er1.strong_count(), 1); - assert_eq!(er2.strong_count(), 1); - assert_eq!(er3.strong_count(), 1); - - Ok(()) + { + for i in 0..table1.size(&mut store) { + table1.set(&mut store, i, Value::ExternRef(None))?; + } + for i in 0..table2.size(&mut store) { + table2.set(&mut store, i, Value::ExternRef(None))?; + } } - */ + + Ok(()) + } }