summaryrefslogtreecommitdiff
path: root/test/spec
diff options
context:
space:
mode:
Diffstat (limited to 'test/spec')
-rw-r--r--test/spec/return_call.wast202
-rw-r--r--test/spec/return_call_eh.wast35
-rw-r--r--test/spec/return_call_indirect.wast536
-rw-r--r--test/spec/return_call_ref.wast377
4 files changed, 1150 insertions, 0 deletions
diff --git a/test/spec/return_call.wast b/test/spec/return_call.wast
new file mode 100644
index 000000000..9423159ff
--- /dev/null
+++ b/test/spec/return_call.wast
@@ -0,0 +1,202 @@
+;; Test `return_call` operator
+
+(module
+ ;; Auxiliary definitions
+ (func $const-i32 (result i32) (i32.const 0x132))
+ (func $const-i64 (result i64) (i64.const 0x164))
+ (func $const-f32 (result f32) (f32.const 0xf32))
+ (func $const-f64 (result f64) (f64.const 0xf64))
+
+ (func $id-i32 (param i32) (result i32) (local.get 0))
+ (func $id-i64 (param i64) (result i64) (local.get 0))
+ (func $id-f32 (param f32) (result f32) (local.get 0))
+ (func $id-f64 (param f64) (result f64) (local.get 0))
+
+ (func $f32-i32 (param f32 i32) (result i32) (local.get 1))
+ (func $i32-i64 (param i32 i64) (result i64) (local.get 1))
+ (func $f64-f32 (param f64 f32) (result f32) (local.get 1))
+ (func $i64-f64 (param i64 f64) (result f64) (local.get 1))
+
+ ;; Typing
+
+ (func (export "type-i32") (result i32) (return_call $const-i32))
+ (func (export "type-i64") (result i64) (return_call $const-i64))
+ (func (export "type-f32") (result f32) (return_call $const-f32))
+ (func (export "type-f64") (result f64) (return_call $const-f64))
+
+ (func (export "type-first-i32") (result i32) (return_call $id-i32 (i32.const 32)))
+ (func (export "type-first-i64") (result i64) (return_call $id-i64 (i64.const 64)))
+ (func (export "type-first-f32") (result f32) (return_call $id-f32 (f32.const 1.32)))
+ (func (export "type-first-f64") (result f64) (return_call $id-f64 (f64.const 1.64)))
+
+ (func (export "type-second-i32") (result i32)
+ (return_call $f32-i32 (f32.const 32.1) (i32.const 32))
+ )
+ (func (export "type-second-i64") (result i64)
+ (return_call $i32-i64 (i32.const 32) (i64.const 64))
+ )
+ (func (export "type-second-f32") (result f32)
+ (return_call $f64-f32 (f64.const 64) (f32.const 32))
+ )
+ (func (export "type-second-f64") (result f64)
+ (return_call $i64-f64 (i64.const 64) (f64.const 64.1))
+ )
+
+ ;; Recursion
+
+ (func $fac-acc (export "fac-acc") (param i64 i64) (result i64)
+ (if (result i64) (i64.eqz (local.get 0))
+ (then (local.get 1))
+ (else
+ (return_call $fac-acc
+ (i64.sub (local.get 0) (i64.const 1))
+ (i64.mul (local.get 0) (local.get 1))
+ )
+ )
+ )
+ )
+
+ (func $count (export "count") (param i64) (result i64)
+ (if (result i64) (i64.eqz (local.get 0))
+ (then (local.get 0))
+ (else (return_call $count (i64.sub (local.get 0) (i64.const 1))))
+ )
+ )
+
+ (func $even (export "even") (param i64) (result i32)
+ (if (result i32) (i64.eqz (local.get 0))
+ (then (i32.const 44))
+ (else (return_call $odd (i64.sub (local.get 0) (i64.const 1))))
+ )
+ )
+ (func $odd (export "odd") (param i64) (result i32)
+ (if (result i32) (i64.eqz (local.get 0))
+ (then (i32.const 99))
+ (else (return_call $even (i64.sub (local.get 0) (i64.const 1))))
+ )
+ )
+)
+
+(assert_return (invoke "type-i32") (i32.const 0x132))
+(assert_return (invoke "type-i64") (i64.const 0x164))
+(assert_return (invoke "type-f32") (f32.const 0xf32))
+(assert_return (invoke "type-f64") (f64.const 0xf64))
+
+(assert_return (invoke "type-first-i32") (i32.const 32))
+(assert_return (invoke "type-first-i64") (i64.const 64))
+(assert_return (invoke "type-first-f32") (f32.const 1.32))
+(assert_return (invoke "type-first-f64") (f64.const 1.64))
+
+(assert_return (invoke "type-second-i32") (i32.const 32))
+(assert_return (invoke "type-second-i64") (i64.const 64))
+(assert_return (invoke "type-second-f32") (f32.const 32))
+(assert_return (invoke "type-second-f64") (f64.const 64.1))
+
+(assert_return (invoke "fac-acc" (i64.const 0) (i64.const 1)) (i64.const 1))
+(assert_return (invoke "fac-acc" (i64.const 1) (i64.const 1)) (i64.const 1))
+(assert_return (invoke "fac-acc" (i64.const 5) (i64.const 1)) (i64.const 120))
+(assert_return
+ (invoke "fac-acc" (i64.const 25) (i64.const 1))
+ (i64.const 7034535277573963776)
+)
+
+(assert_return (invoke "count" (i64.const 0)) (i64.const 0))
+(assert_return (invoke "count" (i64.const 1000)) (i64.const 0))
+(assert_return (invoke "count" (i64.const 1000000)) (i64.const 0))
+
+(assert_return (invoke "even" (i64.const 0)) (i32.const 44))
+(assert_return (invoke "even" (i64.const 1)) (i32.const 99))
+(assert_return (invoke "even" (i64.const 100)) (i32.const 44))
+(assert_return (invoke "even" (i64.const 77)) (i32.const 99))
+(assert_return (invoke "even" (i64.const 1000000)) (i32.const 44))
+(assert_return (invoke "even" (i64.const 1000001)) (i32.const 99))
+(assert_return (invoke "odd" (i64.const 0)) (i32.const 99))
+(assert_return (invoke "odd" (i64.const 1)) (i32.const 44))
+(assert_return (invoke "odd" (i64.const 200)) (i32.const 99))
+(assert_return (invoke "odd" (i64.const 77)) (i32.const 44))
+(assert_return (invoke "odd" (i64.const 1000000)) (i32.const 99))
+(assert_return (invoke "odd" (i64.const 999999)) (i32.const 44))
+
+
+;; Invalid typing
+
+(assert_invalid
+ (module
+ (func $type-void-vs-num (result i32) (return_call 1) (i32.const 0))
+ (func)
+ )
+ "type mismatch"
+)
+(assert_invalid
+ (module
+ (func $type-num-vs-num (result i32) (return_call 1) (i32.const 0))
+ (func (result i64) (i64.const 1))
+ )
+ "type mismatch"
+)
+
+(assert_invalid
+ (module
+ (func $arity-0-vs-1 (return_call 1))
+ (func (param i32))
+ )
+ "type mismatch"
+)
+(assert_invalid
+ (module
+ (func $arity-0-vs-2 (return_call 1))
+ (func (param f64 i32))
+ )
+ "type mismatch"
+)
+
+;; (module
+;; (func $arity-1-vs-0 (i32.const 1) (return_call 1))
+;; (func)
+;; )
+
+;; (module
+;; (func $arity-2-vs-0 (f64.const 2) (i32.const 1) (return_call 1))
+;; (func)
+;; )
+
+(assert_invalid
+ (module
+ (func $type-first-void-vs-num (return_call 1 (nop) (i32.const 1)))
+ (func (param i32 i32))
+ )
+ "type mismatch"
+)
+(assert_invalid
+ (module
+ (func $type-second-void-vs-num (return_call 1 (i32.const 1) (nop)))
+ (func (param i32 i32))
+ )
+ "type mismatch"
+)
+(assert_invalid
+ (module
+ (func $type-first-num-vs-num (return_call 1 (f64.const 1) (i32.const 1)))
+ (func (param i32 f64))
+ )
+ "type mismatch"
+)
+(assert_invalid
+ (module
+ (func $type-second-num-vs-num (return_call 1 (i32.const 1) (f64.const 1)))
+ (func (param f64 i32))
+ )
+ "type mismatch"
+)
+
+
+;; Unbound function
+
+(assert_invalid
+ (module (func $unbound-func (return_call 1)))
+ "unknown function"
+)
+(assert_invalid
+ (module (func $large-func (return_call 1012321300)))
+ "unknown function"
+)
diff --git a/test/spec/return_call_eh.wast b/test/spec/return_call_eh.wast
new file mode 100644
index 000000000..e85fdf7c6
--- /dev/null
+++ b/test/spec/return_call_eh.wast
@@ -0,0 +1,35 @@
+;; Test the combination of 'return_call' with exception handling
+
+(module
+ (tag $t)
+
+ (func $test (export "test") (result i32)
+ (try (result i32)
+ (do
+ (call $return-call-in-try)
+ )
+ (catch_all
+ ;; Catch the exception thrown from $return-callee
+ (i32.const 42)
+ )
+ )
+
+ )
+
+ (func $return-call-in-try (result i32)
+ (try (result i32)
+ (do
+ (return_call $return-callee)
+ )
+ (catch_all
+ (unreachable)
+ )
+ )
+ )
+
+ (func $return-callee (result i32)
+ (throw $t)
+ )
+)
+
+(assert_return (invoke "test") (i32.const 42))
diff --git a/test/spec/return_call_indirect.wast b/test/spec/return_call_indirect.wast
new file mode 100644
index 000000000..27f1dcdbf
--- /dev/null
+++ b/test/spec/return_call_indirect.wast
@@ -0,0 +1,536 @@
+;; Test `return_call_indirect` operator
+
+(module
+ ;; Auxiliary definitions
+ (type $proc (func))
+ (type $out-i32 (func (result i32)))
+ (type $out-i64 (func (result i64)))
+ (type $out-f32 (func (result f32)))
+ (type $out-f64 (func (result f64)))
+ (type $over-i32 (func (param i32) (result i32)))
+ (type $over-i64 (func (param i64) (result i64)))
+ (type $over-f32 (func (param f32) (result f32)))
+ (type $over-f64 (func (param f64) (result f64)))
+ (type $f32-i32 (func (param f32 i32) (result i32)))
+ (type $i32-i64 (func (param i32 i64) (result i64)))
+ (type $f64-f32 (func (param f64 f32) (result f32)))
+ (type $i64-f64 (func (param i64 f64) (result f64)))
+ (type $over-i32-duplicate (func (param i32) (result i32)))
+ (type $over-i64-duplicate (func (param i64) (result i64)))
+ (type $over-f32-duplicate (func (param f32) (result f32)))
+ (type $over-f64-duplicate (func (param f64) (result f64)))
+
+ (func $const-i32 (type $out-i32) (i32.const 0x132))
+ (func $const-i64 (type $out-i64) (i64.const 0x164))
+ (func $const-f32 (type $out-f32) (f32.const 0xf32))
+ (func $const-f64 (type $out-f64) (f64.const 0xf64))
+
+ (func $id-i32 (type $over-i32) (local.get 0))
+ (func $id-i64 (type $over-i64) (local.get 0))
+ (func $id-f32 (type $over-f32) (local.get 0))
+ (func $id-f64 (type $over-f64) (local.get 0))
+
+ (func $i32-i64 (type $i32-i64) (local.get 1))
+ (func $i64-f64 (type $i64-f64) (local.get 1))
+ (func $f32-i32 (type $f32-i32) (local.get 1))
+ (func $f64-f32 (type $f64-f32) (local.get 1))
+
+ (func $over-i32-duplicate (type $over-i32-duplicate) (local.get 0))
+ (func $over-i64-duplicate (type $over-i64-duplicate) (local.get 0))
+ (func $over-f32-duplicate (type $over-f32-duplicate) (local.get 0))
+ (func $over-f64-duplicate (type $over-f64-duplicate) (local.get 0))
+
+ (table funcref
+ (elem
+ $const-i32 $const-i64 $const-f32 $const-f64
+ $id-i32 $id-i64 $id-f32 $id-f64
+ $f32-i32 $i32-i64 $f64-f32 $i64-f64
+ $fac $fac-acc $even $odd
+ $over-i32-duplicate $over-i64-duplicate
+ $over-f32-duplicate $over-f64-duplicate
+ )
+ )
+
+ ;; Syntax
+
+ (func
+ (return_call_indirect (i32.const 0))
+ (return_call_indirect (param i64) (i64.const 0) (i32.const 0))
+ (return_call_indirect (param i64) (param) (param f64 i32 i64)
+ (i64.const 0) (f64.const 0) (i32.const 0) (i64.const 0) (i32.const 0)
+ )
+ (return_call_indirect (result) (i32.const 0))
+ )
+
+ (func (result i32)
+ (return_call_indirect (result i32) (i32.const 0))
+ (return_call_indirect (result i32) (result) (i32.const 0))
+ (return_call_indirect (param i64) (result i32) (i64.const 0) (i32.const 0))
+ (return_call_indirect
+ (param) (param i64) (param) (param f64 i32 i64) (param) (param)
+ (result) (result i32) (result) (result)
+ (i64.const 0) (f64.const 0) (i32.const 0) (i64.const 0) (i32.const 0)
+ )
+ )
+
+ (func (result i64)
+ (return_call_indirect (type $over-i64) (param i64) (result i64)
+ (i64.const 0) (i32.const 0)
+ )
+ )
+
+ ;; Typing
+
+ (func (export "type-i32") (result i32)
+ (return_call_indirect (type $out-i32) (i32.const 0))
+ )
+ (func (export "type-i64") (result i64)
+ (return_call_indirect (type $out-i64) (i32.const 1))
+ )
+ (func (export "type-f32") (result f32)
+ (return_call_indirect (type $out-f32) (i32.const 2))
+ )
+ (func (export "type-f64") (result f64)
+ (return_call_indirect (type $out-f64) (i32.const 3))
+ )
+
+ (func (export "type-index") (result i64)
+ (return_call_indirect (type $over-i64) (i64.const 100) (i32.const 5))
+ )
+
+ (func (export "type-first-i32") (result i32)
+ (return_call_indirect (type $over-i32) (i32.const 32) (i32.const 4))
+ )
+ (func (export "type-first-i64") (result i64)
+ (return_call_indirect (type $over-i64) (i64.const 64) (i32.const 5))
+ )
+ (func (export "type-first-f32") (result f32)
+ (return_call_indirect (type $over-f32) (f32.const 1.32) (i32.const 6))
+ )
+ (func (export "type-first-f64") (result f64)
+ (return_call_indirect (type $over-f64) (f64.const 1.64) (i32.const 7))
+ )
+
+ (func (export "type-second-i32") (result i32)
+ (return_call_indirect (type $f32-i32)
+ (f32.const 32.1) (i32.const 32) (i32.const 8)
+ )
+ )
+ (func (export "type-second-i64") (result i64)
+ (return_call_indirect (type $i32-i64)
+ (i32.const 32) (i64.const 64) (i32.const 9)
+ )
+ )
+ (func (export "type-second-f32") (result f32)
+ (return_call_indirect (type $f64-f32)
+ (f64.const 64) (f32.const 32) (i32.const 10)
+ )
+ )
+ (func (export "type-second-f64") (result f64)
+ (return_call_indirect (type $i64-f64)
+ (i64.const 64) (f64.const 64.1) (i32.const 11)
+ )
+ )
+
+ ;; Dispatch
+
+ (func (export "dispatch") (param i32 i64) (result i64)
+ (return_call_indirect (type $over-i64) (local.get 1) (local.get 0))
+ )
+
+ (func (export "dispatch-structural") (param i32) (result i64)
+ (return_call_indirect (type $over-i64-duplicate)
+ (i64.const 9) (local.get 0)
+ )
+ )
+
+ ;; Multiple tables
+
+ (table $tab2 funcref (elem $tab-f1))
+ (table $tab3 funcref (elem $tab-f2))
+
+ (func $tab-f1 (result i32) (i32.const 0x133))
+ (func $tab-f2 (result i32) (i32.const 0x134))
+
+ (func (export "call-tab") (param $i i32) (result i32)
+ (if (i32.eq (local.get $i) (i32.const 0))
+ (then (return_call_indirect (type $out-i32) (i32.const 0)))
+ )
+ (if (i32.eq (local.get $i) (i32.const 1))
+ (then (return_call_indirect $tab2 (type $out-i32) (i32.const 0)))
+ )
+ (if (i32.eq (local.get $i) (i32.const 2))
+ (then (return_call_indirect $tab3 (type $out-i32) (i32.const 0)))
+ )
+ (i32.const 0)
+ )
+
+ ;; Recursion
+
+ (func $fac (export "fac") (type $over-i64)
+ (return_call_indirect (param i64 i64) (result i64)
+ (local.get 0) (i64.const 1) (i32.const 13)
+ )
+ )
+
+ (func $fac-acc (param i64 i64) (result i64)
+ (if (result i64) (i64.eqz (local.get 0))
+ (then (local.get 1))
+ (else
+ (return_call_indirect (param i64 i64) (result i64)
+ (i64.sub (local.get 0) (i64.const 1))
+ (i64.mul (local.get 0) (local.get 1))
+ (i32.const 13)
+ )
+ )
+ )
+ )
+
+ (func $even (export "even") (param i32) (result i32)
+ (if (result i32) (i32.eqz (local.get 0))
+ (then (i32.const 44))
+ (else
+ (return_call_indirect (type $over-i32)
+ (i32.sub (local.get 0) (i32.const 1))
+ (i32.const 15)
+ )
+ )
+ )
+ )
+ (func $odd (export "odd") (param i32) (result i32)
+ (if (result i32) (i32.eqz (local.get 0))
+ (then (i32.const 99))
+ (else
+ (return_call_indirect (type $over-i32)
+ (i32.sub (local.get 0) (i32.const 1))
+ (i32.const 14)
+ )
+ )
+ )
+ )
+)
+
+(assert_return (invoke "type-i32") (i32.const 0x132))
+(assert_return (invoke "type-i64") (i64.const 0x164))
+(assert_return (invoke "type-f32") (f32.const 0xf32))
+(assert_return (invoke "type-f64") (f64.const 0xf64))
+
+(assert_return (invoke "type-index") (i64.const 100))
+
+(assert_return (invoke "type-first-i32") (i32.const 32))
+(assert_return (invoke "type-first-i64") (i64.const 64))
+(assert_return (invoke "type-first-f32") (f32.const 1.32))
+(assert_return (invoke "type-first-f64") (f64.const 1.64))
+
+(assert_return (invoke "type-second-i32") (i32.const 32))
+(assert_return (invoke "type-second-i64") (i64.const 64))
+(assert_return (invoke "type-second-f32") (f32.const 32))
+(assert_return (invoke "type-second-f64") (f64.const 64.1))
+
+(assert_return (invoke "dispatch" (i32.const 5) (i64.const 2)) (i64.const 2))
+(assert_return (invoke "dispatch" (i32.const 5) (i64.const 5)) (i64.const 5))
+(assert_return (invoke "dispatch" (i32.const 12) (i64.const 5)) (i64.const 120))
+(assert_return (invoke "dispatch" (i32.const 17) (i64.const 2)) (i64.const 2))
+(assert_trap (invoke "dispatch" (i32.const 0) (i64.const 2)) "indirect call type mismatch")
+(assert_trap (invoke "dispatch" (i32.const 15) (i64.const 2)) "indirect call type mismatch")
+(assert_trap (invoke "dispatch" (i32.const 20) (i64.const 2)) "undefined element")
+(assert_trap (invoke "dispatch" (i32.const -1) (i64.const 2)) "undefined element")
+(assert_trap (invoke "dispatch" (i32.const 1213432423) (i64.const 2)) "undefined element")
+
+(assert_return (invoke "dispatch-structural" (i32.const 5)) (i64.const 9))
+(assert_return (invoke "dispatch-structural" (i32.const 5)) (i64.const 9))
+(assert_return (invoke "dispatch-structural" (i32.const 12)) (i64.const 362880))
+(assert_return (invoke "dispatch-structural" (i32.const 17)) (i64.const 9))
+(assert_trap (invoke "dispatch-structural" (i32.const 11)) "indirect call type mismatch")
+(assert_trap (invoke "dispatch-structural" (i32.const 16)) "indirect call type mismatch")
+
+(assert_return (invoke "call-tab" (i32.const 0)) (i32.const 0x132))
+(assert_return (invoke "call-tab" (i32.const 1)) (i32.const 0x133))
+(assert_return (invoke "call-tab" (i32.const 2)) (i32.const 0x134))
+
+(assert_return (invoke "fac" (i64.const 0)) (i64.const 1))
+(assert_return (invoke "fac" (i64.const 1)) (i64.const 1))
+(assert_return (invoke "fac" (i64.const 5)) (i64.const 120))
+(assert_return (invoke "fac" (i64.const 25)) (i64.const 7034535277573963776))
+
+(assert_return (invoke "even" (i32.const 0)) (i32.const 44))
+(assert_return (invoke "even" (i32.const 1)) (i32.const 99))
+(assert_return (invoke "even" (i32.const 100)) (i32.const 44))
+(assert_return (invoke "even" (i32.const 77)) (i32.const 99))
+(assert_return (invoke "even" (i32.const 100000)) (i32.const 44))
+(assert_return (invoke "even" (i32.const 111111)) (i32.const 99))
+(assert_return (invoke "odd" (i32.const 0)) (i32.const 99))
+(assert_return (invoke "odd" (i32.const 1)) (i32.const 44))
+(assert_return (invoke "odd" (i32.const 200)) (i32.const 99))
+(assert_return (invoke "odd" (i32.const 77)) (i32.const 44))
+(assert_return (invoke "odd" (i32.const 200002)) (i32.const 99))
+(assert_return (invoke "odd" (i32.const 300003)) (i32.const 44))
+
+
+;; Invalid syntax
+
+(assert_malformed
+ (module quote
+ "(type $sig (func (param i32) (result i32)))"
+ "(table 0 funcref)"
+ "(func (result i32)"
+ " (return_call_indirect (type $sig) (result i32) (param i32)"
+ " (i32.const 0) (i32.const 0)"
+ " )"
+ ")"
+ )
+ "unexpected token"
+)
+(assert_malformed
+ (module quote
+ "(type $sig (func (param i32) (result i32)))"
+ "(table 0 funcref)"
+ "(func (result i32)"
+ " (return_call_indirect (param i32) (type $sig) (result i32)"
+ " (i32.const 0) (i32.const 0)"
+ " )"
+ ")"
+ )
+ "unexpected token"
+)
+(assert_malformed
+ (module quote
+ "(type $sig (func (param i32) (result i32)))"
+ "(table 0 funcref)"
+ "(func (result i32)"
+ " (return_call_indirect (param i32) (result i32) (type $sig)"
+ " (i32.const 0) (i32.const 0)"
+ " )"
+ ")"
+ )
+ "unexpected token"
+)
+(assert_malformed
+ (module quote
+ "(type $sig (func (param i32) (result i32)))"
+ "(table 0 funcref)"
+ "(func (result i32)"
+ " (return_call_indirect (result i32) (type $sig) (param i32)"
+ " (i32.const 0) (i32.const 0)"
+ " )"
+ ")"
+ )
+ "unexpected token"
+)
+(assert_malformed
+ (module quote
+ "(type $sig (func (param i32) (result i32)))"
+ "(table 0 funcref)"
+ "(func (result i32)"
+ " (return_call_indirect (result i32) (param i32) (type $sig)"
+ " (i32.const 0) (i32.const 0)"
+ " )"
+ ")"
+ )
+ "unexpected token"
+)
+(assert_malformed
+ (module quote
+ "(table 0 funcref)"
+ "(func (result i32)"
+ " (return_call_indirect (result i32) (param i32)"
+ " (i32.const 0) (i32.const 0)"
+ " )"
+ ")"
+ )
+ "unexpected token"
+)
+
+(assert_malformed
+ (module quote
+ "(table 0 funcref)"
+ "(func (return_call_indirect (param $x i32) (i32.const 0) (i32.const 0)))"
+ )
+ "unexpected token"
+)
+(assert_malformed
+ (module quote
+ "(type $sig (func))"
+ "(table 0 funcref)"
+ "(func (result i32)"
+ " (return_call_indirect (type $sig) (result i32) (i32.const 0))"
+ ")"
+ )
+ "inline function type"
+)
+(assert_malformed
+ (module quote
+ "(type $sig (func (param i32) (result i32)))"
+ "(table 0 funcref)"
+ "(func (result i32)"
+ " (return_call_indirect (type $sig) (result i32) (i32.const 0))"
+ ")"
+ )
+ "inline function type"
+)
+(assert_malformed
+ (module quote
+ "(type $sig (func (param i32) (result i32)))"
+ "(table 0 funcref)"
+ "(func"
+ " (return_call_indirect (type $sig) (param i32)"
+ " (i32.const 0) (i32.const 0)"
+ " )"
+ ")"
+ )
+ "inline function type"
+)
+(assert_malformed
+ (module quote
+ "(type $sig (func (param i32 i32) (result i32)))"
+ "(table 0 funcref)"
+ "(func (result i32)"
+ " (return_call_indirect (type $sig) (param i32) (result i32)"
+ " (i32.const 0) (i32.const 0)"
+ " )"
+ ")"
+ )
+ "inline function type"
+)
+
+;; Invalid typing
+
+(assert_invalid
+ (module
+ (type (func))
+ (func $no-table (return_call_indirect (type 0) (i32.const 0)))
+ )
+ "unknown table"
+)
+
+;; (assert_invalid
+;; (module
+;; (type (func))
+;; (table 0 funcref)
+;; (func $type-void-vs-num (i32.eqz (return_call_indirect (type 0) (i32.const 0))))
+;; )
+;; "type mismatch"
+;; )
+(assert_invalid
+ (module
+ (type (func (result i64)))
+ (table 0 funcref)
+ (func $type-num-vs-num (i32.eqz (return_call_indirect (type 0) (i32.const 0))))
+ )
+ "type mismatch"
+)
+
+(assert_invalid
+ (module
+ (type (func (param i32)))
+ (table 0 funcref)
+ (func $arity-0-vs-1 (return_call_indirect (type 0) (i32.const 0)))
+ )
+ "type mismatch"
+)
+(assert_invalid
+ (module
+ (type (func (param f64 i32)))
+ (table 0 funcref)
+ (func $arity-0-vs-2 (return_call_indirect (type 0) (i32.const 0)))
+ )
+ "type mismatch"
+)
+
+;; (module
+;; (type (func))
+;; (table 0 funcref)
+;; (func $arity-1-vs-0 (return_call_indirect (type 0) (i32.const 1) (i32.const 0)))
+;; )
+
+;; (module
+;; (type (func))
+;; (table 0 funcref)
+;; (func $arity-2-vs-0
+;; (return_call_indirect (type 0) (f64.const 2) (i32.const 1) (i32.const 0))
+;; )
+;; )
+
+(assert_invalid
+ (module
+ (type (func (param i32)))
+ (table 0 funcref)
+ (func $type-func-void-vs-i32 (return_call_indirect (type 0) (i32.const 1) (nop)))
+ )
+ "type mismatch"
+)
+(assert_invalid
+ (module
+ (type (func (param i32)))
+ (table 0 funcref)
+ (func $type-func-num-vs-i32 (return_call_indirect (type 0) (i32.const 0) (i64.const 1)))
+ )
+ "type mismatch"
+)
+
+(assert_invalid
+ (module
+ (type (func (param i32 i32)))
+ (table 0 funcref)
+ (func $type-first-void-vs-num
+ (return_call_indirect (type 0) (nop) (i32.const 1) (i32.const 0))
+ )
+ )
+ "type mismatch"
+)
+(assert_invalid
+ (module
+ (type (func (param i32 i32)))
+ (table 0 funcref)
+ (func $type-second-void-vs-num
+ (return_call_indirect (type 0) (i32.const 1) (nop) (i32.const 0))
+ )
+ )
+ "type mismatch"
+)
+(assert_invalid
+ (module
+ (type (func (param i32 f64)))
+ (table 0 funcref)
+ (func $type-first-num-vs-num
+ (return_call_indirect (type 0) (f64.const 1) (i32.const 1) (i32.const 0))
+ )
+ )
+ "type mismatch"
+)
+(assert_invalid
+ (module
+ (type (func (param f64 i32)))
+ (table 0 funcref)
+ (func $type-second-num-vs-num
+ (return_call_indirect (type 0) (i32.const 1) (f64.const 1) (i32.const 0))
+ )
+ )
+ "type mismatch"
+)
+
+
+;; Unbound type
+
+(assert_invalid
+ (module
+ (table 0 funcref)
+ (func $unbound-type (return_call_indirect (type 1) (i32.const 0)))
+ )
+ "unknown type"
+)
+(assert_invalid
+ (module
+ (table 0 funcref)
+ (func $large-type (return_call_indirect (type 1012321300) (i32.const 0)))
+ )
+ "unknown type"
+)
+
+
+;; Unbound function in table
+
+(assert_invalid
+ (module (table funcref (elem 0 0)))
+ "unknown function 0"
+)
diff --git a/test/spec/return_call_ref.wast b/test/spec/return_call_ref.wast
new file mode 100644
index 000000000..6bb5d2a14
--- /dev/null
+++ b/test/spec/return_call_ref.wast
@@ -0,0 +1,377 @@
+;; Test `return_call_ref` operator
+
+(module
+ ;; Auxiliary definitions
+ (type $proc (func))
+ (type $-i32 (func (result i32)))
+ (type $-i64 (func (result i64)))
+ (type $-f32 (func (result f32)))
+ (type $-f64 (func (result f64)))
+
+ (type $i32-i32 (func (param i32) (result i32)))
+ (type $i64-i64 (func (param i64) (result i64)))
+ (type $f32-f32 (func (param f32) (result f32)))
+ (type $f64-f64 (func (param f64) (result f64)))
+
+ (type $f32-i32 (func (param f32 i32) (result i32)))
+ (type $i32-i64 (func (param i32 i64) (result i64)))
+ (type $f64-f32 (func (param f64 f32) (result f32)))
+ (type $i64-f64 (func (param i64 f64) (result f64)))
+
+ (type $i64i64-i64 (func (param i64 i64) (result i64)))
+
+ (func $const-i32 (result i32) (i32.const 0x132))
+ (func $const-i64 (result i64) (i64.const 0x164))
+ (func $const-f32 (result f32) (f32.const 0xf32))
+ (func $const-f64 (result f64) (f64.const 0xf64))
+
+ (func $id-i32 (param i32) (result i32) (local.get 0))
+ (func $id-i64 (param i64) (result i64) (local.get 0))
+ (func $id-f32 (param f32) (result f32) (local.get 0))
+ (func $id-f64 (param f64) (result f64) (local.get 0))
+
+ (func $f32-i32 (param f32 i32) (result i32) (local.get 1))
+ (func $i32-i64 (param i32 i64) (result i64) (local.get 1))
+ (func $f64-f32 (param f64 f32) (result f32) (local.get 1))
+ (func $i64-f64 (param i64 f64) (result f64) (local.get 1))
+
+ (global $const-i32 (ref $-i32) (ref.func $const-i32))
+ (global $const-i64 (ref $-i64) (ref.func $const-i64))
+ (global $const-f32 (ref $-f32) (ref.func $const-f32))
+ (global $const-f64 (ref $-f64) (ref.func $const-f64))
+
+ (global $id-i32 (ref $i32-i32) (ref.func $id-i32))
+ (global $id-i64 (ref $i64-i64) (ref.func $id-i64))
+ (global $id-f32 (ref $f32-f32) (ref.func $id-f32))
+ (global $id-f64 (ref $f64-f64) (ref.func $id-f64))
+
+ (global $f32-i32 (ref $f32-i32) (ref.func $f32-i32))
+ (global $i32-i64 (ref $i32-i64) (ref.func $i32-i64))
+ (global $f64-f32 (ref $f64-f32) (ref.func $f64-f32))
+ (global $i64-f64 (ref $i64-f64) (ref.func $i64-f64))
+
+ (elem declare func
+ $const-i32 $const-i64 $const-f32 $const-f64
+ $id-i32 $id-i64 $id-f32 $id-f64
+ $f32-i32 $i32-i64 $f64-f32 $i64-f64
+ )
+
+ ;; Typing
+
+ (func (export "type-i32") (result i32)
+ (return_call_ref $-i32 (global.get $const-i32))
+ )
+ (func (export "type-i64") (result i64)
+ (return_call_ref $-i64 (global.get $const-i64))
+ )
+ (func (export "type-f32") (result f32)
+ (return_call_ref $-f32 (global.get $const-f32))
+ )
+ (func (export "type-f64") (result f64)
+ (return_call_ref $-f64 (global.get $const-f64))
+ )
+
+ (func (export "type-first-i32") (result i32)
+ (return_call_ref $i32-i32 (i32.const 32) (global.get $id-i32))
+ )
+ (func (export "type-first-i64") (result i64)
+ (return_call_ref $i64-i64 (i64.const 64) (global.get $id-i64))
+ )
+ (func (export "type-first-f32") (result f32)
+ (return_call_ref $f32-f32 (f32.const 1.32) (global.get $id-f32))
+ )
+ (func (export "type-first-f64") (result f64)
+ (return_call_ref $f64-f64 (f64.const 1.64) (global.get $id-f64))
+ )
+
+ (func (export "type-second-i32") (result i32)
+ (return_call_ref $f32-i32 (f32.const 32.1) (i32.const 32) (global.get $f32-i32))
+ )
+ (func (export "type-second-i64") (result i64)
+ (return_call_ref $i32-i64 (i32.const 32) (i64.const 64) (global.get $i32-i64))
+ )
+ (func (export "type-second-f32") (result f32)
+ (return_call_ref $f64-f32 (f64.const 64) (f32.const 32) (global.get $f64-f32))
+ )
+ (func (export "type-second-f64") (result f64)
+ (return_call_ref $i64-f64 (i64.const 64) (f64.const 64.1) (global.get $i64-f64))
+ )
+
+ ;; Null
+
+ (func (export "null")
+ (return_call_ref $proc (ref.null $proc))
+ )
+
+ ;; Recursion
+
+ (global $fac-acc (ref $i64i64-i64) (ref.func $fac-acc))
+
+ (elem declare func $fac-acc)
+ (func $fac-acc (export "fac-acc") (param i64 i64) (result i64)
+ (if (result i64) (i64.eqz (local.get 0))
+ (then (local.get 1))
+ (else
+ (return_call_ref $i64i64-i64
+ (i64.sub (local.get 0) (i64.const 1))
+ (i64.mul (local.get 0) (local.get 1))
+ (global.get $fac-acc)
+ )
+ )
+ )
+ )
+
+ (global $count (ref $i64-i64) (ref.func $count))
+
+ (elem declare func $count)
+ (func $count (export "count") (param i64) (result i64)
+ (if (result i64) (i64.eqz (local.get 0))
+ (then (local.get 0))
+ (else
+ (return_call_ref $i64-i64
+ (i64.sub (local.get 0) (i64.const 1))
+ (global.get $count)
+ )
+ )
+ )
+ )
+
+ (global $even (ref $i64-i64) (ref.func $even))
+ (global $odd (ref $i64-i64) (ref.func $odd))
+
+ (elem declare func $even)
+ (func $even (export "even") (param i64) (result i64)
+ (if (result i64) (i64.eqz (local.get 0))
+ (then (i64.const 44))
+ (else
+ (return_call_ref $i64-i64
+ (i64.sub (local.get 0) (i64.const 1))
+ (global.get $odd)
+ )
+ )
+ )
+ )
+ (elem declare func $odd)
+ (func $odd (export "odd") (param i64) (result i64)
+ (if (result i64) (i64.eqz (local.get 0))
+ (then (i64.const 99))
+ (else
+ (return_call_ref $i64-i64
+ (i64.sub (local.get 0) (i64.const 1))
+ (global.get $even)
+ )
+ )
+ )
+ )
+)
+
+(assert_return (invoke "type-i32") (i32.const 0x132))
+(assert_return (invoke "type-i64") (i64.const 0x164))
+(assert_return (invoke "type-f32") (f32.const 0xf32))
+(assert_return (invoke "type-f64") (f64.const 0xf64))
+
+(assert_return (invoke "type-first-i32") (i32.const 32))
+(assert_return (invoke "type-first-i64") (i64.const 64))
+(assert_return (invoke "type-first-f32") (f32.const 1.32))
+(assert_return (invoke "type-first-f64") (f64.const 1.64))
+
+(assert_return (invoke "type-second-i32") (i32.const 32))
+(assert_return (invoke "type-second-i64") (i64.const 64))
+(assert_return (invoke "type-second-f32") (f32.const 32))
+(assert_return (invoke "type-second-f64") (f64.const 64.1))
+
+(assert_trap (invoke "null") "null function reference")
+
+(assert_return (invoke "fac-acc" (i64.const 0) (i64.const 1)) (i64.const 1))
+(assert_return (invoke "fac-acc" (i64.const 1) (i64.const 1)) (i64.const 1))
+(assert_return (invoke "fac-acc" (i64.const 5) (i64.const 1)) (i64.const 120))
+(assert_return
+ (invoke "fac-acc" (i64.const 25) (i64.const 1))
+ (i64.const 7034535277573963776)
+)
+
+(assert_return (invoke "count" (i64.const 0)) (i64.const 0))
+(assert_return (invoke "count" (i64.const 1000)) (i64.const 0))
+(assert_return (invoke "count" (i64.const 1000000)) (i64.const 0))
+
+(assert_return (invoke "even" (i64.const 0)) (i64.const 44))
+(assert_return (invoke "even" (i64.const 1)) (i64.const 99))
+(assert_return (invoke "even" (i64.const 100)) (i64.const 44))
+(assert_return (invoke "even" (i64.const 77)) (i64.const 99))
+(assert_return (invoke "even" (i64.const 1000000)) (i64.const 44))
+(assert_return (invoke "even" (i64.const 1000001)) (i64.const 99))
+(assert_return (invoke "odd" (i64.const 0)) (i64.const 99))
+(assert_return (invoke "odd" (i64.const 1)) (i64.const 44))
+(assert_return (invoke "odd" (i64.const 200)) (i64.const 99))
+(assert_return (invoke "odd" (i64.const 77)) (i64.const 44))
+(assert_return (invoke "odd" (i64.const 1000000)) (i64.const 99))
+(assert_return (invoke "odd" (i64.const 999999)) (i64.const 44))
+
+
+;; More typing
+
+(module
+ (type $t (func))
+ (type $t1 (func (result (ref $t))))
+ (type $t2 (func (result (ref null $t))))
+ (type $t3 (func (result (ref func))))
+ (type $t4 (func (result (ref null func))))
+ (elem declare func $f11 $f22 $f33 $f44)
+ (func $f11 (result (ref $t)) (return_call_ref $t1 (ref.func $f11)))
+ (func $f21 (result (ref null $t)) (return_call_ref $t1 (ref.func $f11)))
+ (func $f22 (result (ref null $t)) (return_call_ref $t2 (ref.func $f22)))
+ (func $f31 (result (ref func)) (return_call_ref $t1 (ref.func $f11)))
+ (func $f33 (result (ref func)) (return_call_ref $t3 (ref.func $f33)))
+ (func $f41 (result (ref null func)) (return_call_ref $t1 (ref.func $f11)))
+ (func $f42 (result (ref null func)) (return_call_ref $t2 (ref.func $f22)))
+ (func $f43 (result (ref null func)) (return_call_ref $t3 (ref.func $f33)))
+ (func $f44 (result (ref null func)) (return_call_ref $t4 (ref.func $f44)))
+)
+
+(assert_invalid
+ (module
+ (type $t (func))
+ (type $t2 (func (result (ref null $t))))
+ (elem declare func $f22)
+ (func $f12 (result (ref $t)) (return_call_ref $t2 (ref.func $f22)))
+ (func $f22 (result (ref null $t)) (return_call_ref $t2 (ref.func $f22)))
+ )
+ "type mismatch"
+)
+
+(assert_invalid
+ (module
+ (type $t (func))
+ (type $t3 (func (result (ref func))))
+ (elem declare func $f33)
+ (func $f13 (result (ref $t)) (return_call_ref $t3 (ref.func $f33)))
+ (func $f33 (result (ref func)) (return_call_ref $t3 (ref.func $f33)))
+ )
+ "type mismatch"
+)
+
+(assert_invalid
+ (module
+ (type $t (func))
+ (type $t4 (func (result (ref null func))))
+ (elem declare func $f44)
+ (func $f14 (result (ref $t)) (return_call_ref $t4 (ref.func $f44)))
+ (func $f44 (result (ref null func)) (return_call_ref $t4 (ref.func $f44)))
+ )
+ "type mismatch"
+)
+
+(assert_invalid
+ (module
+ (type $t (func))
+ (type $t3 (func (result (ref func))))
+ (elem declare func $f33)
+ (func $f23 (result (ref null $t)) (return_call_ref $t3 (ref.func $f33)))
+ (func $f33 (result (ref func)) (return_call_ref $t3 (ref.func $f33)))
+ )
+ "type mismatch"
+)
+
+(assert_invalid
+ (module
+ (type $t (func))
+ (type $t4 (func (result (ref null func))))
+ (elem declare func $f44)
+ (func $f24 (result (ref null $t)) (return_call_ref $t4 (ref.func $f44)))
+ (func $f44 (result (ref null func)) (return_call_ref $t4 (ref.func $f44)))
+ )
+ "type mismatch"
+)
+
+(assert_invalid
+ (module
+ (type $t4 (func (result (ref null func))))
+ (elem declare func $f44)
+ (func $f34 (result (ref func)) (return_call_ref $t4 (ref.func $f44)))
+ (func $f44 (result (ref null func)) (return_call_ref $t4 (ref.func $f44)))
+ )
+ "type mismatch"
+)
+
+
+;; Unreachable typing.
+
+(module
+ (type $t (func (result i32)))
+ (func (export "unreachable") (result i32)
+ (return_call_ref $t (unreachable))
+ )
+)
+(assert_trap (invoke "unreachable") "unreachable")
+
+(module
+ (elem declare func $f)
+ (type $t (func (param i32) (result i32)))
+ (func $f (param i32) (result i32) (local.get 0))
+
+ (func (export "unreachable") (result i32)
+ (return_call_ref $t
+ (unreachable)
+ (ref.func $f)
+ )
+ )
+)
+(assert_trap (invoke "unreachable") "unreachable")
+
+(module
+ (elem declare func $f)
+ (type $t (func (param i32) (result i32)))
+ (func $f (param i32) (result i32) (local.get 0))
+
+ (func (export "unreachable") (result i32)
+ (unreachable)
+ (return_call_ref $t
+ (i32.const 0)
+ (ref.func $f)
+ )
+ (i32.const 0)
+ )
+)
+(assert_trap (invoke "unreachable") "unreachable")
+
+(assert_invalid
+ (module
+ (elem declare func $f)
+ (type $t (func (param i32) (result i32)))
+ (func $f (param i32) (result i32) (local.get 0))
+
+ (func (export "unreachable") (result i32)
+ (unreachable)
+ (i64.const 0)
+ (ref.func $f)
+ (return_call_ref $t)
+ )
+ )
+ "type mismatch"
+)
+
+(assert_invalid
+ (module
+ (elem declare func $f)
+ (type $t (func (param i32) (result i32)))
+ (func $f (param i32) (result i32) (local.get 0))
+
+ (func (export "unreachable") (result i32)
+ (unreachable)
+ (ref.func $f)
+ (return_call_ref $t)
+ (i64.const 0)
+ )
+ )
+ "type mismatch"
+)
+
+(assert_invalid
+ (module
+ (type $t (func))
+ (func $f (param $r externref)
+ (return_call_ref $t (local.get $r))
+ )
+ )
+ "type mismatch"
+)