| 636 | #[test] |
| 637 | #[cfg_attr(miri, ignore)] |
| 638 | fn call_via_funcref() -> Result<()> { |
| 639 | static HITS: AtomicUsize = AtomicUsize::new(0); |
| 640 | |
| 641 | struct A; |
| 642 | |
| 643 | impl Drop for A { |
| 644 | fn drop(&mut self) { |
| 645 | HITS.fetch_add(1, SeqCst); |
| 646 | } |
| 647 | } |
| 648 | |
| 649 | let wasm = wat::parse_str( |
| 650 | r#" |
| 651 | (table $t 1 funcref) |
| 652 | (type $add (func (param i32 i32) (result i32))) |
| 653 | (func (export "call") (param funcref) (result i32 funcref) |
| 654 | (table.set $t (i32.const 0) (local.get 0)) |
| 655 | (call_indirect (type $add) (i32.const 3) (i32.const 4) (i32.const 0)) |
| 656 | (local.get 0) |
| 657 | ) |
| 658 | "#, |
| 659 | )?; |
| 660 | |
| 661 | let engine = Engine::default(); |
| 662 | let mut linker = Linker::new(&engine); |
| 663 | let a = A; |
| 664 | linker.func_wrap("", "", move |x: i32, y: i32| { |
| 665 | let _ = &a; |
| 666 | x + y |
| 667 | })?; |
| 668 | |
| 669 | let module = Module::new(&engine, &wasm)?; |
| 670 | let mut store = Store::new(&engine, ()); |
| 671 | let instance = Instance::new(&mut store, &module, &[])?; |
| 672 | |
| 673 | let f = linker.get(&mut store, "", "").unwrap().into_func().unwrap(); |
| 674 | let mut results = [Val::I32(0), Val::I32(0)]; |
| 675 | instance |
| 676 | .get_func(&mut store, "call") |
| 677 | .unwrap() |
| 678 | .call(&mut store, &[f.into()], &mut results)?; |
| 679 | assert_eq!(results[0].unwrap_i32(), 7); |
| 680 | |
| 681 | { |
| 682 | let f = results[1].unwrap_funcref().unwrap(); |
| 683 | let mut results = [Val::I32(0)]; |
| 684 | f.call(&mut store, &[1.into(), 2.into()], &mut results)?; |
| 685 | assert_eq!(results[0].unwrap_i32(), 3); |
| 686 | } |
| 687 | |
| 688 | assert_eq!(HITS.load(SeqCst), 0); |
| 689 | |
| 690 | drop(store); |
| 691 | |
| 692 | assert_eq!(HITS.load(SeqCst), 0); |
| 693 | |
| 694 | drop(linker); |
| 695 | |