(use_epochs: bool)
| 28 | } |
| 29 | |
| 30 | fn smoke_test_gc_impl(use_epochs: bool) -> Result<()> { |
| 31 | let (mut store, module) = ref_types_module( |
| 32 | use_epochs, |
| 33 | r#" |
| 34 | (module |
| 35 | (import "" "" (func $do_gc)) |
| 36 | (func $recursive (export "func") (param i32 externref) (result externref) |
| 37 | local.get 0 |
| 38 | i32.eqz |
| 39 | if (result externref) |
| 40 | call $do_gc |
| 41 | local.get 1 |
| 42 | else |
| 43 | local.get 0 |
| 44 | i32.const 1 |
| 45 | i32.sub |
| 46 | local.get 1 |
| 47 | call $recursive |
| 48 | end |
| 49 | ) |
| 50 | ) |
| 51 | "#, |
| 52 | )?; |
| 53 | |
| 54 | let do_gc = Func::wrap(&mut store, |mut caller: Caller<'_, _>| { |
| 55 | // Do a GC with `externref`s on the stack in Wasm frames. |
| 56 | caller.gc(None) |
| 57 | }); |
| 58 | let instance = Instance::new(&mut store, &module, &[do_gc.into()])?; |
| 59 | let func = instance.get_func(&mut store, "func").unwrap(); |
| 60 | |
| 61 | let inner_dropped = Arc::new(AtomicBool::new(false)); |
| 62 | |
| 63 | { |
| 64 | let mut scope = RootScope::new(&mut store); |
| 65 | |
| 66 | let r = ExternRef::new(&mut scope, SetFlagOnDrop(inner_dropped.clone()))?; |
| 67 | { |
| 68 | let args = [Val::I32(5), Val::ExternRef(Some(r))]; |
| 69 | func.call(&mut scope, &args, &mut [Val::I32(0)])?; |
| 70 | } |
| 71 | |
| 72 | // Doing a GC should see that there aren't any `externref`s on the stack in |
| 73 | // Wasm frames anymore. |
| 74 | scope.as_context_mut().gc(None)?; |
| 75 | |
| 76 | // But the scope should still be rooting `r`. |
| 77 | assert!(!inner_dropped.load(SeqCst)); |
| 78 | } |
| 79 | |
| 80 | // Exiting the scope and unrooting `r` should have dropped the inner |
| 81 | // `SetFlagOnDrop` value. |
| 82 | store.gc(None)?; |
| 83 | assert!(inner_dropped.load(SeqCst)); |
| 84 | |
| 85 | Ok(()) |
| 86 | } |
| 87 |
no test coverage detected