;; This test has two components $C and $D where $D imports and calls $C
;; $C implements two resource types imported and used by $D
;; $D creates instances of both resource types, uses them and destroys them
(component
(component $C
(core module $Indirect
(table (export "ftbl") 2 funcref)
(type $FT (func (param i32)))
(func (export "R1-dtor") (param i32)
(call_indirect (type $FT) (local.get 0) (i32.const 0))
)
(func (export "R2-dtor") (param i32)
(call_indirect (type $FT) (local.get 0) (i32.const 1))
)
)
(core instance $indirect (instantiate $Indirect))
(type $R1' (resource (rep i32) (dtor (func $indirect "R1-dtor"))))
(type $R2' (resource (rep i32) (dtor (func $indirect "R2-dtor"))))
(export $R1 "R1" (type $R1'))
(export $R2 "R2" (type $R2'))
(canon resource.new $R1' (core func $R1.resource.new))
(canon resource.new $R2' (core func $R2.resource.new))
(core module $CM
(import "" "ftbl" (table 1 funcref))
(import "" "R1.resource.new" (func $R1.resource.new (param i32) (result i32)))
(import "" "R2.resource.new" (func $R2.resource.new (param i32) (result i32)))
(memory 1)
(global $num-live-R1 (mut i32) (i32.const 0))
(global $num-live-R2 (mut i32) (i32.const 0))
;; constructors
(func $make-R1 (export "make-R1") (result i32)
(local $h i32)
(global.set $num-live-R1 (i32.add (global.get $num-live-R1) (i32.const 1)))
(call $R1.resource.new (i32.add (i32.const 0x40) (global.get $num-live-R1)))
)
(func $make-R2 (export "make-R2") (result i32)
(local $h i32)
(global.set $num-live-R2 (i32.add (global.get $num-live-R2) (i32.const 1)))
(call $R2.resource.new (i32.add (i32.const 0x80) (global.get $num-live-R2)))
)
;; accessors
(func $get-rep-R1 (export "get-rep-R1") (param $rep i32) (result i32)
(local.get $rep)
)
(func $get-rep-R2 (export "get-rep-R2") (param $rep i32) (result i32)
(local.get $rep)
)
;; destructors
(func $R1-dtor (param $rep i32)
(if (i32.or (i32.lt_u (local.get $rep) (i32.const 0x41)) (i32.gt_u (local.get $rep) (i32.const 0x42)))
(then unreachable))
(if (i32.eqz (global.get $num-live-R1))
(then unreachable))
(global.set $num-live-R1 (i32.sub (global.get $num-live-R1) (i32.const 1)))
)
(func $R2-dtor (param $rep i32)
(if (i32.or (i32.lt_u (local.get $rep) (i32.const 0x81)) (i32.gt_u (local.get $rep) (i32.const 0x82)))
(then unreachable))
(if (i32.eqz (global.get $num-live-R2))
(then unreachable))
(global.set $num-live-R2 (i32.sub (global.get $num-live-R2) (i32.const 1)))
)
(func $num-live (export "num-live") (result i32)
(i32.add (global.get $num-live-R1) (global.get $num-live-R2))
)
(elem (i32.const 0) $R1-dtor $R2-dtor)
)
(core instance $cm (instantiate $CM (with "" (instance
(export "ftbl" (table $indirect "ftbl"))
(export "R1.resource.new" (func $R1.resource.new))
(export "R2.resource.new" (func $R2.resource.new))
))))
(func $make-R1 (export "make-R1") (result (own $R1)) (canon lift (core func $cm "make-R1")))
(func $make-R2 (export "make-R2") (result (own $R2)) (canon lift (core func $cm "make-R2")))
(func $get-rep-R1 (export "get-rep-R1") (param "r" (borrow $R1)) (result u32) (canon lift (core func $cm "get-rep-R1")))
(func $get-rep-R2 (export "get-rep-R2") (param "r" (borrow $R2)) (result u32) (canon lift (core func $cm "get-rep-R2")))
(func (export "num-live") (result u32) (canon lift (core func $cm "num-live")))
)
(component $D
(import "c" (instance $c
(export "R1" (type $R1 (sub resource)))
(export "R2" (type $R2 (sub resource)))
(export "make-R1" (func (result (own $R1))))
(export "make-R2" (func (result (own $R2))))
(export "get-rep-R1" (func (param "r" (borrow $R1)) (result u32)))
(export "get-rep-R2" (func (param "r" (borrow $R2)) (result u32)))
(export "num-live" (func (result u32)))
))
(core module $DM
(import "" "R1.resource.drop" (func $R1.resource.drop (param i32)))
(import "" "R2.resource.drop" (func $R2.resource.drop (param i32)))
(import "" "make-R1" (func $make-R1 (result i32)))
(import "" "make-R2" (func $make-R2 (result i32)))
(import "" "get-rep-R1" (func $get-rep-R1 (param i32) (result i32)))
(import "" "get-rep-R2" (func $get-rep-R2 (param i32) (result i32)))
(import "" "num-live" (func $num-live (result i32)))
(memory 1)
(func $run (export "run") (result i32)
(local $ret i32)
(local $h1 i32) (local $h2 i32) (local $h3 i32) (local $h4 i32)
;; create 4 resources
(local.set $h1 (call $make-R1))
(if (i32.ne (i32.const 1) (local.get $h1))
(then unreachable))
(local.set $h2 (call $make-R2))
(if (i32.ne (i32.const 2) (local.get $h2))
(then unreachable))
(local.set $h3 (call $make-R1))
(if (i32.ne (i32.const 3) (local.get $h3))
(then unreachable))
(local.set $h4 (call $make-R2))
(if (i32.ne (i32.const 4) (local.get $h4))
(then unreachable))
(if (i32.ne (i32.const 4) (call $num-live))
(then unreachable))
;; use and destroy resources
(if (i32.ne (i32.const 0x81) (call $get-rep-R2 (local.get $h2)))
(then unreachable))
(call $R2.resource.drop (local.get $h2))
(if (i32.ne (i32.const 0x41) (call $get-rep-R1 (local.get $h1)))
(then unreachable))
(call $R1.resource.drop (local.get $h1))
(if (i32.ne (i32.const 0x82) (call $get-rep-R2 (local.get $h4)))
(then unreachable))
(call $R2.resource.drop (local.get $h4))
(if (i32.ne (i32.const 0x42) (call $get-rep-R1 (local.get $h3)))
(then unreachable))
(call $R1.resource.drop (local.get $h3))
;; everything should be destroyed
(if (i32.ne (i32.const 0) (call $num-live))
(then unreachable))
(i32.const 42)
)
)
(alias export $c "R1" (type $R1))
(alias export $c "R2" (type $R2))
(canon resource.drop $R1 (core func $R1.resource.drop))
(canon resource.drop $R2 (core func $R2.resource.drop))
(canon lower (func $c "make-R1") (core func $make-R1'))
(canon lower (func $c "make-R2") (core func $make-R2'))
(canon lower (func $c "get-rep-R1") (core func $get-rep-R1'))
(canon lower (func $c "get-rep-R2") (core func $get-rep-R2'))
(canon lower (func $c "num-live") (core func $num-live'))
(core instance $dm (instantiate $DM (with "" (instance
(export "R1.resource.drop" (func $R1.resource.drop))
(export "R2.resource.drop" (func $R2.resource.drop))
(export "make-R1" (func $make-R1'))
(export "make-R2" (func $make-R2'))
(export "get-rep-R1" (func $get-rep-R1'))
(export "get-rep-R2" (func $get-rep-R2'))
(export "num-live" (func $num-live'))
))))
(func (export "run") (result u32) (canon lift (core func $dm "run")))
)
(instance $c (instantiate $C))
(instance $d (instantiate $D (with "c" (instance $c))))
(func (export "run") (alias export $d "run"))
)
(assert_return (invoke "run") (u32.const 42))