Add test cases for the requirements of "gc-aot" feature (#3399)

This commit is contained in:
Zhang, Yi 2024-05-09 16:15:44 +08:00 committed by GitHub
parent 480ee02615
commit f729da7656
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 9995 additions and 4 deletions

View File

@ -0,0 +1,74 @@
# Requirement Engineering Tests
This directory contains requirement engineering test cases. Each directory corresponds to a test case suite for a requirement, comprised of test cases for sub-requirements.
## How to Run a Requirement Test
You can use the [all-in-one script](../wamr-test-suites/test_wamr.sh). Here are examples of its usage for testing the "gc-aot" requirement:
```shell
cd ../wamr-test-suites
# Run "gc-aot" requirement test on cases corresponding to sub-requirement ids 1, 2, 3
./test_wamr.sh -r "gc-aot" 1 2 3
# If no sub-requirement id is specified, it will test all cases for this requirement
./test_wamr.sh -r "gc-aot"
```
Or, use the helper scripts under a specific requirement directory. Refer to the help information of that helper script:
```shell
cd gc-aot
# Build first
./build.py
# Print help info
./run.py -h
# Test sub-requirement 1, and output to file output.csv
./run.py -o output 1
# Test all sub-requirements, and output to file output.csv
./run.py -o output
```
## How to Add a New Requirement Test
1. First, create a subdirectory, e.g., `new-requirement`, in this directory. Its name should reflect the requirement, like "gc-aot", and it should contain two helper scripts (`build.py` and `run.py`) to build and run tests under the `new-requirement` sub-directory.
> If you need to use relative paths in your script, it's fine. The caller Python script [../wamr-test-suites/requirement-engineering-test-script/run_requirement.py](../wamr-test-suites/requirement-engineering-test-script/run_requirement.py) will use `os.chdir()` to change to that sub-directory.
Start by writing and testing the helper script in that sub-directory, and add anything helpful (for instance, a main function and CLI argument parser).
2. After finishing the helper script, to let [the all-in-one script `test_wamr.sh`](../wamr-test-suites/test_wamr.sh) -> [../wamr-test-suites/requirement-engineering-test-script/run_requirement.py](../wamr-test-suites/requirement-engineering-test-script/run_requirement.py) invoke the new requirement test, you don't have to modify this script. Just ensure your helper script follows these guidelines:
- The `build.py` should have a **build** function to build everything necessary for running the requirement tests. The signature should be:
```Python
def build(verbose: bool) -> None:
# your implementation
```
- The `run.py` should have a **run** function to execute the test cases. The signature should be:
```Python
def run(output_dir: str, subrequirement_ids: List[int]) -> Dict[int, Dict[Tuple[str, str], bool]]:
# your implementation
```
The result should be a dictionary with sub-requirement ids as keys and inner dictionaries as values. The inner dictionary should map tuples of (test_case, test_case_description) to a boolean indicating the test case's success.
`run.py` should also contain a **SUBREQUIREMENT_DESCRIPTIONS** dictionary, describing each sub-requirement. For example:
```Python
SUBREQUIREMENT_DESCRIPTIONS = {
1: ("633", "Modify existing opcodes to conform to the semantics of the GC proposal when needed."),
2: ("634", "Supporting new GC opcodes(semantics of GC MVP proposal spec)."),
3: ("635", "Supporting new GC opcode(semantics of Binaryen GC spec)."),
}
```
> PS: If anything goes wrong during the build and run process, throw an exception and let it crash, so that it can be seen by the top-level caller (shell script).
3. Now you can test whether [the all-in-one script `test_wamr.sh`](../wamr-test-suites/test_wamr.sh) can correctly execute `new-requirement` and generate a report.
```shell
./test_wamr.sh -r "new-requirement"
```

View File

@ -0,0 +1,74 @@
#!/usr/bin/python3
#
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
import os
WORK_DIR = os.getcwd()
WAMR_DIR = os.path.join(WORK_DIR, "../../../")
IWASM_DIR = os.path.join(
WORK_DIR, "../../../product-mini/platforms/linux")
def compile_llvm():
print("============ compile llvm =============")
os.chdir(os.path.join(WAMR_DIR, "wamr-compiler"))
exit_status = os.system("./build_llvm.sh")
assert exit_status >> 8 == 0, "compile llvm failed, add -v for detail error output"
print("============ compile llvm successful =============")
def compile_wamrc(verbose: bool):
print("============ compile wamrc =============")
os.chdir(os.path.join(WAMR_DIR, "wamr-compiler"))
os.system("rm -rf build")
os.system("mkdir build")
exit_status = os.system(
f"cmake -DWAMR_BUILD_GC=1 -B build {'' if verbose else '> /dev/null 2>&1'}")
exit_status |= os.system(
f"cmake --build build -j {os.cpu_count()} {'' if verbose else '> /dev/null 2>&1'}"
)
assert exit_status >> 8 == 0, "compile wamrc failed, add -v for detail error output"
print("============ compile wamrc successful =============")
def compile_iwasm(verbose: bool):
print("============ compile iwasm =============")
os.chdir(IWASM_DIR)
os.system("rm -rf build")
os.system("mkdir build")
exit_status = os.system(
f"cmake -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_GC=1 -DWAMR_BUILD_SPEC_TEST=1 -B build {'' if verbose else '> /dev/null 2>&1'}"
)
exit_status |= os.system(
f"cmake --build build -j {os.cpu_count()} {'' if verbose else '> /dev/null 2>&1'}"
)
os.chdir(WORK_DIR)
assert exit_status >> 8 == 0, "compile iwasm failed, add -v for detail error output"
print("============ compile iwasm successful =============")
def compile_spec_interpreter():
print("============ compile spec interpreter =============")
os.chdir(WORK_DIR)
exit_status = os.system("./build_spec_interpreter.sh")
assert exit_status >> 8 == 0, "compile spec interpreter failed."
print("============ compile spec interpreter successful =============")
def build(verbose: bool) -> None:
compile_llvm()
compile_wamrc(verbose)
compile_iwasm(verbose)
compile_spec_interpreter()
return
if __name__ == "__main__":
build(True)

View File

@ -0,0 +1,23 @@
#!/usr/bin/env bash
#
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
rm -fr spec
# check spec test cases for GC
git clone -b main --single-branch https://github.com/WebAssembly/gc.git spec
pushd spec
git restore . && git clean -ffd .
# Reset to commit: "[test] Unify the error message."
git reset --hard 0caaadc65b5e1910512d8ae228502edcf9d60390
git apply ../../../wamr-test-suites/spec-test-script/gc_ignore_cases.patch
# Set OCaml compiler environment
eval $(opam config env)
echo "compile the reference intepreter"
pushd interpreter
make
popd

View File

@ -0,0 +1,103 @@
#!/usr/bin/python3
#
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
import os
import argparse
from typing import List, Dict, Tuple
import json
WORK_DIR = os.getcwd()
WAMR_DIR = os.path.join(WORK_DIR, "../../..")
IWASM_CMD = os.path.join(
WORK_DIR, "../../../product-mini/platforms/linux/build/iwasm")
WAMRC_CMD = os.path.join(WORK_DIR, "../../../wamr-compiler/build/wamrc")
SUBREQUIREMENT_DESCRIPTIONS = {
1: ("633", "Modify existing opcodes to conform to the semantics of the GC proposal when needed."),
2: ("634", "Supporting new GC opcodes(semantics of GC MVP proposal spec)."),
3: ("635", "Supporting new GC opcode(semantics of Binaryen GC spec)."),
}
def test_subrequirement(id: int) -> Dict[Tuple[str, str], bool]:
print(f"\n============> test gc aot requirement: {id}")
test_cases = {}
result = {}
with open('test_cases.json') as config_file:
config = json.load(config_file)
for req in config["sub-requirements"]:
if req['req_id'] == id:
test_cases = req['cases']
break
for case in test_cases:
print(case)
print(f"{case['name']}.aot")
exit_status = os.system(
f"python runtest.py --aot --wast2wasm spec/interpreter/wasm --interpreter {IWASM_CMD} --aot-compiler {WAMRC_CMD} --gc wasm-apps/{case['name']}.wast"
)
if exit_status == 0:
result[case['name'], case['description']] = True
else:
result[case['name'], case['description']] = False
return result
def run(
output_dir: str, subrequirement_ids: List[int]
) -> Dict[int, Dict[Tuple[str, str], bool]]:
# key: value -> subrequirement id: dict[tuple(test_case_name, test_case_description), is_success]
result_dict: Dict[int, Dict[Tuple[str, str], bool]] = {}
# Default run all subrequirement
if not subrequirement_ids:
subrequirement_ids = [1, 2, 3]
for subrequirement_id in subrequirement_ids:
if subrequirement_id not in SUBREQUIREMENT_DESCRIPTIONS.keys():
print(
f"Subrequirement id invalid! It should be a value in {[_ for _ in SUBREQUIREMENT_DESCRIPTIONS.keys()]}"
)
continue
result_dict[subrequirement_id] = test_subrequirement(subrequirement_id)
return result_dict
if __name__ == "__main__":
print("============> test GC AOT")
# Create the parser
parser = argparse.ArgumentParser(
description="A script to process sub-requirement ids, run corresponding test cases, and compile wamrc, iwasm if requested."
)
# The argparse module handles -h and --help by default, no needs to add it
# Add an output option `-o` as a flag that, when specified, sets the variable to True
parser.add_argument(
"-o",
"--output",
type=str,
required=False,
help="Specify the output file name. If provided, the script will write the results to <file name>.csv",
)
# Add positional arguments for integers
parser.add_argument(
"integers",
metavar="N",
type=int,
nargs="*",
help="an integer for the sub-requirement ids",
)
# Parse arguments
args = parser.parse_args()
run(args.output, args.integers)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,115 @@
{
"name": "gc-aot-test-suites",
"description": "Test suites for GC AOT feature",
"sub-requirements": [
{
"req_id": 1,
"issue_id": "633",
"desciption": "Modify existing opcodes to conform to the semantics of the GC proposal when needed.",
"cases": [
{
"name": "local_set",
"description": "Test opcodes: 'WASM_OP_GET_LOCAL', 'WASM_OP_SET_LOCAL'"
},
{
"name": "local_tee",
"description": "Test opcodes: 'WASM_OP_GET_LOCAL', 'WASM_OP_TEE_LOCAL'"
},
{
"name": "table_init",
"description": "Test opcodes: 'WASM_OP_TABLE_INIT'"
},
{
"name": "table_grow",
"description": "Test opcodes: 'WASM_OP_TABLE_GROW'"
},
{
"name": "table_fill",
"description": "Test opcodes: 'WASM_OP_TABLE_FILL'"
},
{
"name": "call_ref",
"description": "Test opcodes: 'WASM_OP_CALL_REF'"
},
{
"name": "return_call_ref",
"description": "Test opcodes: 'WASM_OP_RETURN_CALL_REF'"
},
{
"name": "table_get",
"description": "Test opcodes: 'WASM_OP_TABLE_GET'"
},
{
"name": "table_set",
"description": "Test opcodes: 'WASM_OP_TABLE_SET'"
},
{
"name": "select",
"description": "Test opcodes: 'WASM_OP_SELECT_T'"
}
]
},
{
"req_id": 2,
"issue_id": "634",
"desciption": "Supporting new GC opcodes(semantics of GC MVP proposal spec).",
"cases": [
{
"name": "ref_test",
"description": "Test opcodes: 'WASM_OP_TABLE_GET', 'WASM_OP_TABLE_SET', 'WASM_OP_REF_NULL', 'WASM_OP_REF_IS_NULL', 'WASM_OP_REF_TEST', 'WASM_OP_REF_TEST_NULLABLE'"
},
{
"name": "ref_eq",
"description": "Test opcodes: 'WASM_OP_REF_EQ', 'WASM_OP_GET_LOCAL'"
},
{
"name": "ref_cast",
"description": "Test opcodes: 'WASM_OP_REF_CAST', 'WASM_OP_REF_CAST_NULLABLE', 'WASM_OP_REF_AS_NON_NULL'"
},
{
"name": "type_subtyping",
"description": "Test opcodes: 'WASM_OP_CALL_INDIRECT', 'WASM_OP_REF_FUNC'"
},
{
"name": "array",
"description": "Test opcodes: 'WASM_OP_ARRAY_NEW', 'WASM_OP_ARRAY_NEW_DEFAULT', 'WASM_OP_ARRAY_NEW_FIXED', 'WASM_OP_ARRAY_NEW_DATA', 'WASM_OP_ARRAY_GET', 'WASM_OP_ARRAY_GET_S', 'WASM_OP_ARRAY_GET_U', 'WASM_OP_ARRAY_SET', 'WASM_OP_ARRAY_LEN'"
},
{
"name": "array_fill",
"description": "Test opcodes: 'WASM_OP_ARRAY_FILL'"
},
{
"name": "struct",
"description": "Test opcodes: 'WASM_OP_STRUCT_NEW', 'WASM_OP_STRUCT_NEW_DEFAULT', 'WASM_OP_STRUCT_GET', 'WASM_OP_STRUCT_GET_S', 'WASM_OP_STRUCT_GET_U', 'WASM_OP_STRUCT_SET'"
},
{
"name": "i31",
"description": "Test opcodes: 'WASM_OP_I31_NEW', 'WASM_OP_I31_GET_S', 'WASM_OP_I31_GET_U'"
},
{
"name": "br_on_cast",
"description": "Test opcodes: 'WASM_OP_BR_ON_NULL', 'WASM_OP_BR_ON_CAST'"
},
{
"name": "br_on_cast_fail",
"description": "Test opcodes: 'WASM_OP_BR_ON_NON_NULL', 'WASM_OP_BR_ON_CAST_FAIL'"
},
{
"name": "extern",
"description": "Test opcodes: 'WASM_OP_ANY_CONVERT_EXTERN', 'WASM_OP_EXTERN_CONVERT_ANY'"
}
]
},
{
"req_id": 3,
"issue_id": "635",
"desciption": "Supporting new GC opcode(semantics of Binaryen GC spec).",
"cases": [
{
"name": "array_copy",
"description": "Test the opcodes: 'WASM_OP_ARRAY_COPY', 'WASM_OP_SET_LOCAL'"
}
]
}
]
}

View File

@ -0,0 +1,308 @@
;; Type syntax
(module
(type (array i8))
(type (array i16))
(type (array i32))
(type (array i64))
(type (array f32))
(type (array f64))
(type (array anyref))
(type (array (ref struct)))
(type (array (ref 0)))
(type (array (ref null 1)))
(type (array (mut i8)))
(type (array (mut i16)))
(type (array (mut i32)))
(type (array (mut i64)))
(type (array (mut i32)))
(type (array (mut i64)))
(type (array (mut anyref)))
(type (array (mut (ref struct))))
(type (array (mut (ref 0))))
(type (array (mut (ref null i31))))
)
(assert_invalid
(module
(type (array (mut (ref null 10))))
)
"unknown type"
)
;; Binding structure
(module
(rec
(type $s0 (array (ref $s1)))
(type $s1 (array (ref $s0)))
)
(func (param (ref $forward)))
(type $forward (array i32))
)
(assert_invalid
(module (type (array (ref 1))))
"unknown type"
)
(assert_invalid
(module (type (array (mut (ref 1)))))
"unknown type"
)
;; Basic instructions
(module
(type $vec (array f32))
(type $mvec (array (mut f32)))
(global (ref $vec) (array.new $vec (f32.const 1) (i32.const 3)))
(global (ref $vec) (array.new_default $vec (i32.const 3)))
(func $new (export "new") (result (ref $vec))
(array.new_default $vec (i32.const 3))
)
(func $get (param $i i32) (param $v (ref $vec)) (result f32)
(array.get $vec (local.get $v) (local.get $i))
)
(func (export "get") (param $i i32) (result f32)
(call $get (local.get $i) (call $new))
)
(func $set_get (param $i i32) (param $v (ref $mvec)) (param $y f32) (result f32)
(array.set $mvec (local.get $v) (local.get $i) (local.get $y))
(array.get $mvec (local.get $v) (local.get $i))
)
(func (export "set_get") (param $i i32) (param $y f32) (result f32)
(call $set_get (local.get $i)
(array.new_default $mvec (i32.const 3))
(local.get $y)
)
)
(func $len (param $v (ref array)) (result i32)
(array.len (local.get $v))
)
(func (export "len") (result i32)
(call $len (call $new))
)
)
(assert_return (invoke "new") (ref.array))
;; (assert_return (invoke "new") (ref.eq))
(assert_return (invoke "get" (i32.const 0)) (f32.const 0))
(assert_return (invoke "set_get" (i32.const 1) (f32.const 7)) (f32.const 7))
(assert_return (invoke "len") (i32.const 3))
(assert_trap (invoke "get" (i32.const 10)) "out of bounds array access")
(assert_trap (invoke "set_get" (i32.const 10) (f32.const 7)) "out of bounds array access")
(module
(type $vec (array f32))
(type $mvec (array (mut f32)))
(global (ref $vec) (array.new_fixed $vec 2 (f32.const 1) (f32.const 2)))
(func $new (export "new") (result (ref $vec))
(array.new_fixed $vec 2 (f32.const 1) (f32.const 2))
)
(func $get (param $i i32) (param $v (ref $vec)) (result f32)
(array.get $vec (local.get $v) (local.get $i))
)
(func (export "get") (param $i i32) (result f32)
(call $get (local.get $i) (call $new))
)
(func $set_get (param $i i32) (param $v (ref $mvec)) (param $y f32) (result f32)
(array.set $mvec (local.get $v) (local.get $i) (local.get $y))
(array.get $mvec (local.get $v) (local.get $i))
)
(func (export "set_get") (param $i i32) (param $y f32) (result f32)
(call $set_get (local.get $i)
(array.new_fixed $mvec 3 (f32.const 1) (f32.const 2) (f32.const 3))
(local.get $y)
)
)
(func $len (param $v (ref array)) (result i32)
(array.len (local.get $v))
)
(func (export "len") (result i32)
(call $len (call $new))
)
)
(assert_return (invoke "new") (ref.array))
;; (assert_return (invoke "new") (ref.eq))
(assert_return (invoke "get" (i32.const 0)) (f32.const 1))
(assert_return (invoke "set_get" (i32.const 1) (f32.const 7)) (f32.const 7))
(assert_return (invoke "len") (i32.const 2))
(assert_trap (invoke "get" (i32.const 10)) "out of bounds array access")
(assert_trap (invoke "set_get" (i32.const 10) (f32.const 7)) "out of bounds array access")
(module
(type $vec (array i8))
(type $mvec (array (mut i8)))
(data $d "\00\01\02\03\04")
(func $new (export "new") (result (ref $vec))
(array.new_data $vec $d (i32.const 1) (i32.const 3))
)
(func $get (param $i i32) (param $v (ref $vec)) (result i32)
(array.get_u $vec (local.get $v) (local.get $i))
)
(func (export "get") (param $i i32) (result i32)
(call $get (local.get $i) (call $new))
)
(func $set_get (param $i i32) (param $v (ref $mvec)) (param $y i32) (result i32)
(array.set $mvec (local.get $v) (local.get $i) (local.get $y))
(array.get_u $mvec (local.get $v) (local.get $i))
)
(func (export "set_get") (param $i i32) (param $y i32) (result i32)
(call $set_get (local.get $i)
(array.new_data $mvec $d (i32.const 1) (i32.const 3))
(local.get $y)
)
)
(func $len (param $v (ref array)) (result i32)
(array.len (local.get $v))
)
(func (export "len") (result i32)
(call $len (call $new))
)
)
(assert_return (invoke "new") (ref.array))
;; (assert_return (invoke "new") (ref.eq))
(assert_return (invoke "get" (i32.const 0)) (i32.const 1))
(assert_return (invoke "set_get" (i32.const 1) (i32.const 7)) (i32.const 7))
(assert_return (invoke "len") (i32.const 3))
(assert_trap (invoke "get" (i32.const 10)) "out of bounds array access")
(assert_trap (invoke "set_get" (i32.const 10) (i32.const 7)) "out of bounds array access")
(; array.new_elem not supported
(module
(type $bvec (array i8))
(type $vec (array (ref $bvec)))
(type $mvec (array (mut (ref $bvec))))
(type $nvec (array (ref null $bvec)))
(type $avec (array (mut anyref)))
(elem $e (ref $bvec)
(array.new $bvec (i32.const 7) (i32.const 3))
(array.new_fixed $bvec 2 (i32.const 1) (i32.const 2))
)
(func $new (export "new") (result (ref $vec))
(array.new_elem $vec $e (i32.const 0) (i32.const 2))
)
(func $sub1 (result (ref $nvec))
(array.new_elem $nvec $e (i32.const 0) (i32.const 2))
)
(func $sub2 (result (ref $avec))
(array.new_elem $avec $e (i32.const 0) (i32.const 2))
)
(func $get (param $i i32) (param $j i32) (param $v (ref $vec)) (result i32)
(array.get_u $bvec (array.get $vec (local.get $v) (local.get $i)) (local.get $j))
)
(func (export "get") (param $i i32) (param $j i32) (result i32)
(call $get (local.get $i) (local.get $j) (call $new))
)
(func $set_get (param $i i32) (param $j i32) (param $v (ref $mvec)) (param $y i32) (result i32)
(array.set $mvec (local.get $v) (local.get $i) (array.get $mvec (local.get $v) (local.get $y)))
(array.get_u $bvec (array.get $mvec (local.get $v) (local.get $i)) (local.get $j))
)
(func (export "set_get") (param $i i32) (param $j i32) (param $y i32) (result i32)
(call $set_get (local.get $i) (local.get $j)
(array.new_elem $mvec $e (i32.const 0) (i32.const 2))
(local.get $y)
)
)
(func $len (param $v (ref array)) (result i32)
(array.len (local.get $v))
)
(func (export "len") (result i32)
(call $len (call $new))
)
)
(assert_return (invoke "new") (ref.array))
(assert_return (invoke "new") (ref.eq))
(assert_return (invoke "get" (i32.const 0) (i32.const 0)) (i32.const 7))
(assert_return (invoke "get" (i32.const 1) (i32.const 0)) (i32.const 1))
(assert_return (invoke "set_get" (i32.const 0) (i32.const 1) (i32.const 1)) (i32.const 2))
(assert_return (invoke "len") (i32.const 2))
(assert_trap (invoke "get" (i32.const 10) (i32.const 0)) "out of bounds array access")
(assert_trap (invoke "set_get" (i32.const 10) (i32.const 0) (i32.const 0)) "out of bounds array access")
;)
(assert_invalid
(module
(type $a (array i64))
(func (export "array.set-immutable") (param $a (ref $a))
(array.set $a (local.get $a) (i32.const 0) (i64.const 1))
)
)
"array is immutable"
)
(assert_invalid
(module
(type $bvec (array i8))
(data $d "\00\01\02\03\04")
(global (ref $bvec)
(array.new_data $bvec $d (i32.const 1) (i32.const 3))
)
)
"constant expression required"
)
(assert_invalid
(module
(type $bvec (array i8))
(type $vvec (array (ref $bvec)))
(elem $e (ref $bvec) (ref.null $bvec))
(global (ref $vvec)
(array.new_elem $vvec $e (i32.const 0) (i32.const 1))
)
)
"constant expression required"
)
;; Null dereference
(module
(type $t (array (mut i32)))
(func (export "array.get-null")
(local (ref null $t)) (drop (array.get $t (local.get 0) (i32.const 0)))
)
(func (export "array.set-null")
(local (ref null $t)) (array.set $t (local.get 0) (i32.const 0) (i32.const 0))
)
)
(assert_trap (invoke "array.get-null") "null array")
(assert_trap (invoke "array.set-null") "null array")

View File

@ -0,0 +1,139 @@
;; Bulk instructions
;; invalid uses
(assert_invalid
(module
(type $a (array i8))
(type $b (array (mut i8)))
(func (export "array.copy-immutable") (param $1 (ref $a)) (param $2 (ref $b))
(array.copy $a $b (local.get $1) (i32.const 0) (local.get $2) (i32.const 0) (i32.const 0))
)
)
"array is immutable"
)
(assert_invalid
(module
(type $a (array (mut i8)))
(type $b (array i16))
(func (export "array.copy-packed-invalid") (param $1 (ref $a)) (param $2 (ref $b))
(array.copy $a $b (local.get $1) (i32.const 0) (local.get $2) (i32.const 0) (i32.const 0))
)
)
"array types do not match"
)
(assert_invalid
(module
(type $a (array (mut i8)))
(type $b (array (mut (ref $a))))
(func (export "array.copy-ref-invalid-1") (param $1 (ref $a)) (param $2 (ref $b))
(array.copy $a $b (local.get $1) (i32.const 0) (local.get $2) (i32.const 0) (i32.const 0))
)
)
"array types do not match"
)
(assert_invalid
(module
(type $a (array (mut i8)))
(type $b (array (mut (ref $a))))
(type $c (array (mut (ref $b))))
(func (export "array.copy-ref-invalid-1") (param $1 (ref $b)) (param $2 (ref $c))
(array.copy $b $c (local.get $1) (i32.const 0) (local.get $2) (i32.const 0) (i32.const 0))
)
)
"array types do not match"
)
(module
(type $arr8 (array i8))
(type $arr8_mut (array (mut i8)))
(global $g_arr8 (ref $arr8) (array.new $arr8 (i32.const 10) (i32.const 12)))
(global $g_arr8_mut (mut (ref $arr8_mut)) (array.new_default $arr8_mut (i32.const 12)))
(data $d1 "abcdefghijkl")
(func (export "array_get_nth") (param $1 i32) (result i32)
(array.get_u $arr8_mut (global.get $g_arr8_mut) (local.get $1))
)
(func (export "array_copy-null-left")
(array.copy $arr8_mut $arr8 (ref.null $arr8_mut) (i32.const 0) (global.get $g_arr8) (i32.const 0) (i32.const 0))
)
(func (export "array_copy-null-right")
(array.copy $arr8_mut $arr8 (global.get $g_arr8_mut) (i32.const 0) (ref.null $arr8) (i32.const 0) (i32.const 0))
)
(func (export "array_copy") (param $1 i32) (param $2 i32) (param $3 i32)
(array.copy $arr8_mut $arr8 (global.get $g_arr8_mut) (local.get $1) (global.get $g_arr8) (local.get $2) (local.get $3))
)
(func (export "array_copy_overlap_test-1")
(local $1 (ref $arr8_mut))
(array.new_data $arr8_mut $d1 (i32.const 0) (i32.const 12))
(local.set $1)
(array.copy $arr8_mut $arr8_mut (local.get $1) (i32.const 1) (local.get $1) (i32.const 0) (i32.const 11))
(global.set $g_arr8_mut (local.get $1))
)
(func (export "array_copy_overlap_test-2")
(local $1 (ref $arr8_mut))
(array.new_data $arr8_mut $d1 (i32.const 0) (i32.const 12))
(local.set $1)
(array.copy $arr8_mut $arr8_mut (local.get $1) (i32.const 0) (local.get $1) (i32.const 1) (i32.const 11))
(global.set $g_arr8_mut (local.get $1))
)
)
;; null array argument traps
(assert_trap (invoke "array_copy-null-left") "null array reference")
(assert_trap (invoke "array_copy-null-right") "null array reference")
;; OOB initial index traps
(assert_trap (invoke "array_copy" (i32.const 13) (i32.const 0) (i32.const 0)) "out of bounds array access")
(assert_trap (invoke "array_copy" (i32.const 0) (i32.const 13) (i32.const 0)) "out of bounds array access")
;; OOB length traps
(assert_trap (invoke "array_copy" (i32.const 0) (i32.const 0) (i32.const 13)) "out of bounds array access")
(assert_trap (invoke "array_copy" (i32.const 0) (i32.const 0) (i32.const 13)) "out of bounds array access")
;; start index = array size, len = 0 doesn't trap
(assert_return (invoke "array_copy" (i32.const 12) (i32.const 0) (i32.const 0)))
(assert_return (invoke "array_copy" (i32.const 0) (i32.const 12) (i32.const 0)))
;; check arrays were not modified
(assert_return (invoke "array_get_nth" (i32.const 0)) (i32.const 0))
(assert_return (invoke "array_get_nth" (i32.const 5)) (i32.const 0))
(assert_return (invoke "array_get_nth" (i32.const 11)) (i32.const 0))
(assert_trap (invoke "array_get_nth" (i32.const 12)) "out of bounds array access")
;; normal case
(assert_return (invoke "array_copy" (i32.const 0) (i32.const 0) (i32.const 2)))
(assert_return (invoke "array_get_nth" (i32.const 0)) (i32.const 10))
(assert_return (invoke "array_get_nth" (i32.const 1)) (i32.const 10))
(assert_return (invoke "array_get_nth" (i32.const 2)) (i32.const 0))
;; test that overlapping array.copy works as if intermediate copy taken
(assert_return (invoke "array_copy_overlap_test-1"))
(assert_return (invoke "array_get_nth" (i32.const 0)) (i32.const 97))
(assert_return (invoke "array_get_nth" (i32.const 1)) (i32.const 97))
(assert_return (invoke "array_get_nth" (i32.const 2)) (i32.const 98))
(assert_return (invoke "array_get_nth" (i32.const 5)) (i32.const 101))
(assert_return (invoke "array_get_nth" (i32.const 10)) (i32.const 106))
(assert_return (invoke "array_get_nth" (i32.const 11)) (i32.const 107))
(assert_return (invoke "array_copy_overlap_test-2"))
(assert_return (invoke "array_get_nth" (i32.const 0)) (i32.const 98))
(assert_return (invoke "array_get_nth" (i32.const 1)) (i32.const 99))
(assert_return (invoke "array_get_nth" (i32.const 5)) (i32.const 103))
(assert_return (invoke "array_get_nth" (i32.const 9)) (i32.const 107))
(assert_return (invoke "array_get_nth" (i32.const 10)) (i32.const 108))
(assert_return (invoke "array_get_nth" (i32.const 11)) (i32.const 108))

View File

@ -0,0 +1,81 @@
;; Bulk instructions
;; invalid uses
(assert_invalid
(module
(type $a (array i8))
(func (export "array.fill-immutable") (param $1 (ref $a)) (param $2 i32)
(array.fill $a (local.get $1) (i32.const 0) (local.get $2) (i32.const 0))
)
)
"array is immutable"
)
(assert_invalid
(module
(type $a (array (mut i8)))
(func (export "array.fill-invalid-1") (param $1 (ref $a)) (param $2 funcref)
(array.fill $a (local.get $1) (i32.const 0) (local.get $2) (i32.const 0))
)
)
"type mismatch"
)
(assert_invalid
(module
(type $b (array (mut funcref)))
(func (export "array.fill-invalid-1") (param $1 (ref $b)) (param $2 i32)
(array.fill $b (local.get $1) (i32.const 0) (local.get $2) (i32.const 0))
)
)
"type mismatch"
)
(module
(type $arr8 (array i8))
(type $arr8_mut (array (mut i8)))
(global $g_arr8 (ref $arr8) (array.new $arr8 (i32.const 10) (i32.const 12)))
(global $g_arr8_mut (mut (ref $arr8_mut)) (array.new_default $arr8_mut (i32.const 12)))
(func (export "array_get_nth") (param $1 i32) (result i32)
(array.get_u $arr8_mut (global.get $g_arr8_mut) (local.get $1))
)
(func (export "array_fill-null")
(array.fill $arr8_mut (ref.null $arr8_mut) (i32.const 0) (i32.const 0) (i32.const 0))
)
(func (export "array_fill") (param $1 i32) (param $2 i32) (param $3 i32)
(array.fill $arr8_mut (global.get $g_arr8_mut) (local.get $1) (local.get $2) (local.get $3))
)
)
;; null array argument traps
(assert_trap (invoke "array_fill-null") "null array reference")
;; OOB initial index traps
(assert_trap (invoke "array_fill" (i32.const 13) (i32.const 0) (i32.const 0)) "out of bounds array access")
;; OOB length traps
(assert_trap (invoke "array_fill" (i32.const 0) (i32.const 0) (i32.const 13)) "out of bounds array access")
;; start index = array size, len = 0 doesn't trap
(assert_return (invoke "array_fill" (i32.const 12) (i32.const 0) (i32.const 0)))
;; check arrays were not modified
(assert_return (invoke "array_get_nth" (i32.const 0)) (i32.const 0))
(assert_return (invoke "array_get_nth" (i32.const 5)) (i32.const 0))
(assert_return (invoke "array_get_nth" (i32.const 11)) (i32.const 0))
(assert_trap (invoke "array_get_nth" (i32.const 12)) "out of bounds array access")
;; normal case
(assert_return (invoke "array_fill" (i32.const 2) (i32.const 11) (i32.const 2)))
(assert_return (invoke "array_get_nth" (i32.const 1)) (i32.const 0))
(assert_return (invoke "array_get_nth" (i32.const 2)) (i32.const 11))
(assert_return (invoke "array_get_nth" (i32.const 3)) (i32.const 11))
(assert_return (invoke "array_get_nth" (i32.const 4)) (i32.const 0))

View File

@ -0,0 +1,267 @@
;; Abstract Types
(module
(type $ft (func (result i32)))
(type $st (struct (field i16)))
(type $at (array i8))
(table 10 anyref)
(elem declare func $f)
(func $f (result i32) (i32.const 9))
(func (export "init") (param $x externref)
(table.set (i32.const 0) (ref.null any))
(table.set (i32.const 1) (ref.i31 (i32.const 7)))
(table.set (i32.const 2) (struct.new $st (i32.const 6)))
(table.set (i32.const 3) (array.new $at (i32.const 5) (i32.const 3)))
(table.set (i32.const 4) (any.convert_extern (local.get $x)))
)
(func (export "br_on_null") (param $i i32) (result i32)
(block $l
(br_on_null $l (table.get (local.get $i)))
(return (i32.const -1))
)
(i32.const 0)
)
(func (export "br_on_i31") (param $i i32) (result i32)
(block $l (result (ref i31))
(br_on_cast $l anyref (ref i31) (table.get (local.get $i)))
(return (i32.const -1))
)
(i31.get_u)
)
(func (export "br_on_struct") (param $i i32) (result i32)
(block $l (result (ref struct))
(br_on_cast $l anyref (ref struct) (table.get (local.get $i)))
(return (i32.const -1))
)
(block $l2 (param structref) (result (ref $st))
(block $l3 (param structref) (result (ref $at))
(br_on_cast $l2 structref (ref $st))
(br_on_cast $l3 anyref (ref $at))
(return (i32.const -2))
)
(return (array.get_u $at (i32.const 0)))
)
(struct.get_s $st 0)
)
(func (export "br_on_array") (param $i i32) (result i32)
(block $l (result (ref array))
(br_on_cast $l anyref (ref array) (table.get (local.get $i)))
(return (i32.const -1))
)
(array.len)
)
(func (export "null-diff") (param $i i32) (result i32)
(block $l (result (ref null struct))
(block (result (ref any))
(br_on_cast $l (ref null any) (ref null struct) (table.get (local.get $i)))
)
(return (i32.const 0))
)
(return (i32.const 1))
)
)
(invoke "init" (ref.extern 0))
(assert_return (invoke "br_on_null" (i32.const 0)) (i32.const 0))
(assert_return (invoke "br_on_null" (i32.const 1)) (i32.const -1))
(assert_return (invoke "br_on_null" (i32.const 2)) (i32.const -1))
(assert_return (invoke "br_on_null" (i32.const 3)) (i32.const -1))
(assert_return (invoke "br_on_null" (i32.const 4)) (i32.const -1))
(assert_return (invoke "br_on_i31" (i32.const 0)) (i32.const -1))
(assert_return (invoke "br_on_i31" (i32.const 1)) (i32.const 7))
(assert_return (invoke "br_on_i31" (i32.const 2)) (i32.const -1))
(assert_return (invoke "br_on_i31" (i32.const 3)) (i32.const -1))
(assert_return (invoke "br_on_i31" (i32.const 4)) (i32.const -1))
(assert_return (invoke "br_on_struct" (i32.const 0)) (i32.const -1))
(assert_return (invoke "br_on_struct" (i32.const 1)) (i32.const -1))
(assert_return (invoke "br_on_struct" (i32.const 2)) (i32.const 6))
(assert_return (invoke "br_on_struct" (i32.const 3)) (i32.const -1))
(assert_return (invoke "br_on_struct" (i32.const 4)) (i32.const -1))
(assert_return (invoke "br_on_array" (i32.const 0)) (i32.const -1))
(assert_return (invoke "br_on_array" (i32.const 1)) (i32.const -1))
(assert_return (invoke "br_on_array" (i32.const 2)) (i32.const -1))
(assert_return (invoke "br_on_array" (i32.const 3)) (i32.const 3))
(assert_return (invoke "br_on_array" (i32.const 4)) (i32.const -1))
(assert_return (invoke "null-diff" (i32.const 0)) (i32.const 1))
(assert_return (invoke "null-diff" (i32.const 1)) (i32.const 0))
(assert_return (invoke "null-diff" (i32.const 2)) (i32.const 1))
(assert_return (invoke "null-diff" (i32.const 3)) (i32.const 0))
(assert_return (invoke "null-diff" (i32.const 4)) (i32.const 0))
;; Concrete Types
(module
(type $t0 (sub (struct)))
(type $t1 (sub $t0 (struct (field i32))))
(type $t1' (sub $t0 (struct (field i32))))
(type $t2 (sub $t1 (struct (field i32 i32))))
(type $t2' (sub $t1' (struct (field i32 i32))))
(type $t3 (sub $t0 (struct (field i32 i32))))
(type $t0' (sub $t0 (struct)))
(type $t4 (sub $t0' (struct (field i32 i32))))
(table 20 structref)
(func $init
(table.set (i32.const 0) (struct.new_default $t0))
(table.set (i32.const 10) (struct.new_default $t0'))
(table.set (i32.const 1) (struct.new_default $t1))
(table.set (i32.const 11) (struct.new_default $t1'))
(table.set (i32.const 2) (struct.new_default $t2))
(table.set (i32.const 12) (struct.new_default $t2'))
(table.set (i32.const 3) (struct.new_default $t3))
(table.set (i32.const 4) (struct.new_default $t4))
)
(func (export "test-sub")
(call $init)
(block $l (result structref)
;; must succeed
(drop (block (result structref) (br_on_cast 0 structref (ref $t0) (ref.null struct))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t0) (table.get (i32.const 0)))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t0) (table.get (i32.const 1)))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t0) (table.get (i32.const 2)))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t0) (table.get (i32.const 3)))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t0) (table.get (i32.const 4)))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t1) (ref.null struct))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t1) (table.get (i32.const 1)))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t1) (table.get (i32.const 2)))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t2) (ref.null struct))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t2) (table.get (i32.const 2)))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t3) (ref.null struct))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t3) (table.get (i32.const 3)))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t4) (ref.null struct))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t4) (table.get (i32.const 4)))))
;; must not succeed
(br_on_cast $l anyref (ref $t1) (table.get (i32.const 0)))
(br_on_cast $l anyref (ref $t1) (table.get (i32.const 3)))
(br_on_cast $l anyref (ref $t1) (table.get (i32.const 4)))
(br_on_cast $l anyref (ref $t2) (table.get (i32.const 0)))
(br_on_cast $l anyref (ref $t2) (table.get (i32.const 1)))
(br_on_cast $l anyref (ref $t2) (table.get (i32.const 3)))
(br_on_cast $l anyref (ref $t2) (table.get (i32.const 4)))
(br_on_cast $l anyref (ref $t3) (table.get (i32.const 0)))
(br_on_cast $l anyref (ref $t3) (table.get (i32.const 1)))
(br_on_cast $l anyref (ref $t3) (table.get (i32.const 2)))
(br_on_cast $l anyref (ref $t3) (table.get (i32.const 4)))
(br_on_cast $l anyref (ref $t4) (table.get (i32.const 0)))
(br_on_cast $l anyref (ref $t4) (table.get (i32.const 1)))
(br_on_cast $l anyref (ref $t4) (table.get (i32.const 2)))
(br_on_cast $l anyref (ref $t4) (table.get (i32.const 3)))
(return)
)
(unreachable)
)
(func (export "test-canon")
(call $init)
(block $l
(drop (block (result structref) (br_on_cast 0 structref (ref $t0') (table.get (i32.const 0)))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t0') (table.get (i32.const 1)))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t0') (table.get (i32.const 2)))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t0') (table.get (i32.const 3)))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t0') (table.get (i32.const 4)))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t0) (table.get (i32.const 10)))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t0) (table.get (i32.const 11)))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t0) (table.get (i32.const 12)))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t1') (table.get (i32.const 1)))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t1') (table.get (i32.const 2)))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t1) (table.get (i32.const 11)))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t1) (table.get (i32.const 12)))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t2') (table.get (i32.const 2)))))
(drop (block (result structref) (br_on_cast 0 structref (ref $t2) (table.get (i32.const 12)))))
(return)
)
(unreachable)
)
)
(invoke "test-sub")
(invoke "test-canon")
;; Cases of nullability
(module
(type $t (struct))
(func (param (ref any)) (result (ref $t))
(block (result (ref any)) (br_on_cast 1 (ref any) (ref $t) (local.get 0))) (unreachable)
)
(func (param (ref null any)) (result (ref $t))
(block (result (ref null any)) (br_on_cast 1 (ref null any) (ref $t) (local.get 0))) (unreachable)
)
(func (param (ref null any)) (result (ref null $t))
(block (result (ref null any)) (br_on_cast 1 (ref null any) (ref null $t) (local.get 0))) (unreachable)
)
)
(assert_invalid
(module
(type $t (struct))
(func (param (ref any)) (result (ref $t))
(block (result (ref any)) (br_on_cast 1 (ref null any) (ref null $t) (local.get 0))) (unreachable)
)
)
"type mismatch"
)
(assert_invalid
(module
(type $t (struct))
(func (param (ref any)) (result (ref null $t))
(block (result (ref any)) (br_on_cast 1 (ref any) (ref null $t) (local.get 0))) (unreachable)
)
)
"type mismatch"
)
(assert_invalid
(module
(type $t (struct))
(func (param (ref null any)) (result (ref $t))
(block (result (ref any)) (br_on_cast 1 (ref null any) (ref $t) (local.get 0))) (unreachable)
)
)
"type mismatch"
)
(assert_invalid
(module
(func (result anyref)
(br_on_cast 0 eqref anyref (unreachable))
)
)
"type mismatch"
)
(assert_invalid
(module
(func (result anyref)
(br_on_cast 0 structref arrayref (unreachable))
)
)
"type mismatch"
)

View File

@ -0,0 +1,282 @@
;; Abstract Types
(module
(type $ft (func (result i32)))
(type $st (struct (field i16)))
(type $at (array i8))
(table 10 anyref)
(elem declare func $f)
(func $f (result i32) (i32.const 9))
(func (export "init") (param $x externref)
(table.set (i32.const 0) (ref.null any))
(table.set (i32.const 1) (ref.i31 (i32.const 7)))
(table.set (i32.const 2) (struct.new $st (i32.const 6)))
(table.set (i32.const 3) (array.new $at (i32.const 5) (i32.const 3)))
(table.set (i32.const 4) (any.convert_extern (local.get $x)))
)
(func (export "br_on_non_null") (param $i i32) (result i32)
(block $l (result (ref any))
(br_on_non_null $l (table.get (local.get $i)))
(return (i32.const 0))
)
(return (i32.const -1))
)
(func (export "br_on_non_i31") (param $i i32) (result i32)
(block $l (result anyref)
(br_on_cast_fail $l anyref (ref i31) (table.get (local.get $i)))
(return (i31.get_u))
)
(return (i32.const -1))
)
(func (export "br_on_non_struct") (param $i i32) (result i32)
(block $l (result anyref)
(br_on_cast_fail $l anyref (ref struct) (table.get (local.get $i)))
(block $l2 (param structref) (result (ref $st))
(block $l3 (param structref) (result (ref $at))
(br_on_cast $l2 structref (ref $st))
(br_on_cast $l3 anyref (ref $at))
(return (i32.const -2))
)
(return (array.get_u $at (i32.const 0)))
)
(return (struct.get_s $st 0))
)
(return (i32.const -1))
)
(func (export "br_on_non_array") (param $i i32) (result i32)
(block $l (result anyref)
(br_on_cast_fail $l anyref (ref array) (table.get (local.get $i)))
(return (array.len))
)
(return (i32.const -1))
)
(func (export "null-diff") (param $i i32) (result i32)
(block $l (result (ref any))
(block (result (ref null struct))
(br_on_cast_fail $l (ref null any) (ref null struct) (table.get (local.get $i)))
)
(return (i32.const 1))
)
(return (i32.const 0))
)
)
(invoke "init" (ref.extern 0))
(assert_return (invoke "br_on_non_null" (i32.const 0)) (i32.const 0))
(assert_return (invoke "br_on_non_null" (i32.const 1)) (i32.const -1))
(assert_return (invoke "br_on_non_null" (i32.const 2)) (i32.const -1))
(assert_return (invoke "br_on_non_null" (i32.const 3)) (i32.const -1))
(assert_return (invoke "br_on_non_null" (i32.const 4)) (i32.const -1))
(assert_return (invoke "br_on_non_i31" (i32.const 0)) (i32.const -1))
(assert_return (invoke "br_on_non_i31" (i32.const 1)) (i32.const 7))
(assert_return (invoke "br_on_non_i31" (i32.const 2)) (i32.const -1))
(assert_return (invoke "br_on_non_i31" (i32.const 3)) (i32.const -1))
(assert_return (invoke "br_on_non_i31" (i32.const 4)) (i32.const -1))
(assert_return (invoke "br_on_non_struct" (i32.const 0)) (i32.const -1))
(assert_return (invoke "br_on_non_struct" (i32.const 1)) (i32.const -1))
(assert_return (invoke "br_on_non_struct" (i32.const 2)) (i32.const 6))
(assert_return (invoke "br_on_non_struct" (i32.const 3)) (i32.const -1))
(assert_return (invoke "br_on_non_struct" (i32.const 4)) (i32.const -1))
(assert_return (invoke "br_on_non_array" (i32.const 0)) (i32.const -1))
(assert_return (invoke "br_on_non_array" (i32.const 1)) (i32.const -1))
(assert_return (invoke "br_on_non_array" (i32.const 2)) (i32.const -1))
(assert_return (invoke "br_on_non_array" (i32.const 3)) (i32.const 3))
(assert_return (invoke "br_on_non_array" (i32.const 4)) (i32.const -1))
(assert_return (invoke "null-diff" (i32.const 0)) (i32.const 1))
(assert_return (invoke "null-diff" (i32.const 1)) (i32.const 0))
(assert_return (invoke "null-diff" (i32.const 2)) (i32.const 1))
(assert_return (invoke "null-diff" (i32.const 3)) (i32.const 0))
(assert_return (invoke "null-diff" (i32.const 4)) (i32.const 0))
;; Concrete Types
(module
(type $t0 (sub (struct)))
(type $t1 (sub $t0 (struct (field i32))))
(type $t1' (sub $t0 (struct (field i32))))
(type $t2 (sub $t1 (struct (field i32 i32))))
(type $t2' (sub $t1' (struct (field i32 i32))))
(type $t3 (sub $t0 (struct (field i32 i32))))
(type $t0' (sub $t0 (struct)))
(type $t4 (sub $t0' (struct (field i32 i32))))
(table 20 structref)
(func $init
(table.set (i32.const 0) (struct.new_default $t0))
(table.set (i32.const 10) (struct.new_default $t0))
(table.set (i32.const 1) (struct.new_default $t1))
(table.set (i32.const 11) (struct.new_default $t1'))
(table.set (i32.const 2) (struct.new_default $t2))
(table.set (i32.const 12) (struct.new_default $t2'))
(table.set (i32.const 3) (struct.new_default $t3 ))
(table.set (i32.const 4) (struct.new_default $t4))
)
(func (export "test-sub")
(call $init)
(block $l (result structref)
;; must not succeed
(br_on_cast_fail $l structref (ref null $t0) (ref.null struct))
(br_on_cast_fail $l structref (ref null $t0) (table.get (i32.const 0)))
(br_on_cast_fail $l structref (ref null $t0) (table.get (i32.const 1)))
(br_on_cast_fail $l structref (ref null $t0) (table.get (i32.const 2)))
(br_on_cast_fail $l structref (ref null $t0) (table.get (i32.const 3)))
(br_on_cast_fail $l structref (ref null $t0) (table.get (i32.const 4)))
(br_on_cast_fail $l structref (ref $t0) (table.get (i32.const 0)))
(br_on_cast_fail $l structref (ref $t0) (table.get (i32.const 1)))
(br_on_cast_fail $l structref (ref $t0) (table.get (i32.const 2)))
(br_on_cast_fail $l structref (ref $t0) (table.get (i32.const 3)))
(br_on_cast_fail $l structref (ref $t0) (table.get (i32.const 4)))
(br_on_cast_fail $l structref (ref null $t1) (ref.null struct))
(br_on_cast_fail $l structref (ref null $t1) (table.get (i32.const 1)))
(br_on_cast_fail $l structref (ref null $t1) (table.get (i32.const 2)))
(br_on_cast_fail $l structref (ref $t1) (table.get (i32.const 1)))
(br_on_cast_fail $l structref (ref $t1) (table.get (i32.const 2)))
(br_on_cast_fail $l structref (ref null $t2) (ref.null struct))
(br_on_cast_fail $l structref (ref null $t2) (table.get (i32.const 2)))
(br_on_cast_fail $l structref (ref $t2) (table.get (i32.const 2)))
(br_on_cast_fail $l structref (ref null $t3) (ref.null struct))
(br_on_cast_fail $l structref (ref null $t3) (table.get (i32.const 3)))
(br_on_cast_fail $l structref (ref $t3) (table.get (i32.const 3)))
(br_on_cast_fail $l structref (ref null $t4) (ref.null struct))
(br_on_cast_fail $l structref (ref null $t4) (table.get (i32.const 4)))
(br_on_cast_fail $l structref (ref $t4) (table.get (i32.const 4)))
;; must succeed
(drop (block (result structref) (br_on_cast_fail 0 structref (ref $t0) (ref.null struct))))
(drop (block (result structref) (br_on_cast_fail 0 structref (ref $t1) (ref.null struct))))
(drop (block (result structref) (br_on_cast_fail 0 structref (ref $t1) (table.get (i32.const 0)))))
(drop (block (result structref) (br_on_cast_fail 0 structref (ref $t1) (table.get (i32.const 3)))))
(drop (block (result structref) (br_on_cast_fail 0 structref (ref $t1) (table.get (i32.const 4)))))
(drop (block (result structref) (br_on_cast_fail 0 structref (ref $t2) (ref.null struct))))
(drop (block (result structref) (br_on_cast_fail 0 structref (ref $t2) (table.get (i32.const 0)))))
(drop (block (result structref) (br_on_cast_fail 0 structref (ref $t2) (table.get (i32.const 1)))))
(drop (block (result structref) (br_on_cast_fail 0 structref (ref $t2) (table.get (i32.const 3)))))
(drop (block (result structref) (br_on_cast_fail 0 structref (ref $t2) (table.get (i32.const 4)))))
(drop (block (result structref) (br_on_cast_fail 0 structref (ref $t3) (ref.null struct))))
(drop (block (result structref) (br_on_cast_fail 0 structref (ref $t3) (table.get (i32.const 0)))))
(drop (block (result structref) (br_on_cast_fail 0 structref (ref $t3) (table.get (i32.const 1)))))
(drop (block (result structref) (br_on_cast_fail 0 structref (ref $t3) (table.get (i32.const 2)))))
(drop (block (result structref) (br_on_cast_fail 0 structref (ref $t3) (table.get (i32.const 4)))))
(drop (block (result structref) (br_on_cast_fail 0 structref (ref $t4) (ref.null struct))))
(drop (block (result structref) (br_on_cast_fail 0 structref (ref $t4) (table.get (i32.const 0)))))
(drop (block (result structref) (br_on_cast_fail 0 structref (ref $t4) (table.get (i32.const 1)))))
(drop (block (result structref) (br_on_cast_fail 0 structref (ref $t4) (table.get (i32.const 2)))))
(drop (block (result structref) (br_on_cast_fail 0 structref (ref $t4) (table.get (i32.const 3)))))
(return)
)
(unreachable)
)
(func (export "test-canon")
(call $init)
(block $l (result structref)
(br_on_cast_fail $l structref (ref $t0) (table.get (i32.const 0)))
(br_on_cast_fail $l structref (ref $t0) (table.get (i32.const 1)))
(br_on_cast_fail $l structref (ref $t0) (table.get (i32.const 2)))
(br_on_cast_fail $l structref (ref $t0) (table.get (i32.const 3)))
(br_on_cast_fail $l structref (ref $t0) (table.get (i32.const 4)))
(br_on_cast_fail $l structref (ref $t0) (table.get (i32.const 10)))
(br_on_cast_fail $l structref (ref $t0) (table.get (i32.const 11)))
(br_on_cast_fail $l structref (ref $t0) (table.get (i32.const 12)))
(br_on_cast_fail $l structref (ref $t1') (table.get (i32.const 1)))
(br_on_cast_fail $l structref (ref $t1') (table.get (i32.const 2)))
(br_on_cast_fail $l structref (ref $t1) (table.get (i32.const 11)))
(br_on_cast_fail $l structref (ref $t1) (table.get (i32.const 12)))
(br_on_cast_fail $l structref (ref $t2') (table.get (i32.const 2)))
(br_on_cast_fail $l structref (ref $t2) (table.get (i32.const 12)))
(return)
)
(unreachable)
)
)
(invoke "test-sub")
(invoke "test-canon")
;; Cases of nullability
(module
(type $t (struct))
(func (param (ref any)) (result (ref any))
(block (result (ref $t)) (br_on_cast_fail 1 (ref any) (ref $t) (local.get 0)))
)
(func (param (ref null any)) (result (ref null any))
(block (result (ref $t)) (br_on_cast_fail 1 (ref null any) (ref $t) (local.get 0)))
)
(func (param (ref null any)) (result (ref null any))
(block (result (ref null $t)) (br_on_cast_fail 1 (ref null any) (ref null $t) (local.get 0)))
)
)
(assert_invalid
(module
(type $t (struct))
(func (param (ref any)) (result (ref any))
(block (result (ref $t)) (br_on_cast_fail 1 (ref null any) (ref null $t) (local.get 0)))
)
)
"type mismatch"
)
(assert_invalid
(module
(type $t (struct))
(func (param (ref any)) (result (ref any))
(block (result (ref null $t)) (br_on_cast_fail 1 (ref any) (ref null $t) (local.get 0))) (ref.as_non_null)
)
)
"type mismatch"
)
(assert_invalid
(module
(type $t (struct))
(func (param (ref null any)) (result (ref any))
(block (result (ref $t)) (br_on_cast_fail 1 (ref null any) (ref $t) (local.get 0)))
)
)
"type mismatch"
)
(assert_invalid
(module
(func (result anyref)
(br_on_cast_fail 0 eqref anyref (unreachable))
)
)
"type mismatch"
)
(assert_invalid
(module
(func (result anyref)
(br_on_cast_fail 0 structref arrayref (unreachable))
)
)
"type mismatch"
)

View File

@ -0,0 +1,208 @@
(module
(type $ii (func (param i32) (result i32)))
(func $apply (param $f (ref $ii)) (param $x i32) (result i32)
(call_ref $ii (local.get $x) (local.get $f))
)
(func $f (type $ii) (i32.mul (local.get 0) (local.get 0)))
(func $g (type $ii) (i32.sub (i32.const 0) (local.get 0)))
(elem declare func $f $g)
(func (export "run") (param $x i32) (result i32)
(local $rf (ref null $ii))
(local $rg (ref null $ii))
(local.set $rf (ref.func $f))
(local.set $rg (ref.func $g))
(call_ref $ii (call_ref $ii (local.get $x) (local.get $rf)) (local.get $rg))
)
(func (export "null") (result i32)
(call_ref $ii (i32.const 1) (ref.null $ii))
)
;; Recursion
(type $ll (func (param i64) (result i64)))
(type $lll (func (param i64 i64) (result i64)))
(elem declare func $fac)
(global $fac (ref $ll) (ref.func $fac))
(func $fac (export "fac") (type $ll)
(if (result i64) (i64.eqz (local.get 0))
(then (i64.const 1))
(else
(i64.mul
(local.get 0)
(call_ref $ll (i64.sub (local.get 0) (i64.const 1)) (global.get $fac))
)
)
)
)
(elem declare func $fac-acc)
(global $fac-acc (ref $lll) (ref.func $fac-acc))
(func $fac-acc (export "fac-acc") (type $lll)
(if (result i64) (i64.eqz (local.get 0))
(then (local.get 1))
(else
(call_ref $lll
(i64.sub (local.get 0) (i64.const 1))
(i64.mul (local.get 0) (local.get 1))
(global.get $fac-acc)
)
)
)
)
(elem declare func $fib)
(global $fib (ref $ll) (ref.func $fib))
(func $fib (export "fib") (type $ll)
(if (result i64) (i64.le_u (local.get 0) (i64.const 1))
(then (i64.const 1))
(else
(i64.add
(call_ref $ll (i64.sub (local.get 0) (i64.const 2)) (global.get $fib))
(call_ref $ll (i64.sub (local.get 0) (i64.const 1)) (global.get $fib))
)
)
)
)
(elem declare func $even $odd)
(global $even (ref $ll) (ref.func $even))
(global $odd (ref $ll) (ref.func $odd))
(func $even (export "even") (type $ll)
(if (result i64) (i64.eqz (local.get 0))
(then (i64.const 44))
(else (call_ref $ll (i64.sub (local.get 0) (i64.const 1)) (global.get $odd)))
)
)
(func $odd (export "odd") (type $ll)
(if (result i64) (i64.eqz (local.get 0))
(then (i64.const 99))
(else (call_ref $ll (i64.sub (local.get 0) (i64.const 1)) (global.get $even)))
)
)
)
(assert_return (invoke "run" (i32.const 0)) (i32.const 0))
(assert_return (invoke "run" (i32.const 3)) (i32.const -9))
(assert_trap (invoke "null") "null function")
(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 "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 "fib" (i64.const 0)) (i64.const 1))
(assert_return (invoke "fib" (i64.const 1)) (i64.const 1))
(assert_return (invoke "fib" (i64.const 2)) (i64.const 2))
(assert_return (invoke "fib" (i64.const 5)) (i64.const 8))
(assert_return (invoke "fib" (i64.const 20)) (i64.const 10946))
(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 "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))
;; Unreachable typing.
(module
(type $t (func))
(func (export "unreachable") (result i32)
(unreachable)
(call_ref $t)
)
)
(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)
(ref.func $f)
(call_ref $t)
)
)
(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)
(i32.const 0)
(ref.func $f)
(call_ref $t)
(drop)
(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)
(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)
(call_ref $t)
(drop)
(i64.const 0)
)
)
"type mismatch"
)
(assert_invalid
(module
(type $t (func))
(func $f (param $r externref)
(call_ref $t (local.get $r))
)
)
"type mismatch"
)

View File

@ -0,0 +1,54 @@
(module
(type $ft (func))
(type $st (struct))
(type $at (array i8))
(table 10 anyref)
(elem declare func $f)
(func $f)
(func (export "init") (param $x externref)
(table.set (i32.const 0) (ref.null any))
(table.set (i32.const 1) (ref.i31 (i32.const 7)))
(table.set (i32.const 2) (struct.new_default $st))
(table.set (i32.const 3) (array.new_default $at (i32.const 0)))
(table.set (i32.const 4) (any.convert_extern (local.get $x)))
)
(func (export "internalize") (param externref) (result anyref)
(any.convert_extern (local.get 0))
)
(func (export "externalize") (param anyref) (result externref)
(extern.convert_any (local.get 0))
)
(func (export "externalize-i") (param i32) (result externref)
(extern.convert_any (table.get (local.get 0)))
)
(func (export "externalize-ii") (param i32) (result anyref)
(any.convert_extern (extern.convert_any (table.get (local.get 0))))
)
)
(invoke "init" (ref.extern 0))
(assert_return (invoke "internalize" (ref.extern 1)) (ref.host 1))
(assert_return (invoke "internalize" (ref.null extern)) (ref.null any))
(assert_return (invoke "externalize" (ref.host 2)) (ref.extern 2))
(assert_return (invoke "externalize" (ref.null any)) (ref.null extern))
(assert_return (invoke "externalize-i" (i32.const 0)) (ref.null extern))
(assert_return (invoke "externalize-i" (i32.const 1)) (ref.extern))
(assert_return (invoke "externalize-i" (i32.const 2)) (ref.extern))
(assert_return (invoke "externalize-i" (i32.const 3)) (ref.extern))
(assert_return (invoke "externalize-i" (i32.const 4)) (ref.extern 0))
(assert_return (invoke "externalize-i" (i32.const 5)) (ref.null extern))
(assert_return (invoke "externalize-ii" (i32.const 0)) (ref.null any))
(assert_return (invoke "externalize-ii" (i32.const 1)) (ref.i31))
(assert_return (invoke "externalize-ii" (i32.const 2)) (ref.struct))
(assert_return (invoke "externalize-ii" (i32.const 3)) (ref.array))
(assert_return (invoke "externalize-ii" (i32.const 4)) (ref.host 0))
(assert_return (invoke "externalize-ii" (i32.const 5)) (ref.null any))

View File

@ -0,0 +1,51 @@
(module
(func (export "new") (param $i i32) (result (ref i31))
(ref.i31 (local.get $i))
)
(func (export "get_u") (param $i i32) (result i32)
(i31.get_u (ref.i31 (local.get $i)))
)
(func (export "get_s") (param $i i32) (result i32)
(i31.get_s (ref.i31 (local.get $i)))
)
(func (export "get_u-null") (result i32)
(i31.get_u (ref.null i31))
)
(func (export "get_s-null") (result i32)
(i31.get_u (ref.null i31))
)
(global $i (ref i31) (ref.i31 (i32.const 2)))
(global $m (mut (ref i31)) (ref.i31 (i32.const 3)))
(func (export "get_globals") (result i32 i32)
(i31.get_u (global.get $i))
(i31.get_u (global.get $m))
)
)
(assert_return (invoke "new" (i32.const 1)) (ref.i31))
(assert_return (invoke "get_u" (i32.const 0)) (i32.const 0))
(assert_return (invoke "get_u" (i32.const 100)) (i32.const 100))
(assert_return (invoke "get_u" (i32.const -1)) (i32.const 0x7fff_ffff))
(assert_return (invoke "get_u" (i32.const 0x3fff_ffff)) (i32.const 0x3fff_ffff))
(assert_return (invoke "get_u" (i32.const 0x4000_0000)) (i32.const 0x4000_0000))
(assert_return (invoke "get_u" (i32.const 0x7fff_ffff)) (i32.const 0x7fff_ffff))
(assert_return (invoke "get_u" (i32.const 0xaaaa_aaaa)) (i32.const 0x2aaa_aaaa))
(assert_return (invoke "get_u" (i32.const 0xcaaa_aaaa)) (i32.const 0x4aaa_aaaa))
(assert_return (invoke "get_s" (i32.const 0)) (i32.const 0))
(assert_return (invoke "get_s" (i32.const 100)) (i32.const 100))
(assert_return (invoke "get_s" (i32.const -1)) (i32.const -1))
(assert_return (invoke "get_s" (i32.const 0x3fff_ffff)) (i32.const 0x3fff_ffff))
(assert_return (invoke "get_s" (i32.const 0x4000_0000)) (i32.const -0x4000_0000))
(assert_return (invoke "get_s" (i32.const 0x7fff_ffff)) (i32.const -1))
(assert_return (invoke "get_s" (i32.const 0xaaaa_aaaa)) (i32.const 0x2aaa_aaaa))
(assert_return (invoke "get_s" (i32.const 0xcaaa_aaaa)) (i32.const 0xcaaa_aaaa))
(assert_trap (invoke "get_u-null") "null i31 reference")
(assert_trap (invoke "get_s-null") "null i31 reference")
(assert_return (invoke "get_globals") (i32.const 2) (i32.const 3))

View File

@ -0,0 +1,362 @@
;; Test `local.set` operator
(module
;; Typing
(func (export "type-local-i32") (local i32) (local.set 0 (i32.const 0)))
(func (export "type-local-i64") (local i64) (local.set 0 (i64.const 0)))
(func (export "type-local-f32") (local f32) (local.set 0 (f32.const 0)))
(func (export "type-local-f64") (local f64) (local.set 0 (f64.const 0)))
(func (export "type-param-i32") (param i32) (local.set 0 (i32.const 10)))
(func (export "type-param-i64") (param i64) (local.set 0 (i64.const 11)))
(func (export "type-param-f32") (param f32) (local.set 0 (f32.const 11.1)))
(func (export "type-param-f64") (param f64) (local.set 0 (f64.const 12.2)))
(func (export "type-mixed") (param i64 f32 f64 i32 i32) (local f32 i64 i64 f64)
(local.set 0 (i64.const 0))
(local.set 1 (f32.const 0))
(local.set 2 (f64.const 0))
(local.set 3 (i32.const 0))
(local.set 4 (i32.const 0))
(local.set 5 (f32.const 0))
(local.set 6 (i64.const 0))
(local.set 7 (i64.const 0))
(local.set 8 (f64.const 0))
)
;; Writing
(func (export "write") (param i64 f32 f64 i32 i32) (result i64)
(local f32 i64 i64 f64)
(local.set 1 (f32.const -0.3))
(local.set 3 (i32.const 40))
(local.set 4 (i32.const -7))
(local.set 5 (f32.const 5.5))
(local.set 6 (i64.const 6))
(local.set 8 (f64.const 8))
(i64.trunc_f64_s
(f64.add
(f64.convert_i64_u (local.get 0))
(f64.add
(f64.promote_f32 (local.get 1))
(f64.add
(local.get 2)
(f64.add
(f64.convert_i32_u (local.get 3))
(f64.add
(f64.convert_i32_s (local.get 4))
(f64.add
(f64.promote_f32 (local.get 5))
(f64.add
(f64.convert_i64_u (local.get 6))
(f64.add
(f64.convert_i64_u (local.get 7))
(local.get 8)
)
)
)
)
)
)
)
)
)
)
;; As parameter of control constructs and instructions
(func (export "as-block-value") (param i32)
(block (local.set 0 (i32.const 1)))
)
(func (export "as-loop-value") (param i32)
(loop (local.set 0 (i32.const 3)))
)
(func (export "as-br-value") (param i32)
(block (br 0 (local.set 0 (i32.const 9))))
)
(func (export "as-br_if-value") (param i32)
(block
(br_if 0 (local.set 0 (i32.const 8)) (i32.const 1))
)
)
(func (export "as-br_if-value-cond") (param i32)
(block
(br_if 0 (i32.const 6) (local.set 0 (i32.const 9)))
)
)
(func (export "as-br_table-value") (param i32)
(block
(br_table 0 (local.set 0 (i32.const 10)) (i32.const 1))
)
)
(func (export "as-return-value") (param i32)
(return (local.set 0 (i32.const 7)))
)
(func (export "as-if-then") (param i32)
(if (local.get 0) (then (local.set 0 (i32.const 3))))
)
(func (export "as-if-else") (param i32)
(if (local.get 0) (then) (else (local.set 0 (i32.const 1))))
)
)
(assert_return (invoke "type-local-i32"))
(assert_return (invoke "type-local-i64"))
(assert_return (invoke "type-local-f32"))
(assert_return (invoke "type-local-f64"))
(assert_return (invoke "type-param-i32" (i32.const 2)))
(assert_return (invoke "type-param-i64" (i64.const 3)))
(assert_return (invoke "type-param-f32" (f32.const 4.4)))
(assert_return (invoke "type-param-f64" (f64.const 5.5)))
(assert_return (invoke "as-block-value" (i32.const 0)))
(assert_return (invoke "as-loop-value" (i32.const 0)))
(assert_return (invoke "as-br-value" (i32.const 0)))
(assert_return (invoke "as-br_if-value" (i32.const 0)))
(assert_return (invoke "as-br_if-value-cond" (i32.const 0)))
(assert_return (invoke "as-br_table-value" (i32.const 0)))
(assert_return (invoke "as-return-value" (i32.const 0)))
(assert_return (invoke "as-if-then" (i32.const 1)))
(assert_return (invoke "as-if-else" (i32.const 0)))
(assert_return
(invoke "type-mixed"
(i64.const 1) (f32.const 2.2) (f64.const 3.3) (i32.const 4) (i32.const 5)
)
)
(assert_return
(invoke "write"
(i64.const 1) (f32.const 2) (f64.const 3.3) (i32.const 4) (i32.const 5)
)
(i64.const 56)
)
;; Invalid typing of access to locals
(assert_invalid
(module (func $type-local-arg-void-vs-num (local i32) (local.set 0 (nop))))
"type mismatch"
)
(assert_invalid
(module (func $type-local-arg-num-vs-num (local i32) (local.set 0 (f32.const 0))))
"type mismatch"
)
(assert_invalid
(module (func $type-local-arg-num-vs-num (local f32) (local.set 0 (f64.const 0))))
"type mismatch"
)
(assert_invalid
(module (func $type-local-arg-num-vs-num (local f64 i64) (local.set 1 (f64.const 0))))
"type mismatch"
)
;; Invalid typing of access to parameters
(assert_invalid
(module (func $type-param-arg-void-vs-num (param i32) (local.set 0 (nop))))
"type mismatch"
)
(assert_invalid
(module (func $type-param-arg-num-vs-num (param i32) (local.set 0 (f32.const 0))))
"type mismatch"
)
(assert_invalid
(module (func $type-param-arg-num-vs-num (param f32) (local.set 0 (f64.const 0))))
"type mismatch"
)
(assert_invalid
(module (func $type-param-arg-num-vs-num (param f64 i64) (local.set 1 (f64.const 0))))
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num (param i32)
(local.set 0)
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num-in-block (param i32)
(i32.const 0)
(block (local.set 0))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num-in-loop (param i32)
(i32.const 0)
(loop (local.set 0))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num-in-then (param i32)
(i32.const 0)
(if (i32.const 1) (then (local.set 0)))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num-in-else (param i32)
(i32.const 0)
(if (result i32) (i32.const 0) (then (i32.const 0)) (else (local.set 0)))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num-in-br (param i32)
(i32.const 0)
(block (br 0 (local.set 0)))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num-in-br_if (param i32)
(i32.const 0)
(block (br_if 0 (local.set 0)))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num-in-br_table (param i32)
(i32.const 0)
(block (br_table 0 (local.set 0)))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num-in-return (param i32)
(return (local.set 0))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num-in-select (param i32)
(select (local.set 0) (i32.const 1) (i32.const 2))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num-in-call (param i32)
(call 1 (local.set 0))
)
(func (param i32) (result i32) (local.get 0))
)
"type mismatch"
)
(assert_invalid
(module
(func $f (param i32) (result i32) (local.get 0))
(type $sig (func (param i32) (result i32)))
(table funcref (elem $f))
(func $type-param-arg-empty-vs-num-in-call_indirect (param i32)
(block (result i32)
(call_indirect (type $sig)
(local.set 0) (i32.const 0)
)
)
)
)
"type mismatch"
)
;; Invalid typing of access to mixed args
(assert_invalid
(module (func $type-mixed-arg-num-vs-num (param f32) (local i32) (local.set 1 (f32.const 0))))
"type mismatch"
)
(assert_invalid
(module (func $type-mixed-arg-num-vs-num (param i64 i32) (local f32) (local.set 1 (f32.const 0))))
"type mismatch"
)
(assert_invalid
(module (func $type-mixed-arg-num-vs-num (param i64) (local f64 i64) (local.set 1 (i64.const 0))))
"type mismatch"
)
;; local.set should have no retval
(assert_invalid
(module (func $type-empty-vs-i32 (param i32) (result i32) (local.set 0 (i32.const 1))))
"type mismatch"
)
(assert_invalid
(module (func $type-empty-vs-i64 (param i64) (result i64) (local.set 0 (i64.const 1))))
"type mismatch"
)
(assert_invalid
(module (func $type-empty-vs-f32 (param f32) (result f32) (local.set 0 (f32.const 1))))
"type mismatch"
)
(assert_invalid
(module (func $type-empty-vs-f64 (param f64) (result f64) (local.set 0 (f64.const 1))))
"type mismatch"
)
;; Invalid local index
(assert_invalid
(module (func $unbound-local (local i32 i64) (local.set 3 (i32.const 0))))
"unknown local"
)
(assert_invalid
(module (func $large-local (local i32 i64) (local.set 14324343 (i32.const 0))))
"unknown local"
)
(assert_invalid
(module (func $unbound-param (param i32 i64) (local.set 2 (i32.const 0))))
"unknown local"
)
(assert_invalid
(module (func $large-param (param i32 i64) (local.set 714324343 (i32.const 0))))
"unknown local"
)
(assert_invalid
(module (func $unbound-mixed (param i32) (local i32 i64) (local.set 3 (i32.const 0))))
"unknown local"
)
(assert_invalid
(module (func $large-mixed (param i64) (local i32 i64) (local.set 214324343 (i32.const 0))))
"unknown local"
)

View File

@ -0,0 +1,639 @@
;; Test `local.tee` operator
(module
;; Typing
(func (export "type-local-i32") (result i32) (local i32) (local.tee 0 (i32.const 0)))
(func (export "type-local-i64") (result i64) (local i64) (local.tee 0 (i64.const 0)))
(func (export "type-local-f32") (result f32) (local f32) (local.tee 0 (f32.const 0)))
(func (export "type-local-f64") (result f64) (local f64) (local.tee 0 (f64.const 0)))
(func (export "type-param-i32") (param i32) (result i32) (local.tee 0 (i32.const 10)))
(func (export "type-param-i64") (param i64) (result i64) (local.tee 0 (i64.const 11)))
(func (export "type-param-f32") (param f32) (result f32) (local.tee 0 (f32.const 11.1)))
(func (export "type-param-f64") (param f64) (result f64) (local.tee 0 (f64.const 12.2)))
(func (export "type-mixed") (param i64 f32 f64 i32 i32) (local f32 i64 i64 f64)
(drop (i64.eqz (local.tee 0 (i64.const 0))))
(drop (f32.neg (local.tee 1 (f32.const 0))))
(drop (f64.neg (local.tee 2 (f64.const 0))))
(drop (i32.eqz (local.tee 3 (i32.const 0))))
(drop (i32.eqz (local.tee 4 (i32.const 0))))
(drop (f32.neg (local.tee 5 (f32.const 0))))
(drop (i64.eqz (local.tee 6 (i64.const 0))))
(drop (i64.eqz (local.tee 7 (i64.const 0))))
(drop (f64.neg (local.tee 8 (f64.const 0))))
)
;; Writing
(func (export "write") (param i64 f32 f64 i32 i32) (result i64) (local f32 i64 i64 f64)
(drop (local.tee 1 (f32.const -0.3)))
(drop (local.tee 3 (i32.const 40)))
(drop (local.tee 4 (i32.const -7)))
(drop (local.tee 5 (f32.const 5.5)))
(drop (local.tee 6 (i64.const 6)))
(drop (local.tee 8 (f64.const 8)))
(i64.trunc_f64_s
(f64.add
(f64.convert_i64_u (local.get 0))
(f64.add
(f64.promote_f32 (local.get 1))
(f64.add
(local.get 2)
(f64.add
(f64.convert_i32_u (local.get 3))
(f64.add
(f64.convert_i32_s (local.get 4))
(f64.add
(f64.promote_f32 (local.get 5))
(f64.add
(f64.convert_i64_u (local.get 6))
(f64.add
(f64.convert_i64_u (local.get 7))
(local.get 8)
)
)
)
)
)
)
)
)
)
)
;; Result
(func (export "result") (param i64 f32 f64 i32 i32) (result f64)
(local f32 i64 i64 f64)
(f64.add
(f64.convert_i64_u (local.tee 0 (i64.const 1)))
(f64.add
(f64.promote_f32 (local.tee 1 (f32.const 2)))
(f64.add
(local.tee 2 (f64.const 3.3))
(f64.add
(f64.convert_i32_u (local.tee 3 (i32.const 4)))
(f64.add
(f64.convert_i32_s (local.tee 4 (i32.const 5)))
(f64.add
(f64.promote_f32 (local.tee 5 (f32.const 5.5)))
(f64.add
(f64.convert_i64_u (local.tee 6 (i64.const 6)))
(f64.add
(f64.convert_i64_u (local.tee 7 (i64.const 0)))
(local.tee 8 (f64.const 8))
)
)
)
)
)
)
)
)
)
(func $dummy)
(func (export "as-block-first") (param i32) (result i32)
(block (result i32) (local.tee 0 (i32.const 1)) (call $dummy))
)
(func (export "as-block-mid") (param i32) (result i32)
(block (result i32) (call $dummy) (local.tee 0 (i32.const 1)) (call $dummy))
)
(func (export "as-block-last") (param i32) (result i32)
(block (result i32) (call $dummy) (call $dummy) (local.tee 0 (i32.const 1)))
)
(func (export "as-loop-first") (param i32) (result i32)
(loop (result i32) (local.tee 0 (i32.const 3)) (call $dummy))
)
(func (export "as-loop-mid") (param i32) (result i32)
(loop (result i32) (call $dummy) (local.tee 0 (i32.const 4)) (call $dummy))
)
(func (export "as-loop-last") (param i32) (result i32)
(loop (result i32) (call $dummy) (call $dummy) (local.tee 0 (i32.const 5)))
)
(func (export "as-br-value") (param i32) (result i32)
(block (result i32) (br 0 (local.tee 0 (i32.const 9))))
)
(func (export "as-br_if-cond") (param i32)
(block (br_if 0 (local.tee 0 (i32.const 1))))
)
(func (export "as-br_if-value") (param i32) (result i32)
(block (result i32)
(drop (br_if 0 (local.tee 0 (i32.const 8)) (i32.const 1))) (i32.const 7)
)
)
(func (export "as-br_if-value-cond") (param i32) (result i32)
(block (result i32)
(drop (br_if 0 (i32.const 6) (local.tee 0 (i32.const 9)))) (i32.const 7)
)
)
(func (export "as-br_table-index") (param i32)
(block (br_table 0 0 0 (local.tee 0 (i32.const 0))))
)
(func (export "as-br_table-value") (param i32) (result i32)
(block (result i32)
(br_table 0 0 0 (local.tee 0 (i32.const 10)) (i32.const 1)) (i32.const 7)
)
)
(func (export "as-br_table-value-index") (param i32) (result i32)
(block (result i32)
(br_table 0 0 (i32.const 6) (local.tee 0 (i32.const 11))) (i32.const 7)
)
)
(func (export "as-return-value") (param i32) (result i32)
(return (local.tee 0 (i32.const 7)))
)
(func (export "as-if-cond") (param i32) (result i32)
(if (result i32) (local.tee 0 (i32.const 2))
(then (i32.const 0)) (else (i32.const 1))
)
)
(func (export "as-if-then") (param i32) (result i32)
(if (result i32) (local.get 0)
(then (local.tee 0 (i32.const 3))) (else (local.get 0))
)
)
(func (export "as-if-else") (param i32) (result i32)
(if (result i32) (local.get 0)
(then (local.get 0)) (else (local.tee 0 (i32.const 4)))
)
)
(func (export "as-select-first") (param i32 i32) (result i32)
(select (local.tee 0 (i32.const 5)) (local.get 0) (local.get 1))
)
(func (export "as-select-second") (param i32 i32) (result i32)
(select (local.get 0) (local.tee 0 (i32.const 6)) (local.get 1))
)
(func (export "as-select-cond") (param i32) (result i32)
(select (i32.const 0) (i32.const 1) (local.tee 0 (i32.const 7)))
)
(func $f (param i32 i32 i32) (result i32) (i32.const -1))
(func (export "as-call-first") (param i32) (result i32)
(call $f (local.tee 0 (i32.const 12)) (i32.const 2) (i32.const 3))
)
(func (export "as-call-mid") (param i32) (result i32)
(call $f (i32.const 1) (local.tee 0 (i32.const 13)) (i32.const 3))
)
(func (export "as-call-last") (param i32) (result i32)
(call $f (i32.const 1) (i32.const 2) (local.tee 0 (i32.const 14)))
)
(type $sig (func (param i32 i32 i32) (result i32)))
(table funcref (elem $f))
(func (export "as-call_indirect-first") (param i32) (result i32)
(call_indirect (type $sig)
(local.tee 0 (i32.const 1)) (i32.const 2) (i32.const 3) (i32.const 0)
)
)
(func (export "as-call_indirect-mid") (param i32) (result i32)
(call_indirect (type $sig)
(i32.const 1) (local.tee 0 (i32.const 2)) (i32.const 3) (i32.const 0)
)
)
(func (export "as-call_indirect-last") (param i32) (result i32)
(call_indirect (type $sig)
(i32.const 1) (i32.const 2) (local.tee 0 (i32.const 3)) (i32.const 0)
)
)
(func (export "as-call_indirect-index") (param i32) (result i32)
(call_indirect (type $sig)
(i32.const 1) (i32.const 2) (i32.const 3) (local.tee 0 (i32.const 0))
)
)
(func (export "as-local.set-value") (local i32)
(local.set 0 (local.tee 0 (i32.const 1)))
)
(func (export "as-local.tee-value") (param i32) (result i32)
(local.tee 0 (local.tee 0 (i32.const 1)))
)
(global $g (mut i32) (i32.const 0))
(func (export "as-global.set-value") (local i32)
(global.set $g (local.tee 0 (i32.const 1)))
)
(memory 1)
(func (export "as-load-address") (param i32) (result i32)
(i32.load (local.tee 0 (i32.const 1)))
)
(func (export "as-loadN-address") (param i32) (result i32)
(i32.load8_s (local.tee 0 (i32.const 3)))
)
(func (export "as-store-address") (param i32)
(i32.store (local.tee 0 (i32.const 30)) (i32.const 7))
)
(func (export "as-store-value") (param i32)
(i32.store (i32.const 2) (local.tee 0 (i32.const 1)))
)
(func (export "as-storeN-address") (param i32)
(i32.store8 (local.tee 0 (i32.const 1)) (i32.const 7))
)
(func (export "as-storeN-value") (param i32)
(i32.store16 (i32.const 2) (local.tee 0 (i32.const 1)))
)
(func (export "as-unary-operand") (param f32) (result f32)
(f32.neg (local.tee 0 (f32.const nan:0x0f1e2)))
)
(func (export "as-binary-left") (param i32) (result i32)
(i32.add (local.tee 0 (i32.const 3)) (i32.const 10))
)
(func (export "as-binary-right") (param i32) (result i32)
(i32.sub (i32.const 10) (local.tee 0 (i32.const 4)))
)
(func (export "as-test-operand") (param i32) (result i32)
(i32.eqz (local.tee 0 (i32.const 0)))
)
(func (export "as-compare-left") (param i32) (result i32)
(i32.le_s (local.tee 0 (i32.const 43)) (i32.const 10))
)
(func (export "as-compare-right") (param i32) (result i32)
(i32.ne (i32.const 10) (local.tee 0 (i32.const 42)))
)
(func (export "as-convert-operand") (param i64) (result i32)
(i32.wrap_i64 (local.tee 0 (i64.const 41)))
)
(func (export "as-memory.grow-size") (param i32) (result i32)
(memory.grow (local.tee 0 (i32.const 40)))
)
)
(assert_return (invoke "type-local-i32") (i32.const 0))
(assert_return (invoke "type-local-i64") (i64.const 0))
(assert_return (invoke "type-local-f32") (f32.const 0))
(assert_return (invoke "type-local-f64") (f64.const 0))
(assert_return (invoke "type-param-i32" (i32.const 2)) (i32.const 10))
(assert_return (invoke "type-param-i64" (i64.const 3)) (i64.const 11))
(assert_return (invoke "type-param-f32" (f32.const 4.4)) (f32.const 11.1))
(assert_return (invoke "type-param-f64" (f64.const 5.5)) (f64.const 12.2))
(assert_return (invoke "as-block-first" (i32.const 0)) (i32.const 1))
(assert_return (invoke "as-block-mid" (i32.const 0)) (i32.const 1))
(assert_return (invoke "as-block-last" (i32.const 0)) (i32.const 1))
(assert_return (invoke "as-loop-first" (i32.const 0)) (i32.const 3))
(assert_return (invoke "as-loop-mid" (i32.const 0)) (i32.const 4))
(assert_return (invoke "as-loop-last" (i32.const 0)) (i32.const 5))
(assert_return (invoke "as-br-value" (i32.const 0)) (i32.const 9))
(assert_return (invoke "as-br_if-cond" (i32.const 0)))
(assert_return (invoke "as-br_if-value" (i32.const 0)) (i32.const 8))
(assert_return (invoke "as-br_if-value-cond" (i32.const 0)) (i32.const 6))
(assert_return (invoke "as-br_table-index" (i32.const 0)))
(assert_return (invoke "as-br_table-value" (i32.const 0)) (i32.const 10))
(assert_return (invoke "as-br_table-value-index" (i32.const 0)) (i32.const 6))
(assert_return (invoke "as-return-value" (i32.const 0)) (i32.const 7))
(assert_return (invoke "as-if-cond" (i32.const 0)) (i32.const 0))
(assert_return (invoke "as-if-then" (i32.const 1)) (i32.const 3))
(assert_return (invoke "as-if-else" (i32.const 0)) (i32.const 4))
(assert_return (invoke "as-select-first" (i32.const 0) (i32.const 1)) (i32.const 5))
(assert_return (invoke "as-select-second" (i32.const 0) (i32.const 0)) (i32.const 6))
(assert_return (invoke "as-select-cond" (i32.const 0)) (i32.const 0))
(assert_return (invoke "as-call-first" (i32.const 0)) (i32.const -1))
(assert_return (invoke "as-call-mid" (i32.const 0)) (i32.const -1))
(assert_return (invoke "as-call-last" (i32.const 0)) (i32.const -1))
(assert_return (invoke "as-call_indirect-first" (i32.const 0)) (i32.const -1))
(assert_return (invoke "as-call_indirect-mid" (i32.const 0)) (i32.const -1))
(assert_return (invoke "as-call_indirect-last" (i32.const 0)) (i32.const -1))
(assert_return (invoke "as-call_indirect-index" (i32.const 0)) (i32.const -1))
(assert_return (invoke "as-local.set-value"))
(assert_return (invoke "as-local.tee-value" (i32.const 0)) (i32.const 1))
(assert_return (invoke "as-global.set-value"))
(assert_return (invoke "as-load-address" (i32.const 0)) (i32.const 0))
(assert_return (invoke "as-loadN-address" (i32.const 0)) (i32.const 0))
(assert_return (invoke "as-store-address" (i32.const 0)))
(assert_return (invoke "as-store-value" (i32.const 0)))
(assert_return (invoke "as-storeN-address" (i32.const 0)))
(assert_return (invoke "as-storeN-value" (i32.const 0)))
(assert_return (invoke "as-unary-operand" (f32.const 0)) (f32.const -nan:0x0f1e2))
(assert_return (invoke "as-binary-left" (i32.const 0)) (i32.const 13))
(assert_return (invoke "as-binary-right" (i32.const 0)) (i32.const 6))
(assert_return (invoke "as-test-operand" (i32.const 0)) (i32.const 1))
(assert_return (invoke "as-compare-left" (i32.const 0)) (i32.const 0))
(assert_return (invoke "as-compare-right" (i32.const 0)) (i32.const 1))
(assert_return (invoke "as-convert-operand" (i64.const 0)) (i32.const 41))
(assert_return (invoke "as-memory.grow-size" (i32.const 0)) (i32.const 1))
(assert_return
(invoke "type-mixed"
(i64.const 1) (f32.const 2.2) (f64.const 3.3) (i32.const 4) (i32.const 5)
)
)
(assert_return
(invoke "write"
(i64.const 1) (f32.const 2) (f64.const 3.3) (i32.const 4) (i32.const 5)
)
(i64.const 56)
)
(assert_return
(invoke "result"
(i64.const -1) (f32.const -2) (f64.const -3.3) (i32.const -4) (i32.const -5)
)
(f64.const 34.8)
)
;; Invalid typing of access to locals
(assert_invalid
(module (func $type-local-num-vs-num (result i64) (local i32) (local.tee 0 (i32.const 0))))
"type mismatch"
)
(assert_invalid
(module (func $type-local-num-vs-num (local f32) (i32.eqz (local.tee 0 (f32.const 0)))))
"type mismatch"
)
(assert_invalid
(module (func $type-local-num-vs-num (local f64 i64) (f64.neg (local.tee 1 (i64.const 0)))))
"type mismatch"
)
(assert_invalid
(module (func $type-local-arg-void-vs-num (local i32) (local.tee 0 (nop))))
"type mismatch"
)
(assert_invalid
(module (func $type-local-arg-num-vs-num (local i32) (local.tee 0 (f32.const 0))))
"type mismatch"
)
(assert_invalid
(module (func $type-local-arg-num-vs-num (local f32) (local.tee 0 (f64.const 0))))
"type mismatch"
)
(assert_invalid
(module (func $type-local-arg-num-vs-num (local f64 i64) (local.tee 1 (f64.const 0))))
"type mismatch"
)
;; Invalid typing of access to parameters
(assert_invalid
(module (func $type-param-num-vs-num (param i32) (result i64) (local.get 0)))
"type mismatch"
)
(assert_invalid
(module (func $type-param-num-vs-num (param f32) (i32.eqz (local.get 0))))
"type mismatch"
)
(assert_invalid
(module (func $type-param-num-vs-num (param f64 i64) (f64.neg (local.get 1))))
"type mismatch"
)
(assert_invalid
(module (func $type-param-arg-void-vs-num (param i32) (local.tee 0 (nop))))
"type mismatch"
)
(assert_invalid
(module (func $type-param-arg-num-vs-num (param i32) (local.tee 0 (f32.const 0))))
"type mismatch"
)
(assert_invalid
(module (func $type-param-arg-num-vs-num (param f32) (local.tee 0 (f64.const 0))))
"type mismatch"
)
(assert_invalid
(module (func $type-param-arg-num-vs-num (param f64 i64) (local.tee 1 (f64.const 0))))
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num (param i32)
(local.tee 0) (drop)
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num-in-block (param i32)
(i32.const 0)
(block (local.tee 0) (drop))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num-in-loop (param i32)
(i32.const 0)
(loop (local.tee 0) (drop))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num-in-then (param i32)
(i32.const 0) (i32.const 0)
(if (then (local.tee 0) (drop)))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num-in-else (param i32)
(i32.const 0) (i32.const 0)
(if (result i32) (then (i32.const 0)) (else (local.tee 0))) (drop)
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num-in-br (param i32)
(i32.const 0)
(block (br 0 (local.tee 0)) (drop))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num-in-br_if (param i32)
(i32.const 0)
(block (br_if 0 (local.tee 0) (i32.const 1)) (drop))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num-in-br_table (param i32)
(i32.const 0)
(block (br_table 0 (local.tee 0)) (drop))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num-in-return (param i32)
(return (local.tee 0)) (drop)
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num-in-select (param i32)
(select (local.tee 0) (i32.const 1) (i32.const 2)) (drop)
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num-in-call (param i32)
(call 1 (local.tee 0)) (drop)
)
(func (param i32) (result i32) (local.get 0))
)
"type mismatch"
)
(assert_invalid
(module
(func $f (param i32) (result i32) (local.get 0))
(type $sig (func (param i32) (result i32)))
(table funcref (elem $f))
(func $type-param-arg-empty-vs-num-in-call_indirect (param i32)
(block (result i32)
(call_indirect (type $sig)
(local.tee 0) (i32.const 0)
)
(drop)
)
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num-in-local.set (param i32)
(local.set 0 (local.tee 0)) (local.get 0) (drop)
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-param-arg-empty-vs-num-in-local.tee (param i32)
(local.tee 0 (local.tee 0)) (drop)
)
)
"type mismatch"
)
(assert_invalid
(module
(global $x (mut i32) (i32.const 0))
(func $type-param-arg-empty-vs-num-in-global.set (param i32)
(global.set $x (local.tee 0)) (global.get $x) (drop)
)
)
"type mismatch"
)
(assert_invalid
(module
(memory 0)
(func $type-param-arg-empty-vs-num-in-memory.grow (param i32)
(memory.grow (local.tee 0)) (drop)
)
)
"type mismatch"
)
(assert_invalid
(module
(memory 0)
(func $type-param-arg-empty-vs-num-in-load (param i32)
(i32.load (local.tee 0)) (drop)
)
)
"type mismatch"
)
(assert_invalid
(module
(memory 1)
(func $type-param-arg-empty-vs-num-in-store (param i32)
(i32.store (local.tee 0) (i32.const 1))
)
)
"type mismatch"
)
(assert_invalid
(module (func $type-mixed-arg-num-vs-num (param f32) (local i32) (local.tee 1 (f32.const 0))))
"type mismatch"
)
(assert_invalid
(module (func $type-mixed-arg-num-vs-num (param i64 i32) (local f32) (local.tee 1 (f32.const 0))))
"type mismatch"
)
(assert_invalid
(module (func $type-mixed-arg-num-vs-num (param i64) (local f64 i64) (local.tee 1 (i64.const 0))))
"type mismatch"
)
;; Invalid local index
(assert_invalid
(module (func $unbound-local (local i32 i64) (local.tee 3 (i32.const 0)) drop))
"unknown local"
)
(assert_invalid
(module (func $large-local (local i32 i64) (local.tee 14324343 (i32.const 0)) drop))
"unknown local"
)
(assert_invalid
(module (func $unbound-param (param i32 i64) (local.tee 2 (i32.const 0)) drop))
"unknown local"
)
(assert_invalid
(module (func $large-param (param i32 i64) (local.tee 714324343 (i32.const 0)) drop))
"unknown local"
)
(assert_invalid
(module (func $unbound-mixed (param i32) (local i32 i64) (local.tee 3 (i32.const 0)) drop))
"unknown local"
)
(assert_invalid
(module (func $large-mixed (param i64) (local i32 i64) (local.tee 214324343 (i32.const 0)) drop))
"unknown local"
)

View File

@ -0,0 +1,186 @@
;; Abstract Types
(module
(type $ft (func))
(type $st (struct))
(type $at (array i8))
(table 10 anyref)
(elem declare func $f)
(func $f)
(func (export "init") (param $x externref)
(table.set (i32.const 0) (ref.null any))
(table.set (i32.const 1) (ref.i31 (i32.const 7)))
(table.set (i32.const 2) (struct.new_default $st))
(table.set (i32.const 3) (array.new_default $at (i32.const 0)))
(table.set (i32.const 4) (any.convert_extern (local.get $x)))
(table.set (i32.const 5) (ref.null i31))
(table.set (i32.const 6) (ref.null struct))
(table.set (i32.const 7) (ref.null none))
)
(func (export "ref_cast_non_null") (param $i i32)
(drop (ref.as_non_null (table.get (local.get $i))))
(drop (ref.cast (ref null any) (table.get (local.get $i))))
)
(func (export "ref_cast_null") (param $i i32)
(drop (ref.cast anyref (table.get (local.get $i))))
(drop (ref.cast structref (table.get (local.get $i))))
(drop (ref.cast arrayref (table.get (local.get $i))))
(drop (ref.cast i31ref (table.get (local.get $i))))
(drop (ref.cast nullref (table.get (local.get $i))))
)
(func (export "ref_cast_i31") (param $i i32)
(drop (ref.cast (ref i31) (table.get (local.get $i))))
(drop (ref.cast i31ref (table.get (local.get $i))))
)
(func (export "ref_cast_struct") (param $i i32)
(drop (ref.cast (ref struct) (table.get (local.get $i))))
(drop (ref.cast structref (table.get (local.get $i))))
)
(func (export "ref_cast_array") (param $i i32)
(drop (ref.cast (ref array) (table.get (local.get $i))))
(drop (ref.cast arrayref (table.get (local.get $i))))
)
)
(invoke "init" (ref.extern 0))
(assert_trap (invoke "ref_cast_non_null" (i32.const 0)) "null reference")
(assert_return (invoke "ref_cast_non_null" (i32.const 1)))
(assert_return (invoke "ref_cast_non_null" (i32.const 2)))
(assert_return (invoke "ref_cast_non_null" (i32.const 3)))
(assert_return (invoke "ref_cast_non_null" (i32.const 4)))
(assert_trap (invoke "ref_cast_non_null" (i32.const 5)) "null reference")
(assert_trap (invoke "ref_cast_non_null" (i32.const 6)) "null reference")
(assert_trap (invoke "ref_cast_non_null" (i32.const 7)) "null reference")
(assert_return (invoke "ref_cast_null" (i32.const 0)))
(assert_trap (invoke "ref_cast_null" (i32.const 1)) "cast failure")
(assert_trap (invoke "ref_cast_null" (i32.const 2)) "cast failure")
(assert_trap (invoke "ref_cast_null" (i32.const 3)) "cast failure")
(assert_trap (invoke "ref_cast_null" (i32.const 4)) "cast failure")
(assert_return (invoke "ref_cast_null" (i32.const 5)))
(assert_return (invoke "ref_cast_null" (i32.const 6)))
(assert_return (invoke "ref_cast_null" (i32.const 7)))
(assert_trap (invoke "ref_cast_i31" (i32.const 0)) "cast failure")
(assert_return (invoke "ref_cast_i31" (i32.const 1)))
(assert_trap (invoke "ref_cast_i31" (i32.const 2)) "cast failure")
(assert_trap (invoke "ref_cast_i31" (i32.const 3)) "cast failure")
(assert_trap (invoke "ref_cast_i31" (i32.const 4)) "cast failure")
(assert_trap (invoke "ref_cast_i31" (i32.const 5)) "cast failure")
(assert_trap (invoke "ref_cast_i31" (i32.const 6)) "cast failure")
(assert_trap (invoke "ref_cast_i31" (i32.const 7)) "cast failure")
(assert_trap (invoke "ref_cast_struct" (i32.const 0)) "cast failure")
(assert_trap (invoke "ref_cast_struct" (i32.const 1)) "cast failure")
(assert_return (invoke "ref_cast_struct" (i32.const 2)))
(assert_trap (invoke "ref_cast_struct" (i32.const 3)) "cast failure")
(assert_trap (invoke "ref_cast_struct" (i32.const 4)) "cast failure")
(assert_trap (invoke "ref_cast_struct" (i32.const 5)) "cast failure")
(assert_trap (invoke "ref_cast_struct" (i32.const 6)) "cast failure")
(assert_trap (invoke "ref_cast_struct" (i32.const 7)) "cast failure")
(assert_trap (invoke "ref_cast_array" (i32.const 0)) "cast failure")
(assert_trap (invoke "ref_cast_array" (i32.const 1)) "cast failure")
(assert_trap (invoke "ref_cast_array" (i32.const 2)) "cast failure")
(assert_return (invoke "ref_cast_array" (i32.const 3)))
(assert_trap (invoke "ref_cast_array" (i32.const 4)) "cast failure")
(assert_trap (invoke "ref_cast_array" (i32.const 5)) "cast failure")
(assert_trap (invoke "ref_cast_array" (i32.const 6)) "cast failure")
(assert_trap (invoke "ref_cast_array" (i32.const 7)) "cast failure")
;; Concrete Types
(module
(type $t0 (sub (struct)))
(type $t1 (sub $t0 (struct (field i32))))
(type $t1' (sub $t0 (struct (field i32))))
(type $t2 (sub $t1 (struct (field i32 i32))))
(type $t2' (sub $t1' (struct (field i32 i32))))
(type $t3 (sub $t0 (struct (field i32 i32))))
(type $t0' (sub $t0 (struct)))
(type $t4 (sub $t0' (struct (field i32 i32))))
(table 20 (ref null struct))
(func $init
(table.set (i32.const 0) (struct.new_default $t0))
(table.set (i32.const 10) (struct.new_default $t0))
(table.set (i32.const 1) (struct.new_default $t1))
(table.set (i32.const 11) (struct.new_default $t1'))
(table.set (i32.const 2) (struct.new_default $t2))
(table.set (i32.const 12) (struct.new_default $t2'))
(table.set (i32.const 3) (struct.new_default $t3))
(table.set (i32.const 4) (struct.new_default $t4))
)
(func (export "test-sub")
(call $init)
(drop (ref.cast (ref null $t0) (ref.null struct)))
(drop (ref.cast (ref null $t0) (table.get (i32.const 0))))
(drop (ref.cast (ref null $t0) (table.get (i32.const 1))))
(drop (ref.cast (ref null $t0) (table.get (i32.const 2))))
(drop (ref.cast (ref null $t0) (table.get (i32.const 3))))
(drop (ref.cast (ref null $t0) (table.get (i32.const 4))))
(drop (ref.cast (ref null $t0) (ref.null struct)))
(drop (ref.cast (ref null $t1) (table.get (i32.const 1))))
(drop (ref.cast (ref null $t1) (table.get (i32.const 2))))
(drop (ref.cast (ref null $t0) (ref.null struct)))
(drop (ref.cast (ref null $t2) (table.get (i32.const 2))))
(drop (ref.cast (ref null $t0) (ref.null struct)))
(drop (ref.cast (ref null $t3) (table.get (i32.const 3))))
(drop (ref.cast (ref null $t4) (table.get (i32.const 4))))
(drop (ref.cast (ref $t0) (table.get (i32.const 0))))
(drop (ref.cast (ref $t0) (table.get (i32.const 1))))
(drop (ref.cast (ref $t0) (table.get (i32.const 2))))
(drop (ref.cast (ref $t0) (table.get (i32.const 3))))
(drop (ref.cast (ref $t0) (table.get (i32.const 4))))
(drop (ref.cast (ref $t1) (table.get (i32.const 1))))
(drop (ref.cast (ref $t1) (table.get (i32.const 2))))
(drop (ref.cast (ref $t2) (table.get (i32.const 2))))
(drop (ref.cast (ref $t3) (table.get (i32.const 3))))
(drop (ref.cast (ref $t4) (table.get (i32.const 4))))
)
(func (export "test-canon")
(call $init)
(drop (ref.cast (ref $t0) (table.get (i32.const 0))))
(drop (ref.cast (ref $t0) (table.get (i32.const 1))))
(drop (ref.cast (ref $t0) (table.get (i32.const 2))))
(drop (ref.cast (ref $t0) (table.get (i32.const 3))))
(drop (ref.cast (ref $t0) (table.get (i32.const 4))))
(drop (ref.cast (ref $t0) (table.get (i32.const 10))))
(drop (ref.cast (ref $t0) (table.get (i32.const 11))))
(drop (ref.cast (ref $t0) (table.get (i32.const 12))))
(drop (ref.cast (ref $t1') (table.get (i32.const 1))))
(drop (ref.cast (ref $t1') (table.get (i32.const 2))))
(drop (ref.cast (ref $t1) (table.get (i32.const 11))))
(drop (ref.cast (ref $t1) (table.get (i32.const 12))))
(drop (ref.cast (ref $t2') (table.get (i32.const 2))))
(drop (ref.cast (ref $t2) (table.get (i32.const 12))))
)
)
(invoke "test-sub")
(invoke "test-canon")

View File

@ -0,0 +1,168 @@
(module
(type $st (sub (struct)))
(type $st' (sub (struct (field i32))))
(type $at (array i8))
(type $st-sub1 (sub $st (struct)))
(type $st-sub2 (sub $st (struct)))
(type $st'-sub1 (sub $st' (struct (field i32))))
(type $st'-sub2 (sub $st' (struct (field i32))))
(table 20 (ref null eq))
(func (export "init")
(table.set (i32.const 0) (ref.null eq))
(table.set (i32.const 1) (ref.null i31))
(table.set (i32.const 2) (ref.i31 (i32.const 7)))
(table.set (i32.const 3) (ref.i31 (i32.const 7)))
(table.set (i32.const 4) (ref.i31 (i32.const 8)))
(table.set (i32.const 5) (struct.new_default $st))
(table.set (i32.const 6) (struct.new_default $st))
(table.set (i32.const 7) (array.new_default $at (i32.const 0)))
(table.set (i32.const 8) (array.new_default $at (i32.const 0)))
)
(func (export "eq") (param $i i32) (param $j i32) (result i32)
(ref.eq (table.get (local.get $i)) (table.get (local.get $j)))
)
)
(invoke "init")
(assert_return (invoke "eq" (i32.const 0) (i32.const 0)) (i32.const 1))
(assert_return (invoke "eq" (i32.const 0) (i32.const 1)) (i32.const 1))
(assert_return (invoke "eq" (i32.const 0) (i32.const 2)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 0) (i32.const 3)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 0) (i32.const 4)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 0) (i32.const 5)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 0) (i32.const 6)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 0) (i32.const 7)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 0) (i32.const 8)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 1) (i32.const 0)) (i32.const 1))
(assert_return (invoke "eq" (i32.const 1) (i32.const 1)) (i32.const 1))
(assert_return (invoke "eq" (i32.const 1) (i32.const 2)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 1) (i32.const 3)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 1) (i32.const 4)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 1) (i32.const 5)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 1) (i32.const 6)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 1) (i32.const 7)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 1) (i32.const 8)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 2) (i32.const 0)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 2) (i32.const 1)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 2) (i32.const 2)) (i32.const 1))
(assert_return (invoke "eq" (i32.const 2) (i32.const 3)) (i32.const 1))
(assert_return (invoke "eq" (i32.const 2) (i32.const 4)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 2) (i32.const 5)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 2) (i32.const 6)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 2) (i32.const 7)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 2) (i32.const 8)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 3) (i32.const 0)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 3) (i32.const 1)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 3) (i32.const 2)) (i32.const 1))
(assert_return (invoke "eq" (i32.const 3) (i32.const 3)) (i32.const 1))
(assert_return (invoke "eq" (i32.const 3) (i32.const 4)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 3) (i32.const 5)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 3) (i32.const 6)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 3) (i32.const 7)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 3) (i32.const 8)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 4) (i32.const 0)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 4) (i32.const 1)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 4) (i32.const 2)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 4) (i32.const 3)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 4) (i32.const 4)) (i32.const 1))
(assert_return (invoke "eq" (i32.const 4) (i32.const 5)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 4) (i32.const 6)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 4) (i32.const 7)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 4) (i32.const 8)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 5) (i32.const 0)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 5) (i32.const 1)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 5) (i32.const 2)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 5) (i32.const 3)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 5) (i32.const 4)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 5) (i32.const 5)) (i32.const 1))
(assert_return (invoke "eq" (i32.const 5) (i32.const 6)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 5) (i32.const 7)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 5) (i32.const 8)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 6) (i32.const 0)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 6) (i32.const 1)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 6) (i32.const 2)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 6) (i32.const 3)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 6) (i32.const 4)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 6) (i32.const 5)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 6) (i32.const 6)) (i32.const 1))
(assert_return (invoke "eq" (i32.const 6) (i32.const 7)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 6) (i32.const 8)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 7) (i32.const 0)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 7) (i32.const 1)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 7) (i32.const 2)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 7) (i32.const 3)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 7) (i32.const 4)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 7) (i32.const 5)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 7) (i32.const 6)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 7) (i32.const 7)) (i32.const 1))
(assert_return (invoke "eq" (i32.const 7) (i32.const 8)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 8) (i32.const 0)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 8) (i32.const 1)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 8) (i32.const 2)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 8) (i32.const 3)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 8) (i32.const 4)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 8) (i32.const 5)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 8) (i32.const 6)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 8) (i32.const 7)) (i32.const 0))
(assert_return (invoke "eq" (i32.const 8) (i32.const 8)) (i32.const 1))
(assert_invalid
(module
(func (export "eq") (param $r (ref any)) (result i32)
(ref.eq (local.get $r) (local.get $r))
)
)
"type mismatch"
)
(assert_invalid
(module
(func (export "eq") (param $r (ref null any)) (result i32)
(ref.eq (local.get $r) (local.get $r))
)
)
"type mismatch"
)
(assert_invalid
(module
(func (export "eq") (param $r (ref func)) (result i32)
(ref.eq (local.get $r) (local.get $r))
)
)
"type mismatch"
)
(assert_invalid
(module
(func (export "eq") (param $r (ref null func)) (result i32)
(ref.eq (local.get $r) (local.get $r))
)
)
"type mismatch"
)
(assert_invalid
(module
(func (export "eq") (param $r (ref extern)) (result i32)
(ref.eq (local.get $r) (local.get $r))
)
)
"type mismatch"
)
(assert_invalid
(module
(func (export "eq") (param $r (ref null extern)) (result i32)
(ref.eq (local.get $r) (local.get $r))
)
)
"type mismatch"
)

View File

@ -0,0 +1,331 @@
;; Abstract Types
(module
(type $ft (func))
(type $st (struct))
(type $at (array i8))
(table $ta 10 anyref)
(table $tf 10 funcref)
(table $te 10 externref)
(elem declare func $f)
(func $f)
(func (export "init") (param $x externref)
(table.set $ta (i32.const 0) (ref.null any))
(table.set $ta (i32.const 1) (ref.null struct))
(table.set $ta (i32.const 2) (ref.null none))
(table.set $ta (i32.const 3) (ref.i31 (i32.const 7)))
(table.set $ta (i32.const 4) (struct.new_default $st))
(table.set $ta (i32.const 5) (array.new_default $at (i32.const 0)))
(table.set $ta (i32.const 6) (any.convert_extern (local.get $x)))
(table.set $ta (i32.const 7) (any.convert_extern (ref.null extern)))
(table.set $tf (i32.const 0) (ref.null nofunc))
(table.set $tf (i32.const 1) (ref.null func))
(table.set $tf (i32.const 2) (ref.func $f))
(table.set $te (i32.const 0) (ref.null noextern))
(table.set $te (i32.const 1) (ref.null extern))
(table.set $te (i32.const 2) (local.get $x))
(table.set $te (i32.const 3) (extern.convert_any (ref.i31 (i32.const 8))))
(table.set $te (i32.const 4) (extern.convert_any (struct.new_default $st)))
(table.set $te (i32.const 5) (extern.convert_any (ref.null any)))
)
(func (export "ref_test_null_data") (param $i i32) (result i32)
(i32.add
(ref.is_null (table.get $ta (local.get $i)))
(ref.test nullref (table.get $ta (local.get $i)))
)
)
(func (export "ref_test_any") (param $i i32) (result i32)
(i32.add
(ref.test (ref any) (table.get $ta (local.get $i)))
(ref.test anyref (table.get $ta (local.get $i)))
)
)
(func (export "ref_test_eq") (param $i i32) (result i32)
(i32.add
(ref.test (ref eq) (table.get $ta (local.get $i)))
(ref.test eqref (table.get $ta (local.get $i)))
)
)
(func (export "ref_test_i31") (param $i i32) (result i32)
(i32.add
(ref.test (ref i31) (table.get $ta (local.get $i)))
(ref.test i31ref (table.get $ta (local.get $i)))
)
)
(func (export "ref_test_struct") (param $i i32) (result i32)
(i32.add
(ref.test (ref struct) (table.get $ta (local.get $i)))
(ref.test structref (table.get $ta (local.get $i)))
)
)
(func (export "ref_test_array") (param $i i32) (result i32)
(i32.add
(ref.test (ref array) (table.get $ta (local.get $i)))
(ref.test arrayref (table.get $ta (local.get $i)))
)
)
(func (export "ref_test_null_func") (param $i i32) (result i32)
(i32.add
(ref.is_null (table.get $tf (local.get $i)))
(ref.test (ref null nofunc) (table.get $tf (local.get $i)))
)
)
(func (export "ref_test_func") (param $i i32) (result i32)
(i32.add
(ref.test (ref func) (table.get $tf (local.get $i)))
(ref.test funcref (table.get $tf (local.get $i)))
)
)
(func (export "ref_test_null_extern") (param $i i32) (result i32)
(i32.add
(ref.is_null (table.get $te (local.get $i)))
(ref.test (ref null noextern) (table.get $te (local.get $i)))
)
)
(func (export "ref_test_extern") (param $i i32) (result i32)
(i32.add
(ref.test (ref extern) (table.get $te (local.get $i)))
(ref.test externref (table.get $te (local.get $i)))
)
)
)
(invoke "init" (ref.extern 0))
(assert_return (invoke "ref_test_null_data" (i32.const 0)) (i32.const 2))
(assert_return (invoke "ref_test_null_data" (i32.const 1)) (i32.const 2))
(assert_return (invoke "ref_test_null_data" (i32.const 2)) (i32.const 2))
(assert_return (invoke "ref_test_null_data" (i32.const 3)) (i32.const 0))
(assert_return (invoke "ref_test_null_data" (i32.const 4)) (i32.const 0))
(assert_return (invoke "ref_test_null_data" (i32.const 5)) (i32.const 0))
(assert_return (invoke "ref_test_null_data" (i32.const 6)) (i32.const 0))
(assert_return (invoke "ref_test_null_data" (i32.const 7)) (i32.const 2))
(assert_return (invoke "ref_test_any" (i32.const 0)) (i32.const 1))
(assert_return (invoke "ref_test_any" (i32.const 1)) (i32.const 1))
(assert_return (invoke "ref_test_any" (i32.const 2)) (i32.const 1))
(assert_return (invoke "ref_test_any" (i32.const 3)) (i32.const 2))
(assert_return (invoke "ref_test_any" (i32.const 4)) (i32.const 2))
(assert_return (invoke "ref_test_any" (i32.const 5)) (i32.const 2))
(assert_return (invoke "ref_test_any" (i32.const 6)) (i32.const 2))
(assert_return (invoke "ref_test_any" (i32.const 7)) (i32.const 1))
(assert_return (invoke "ref_test_eq" (i32.const 0)) (i32.const 1))
(assert_return (invoke "ref_test_eq" (i32.const 1)) (i32.const 1))
(assert_return (invoke "ref_test_eq" (i32.const 2)) (i32.const 1))
(assert_return (invoke "ref_test_eq" (i32.const 3)) (i32.const 2))
(assert_return (invoke "ref_test_eq" (i32.const 4)) (i32.const 2))
(assert_return (invoke "ref_test_eq" (i32.const 5)) (i32.const 2))
(assert_return (invoke "ref_test_eq" (i32.const 6)) (i32.const 0))
(assert_return (invoke "ref_test_eq" (i32.const 7)) (i32.const 1))
(assert_return (invoke "ref_test_i31" (i32.const 0)) (i32.const 1))
(assert_return (invoke "ref_test_i31" (i32.const 1)) (i32.const 1))
(assert_return (invoke "ref_test_i31" (i32.const 2)) (i32.const 1))
(assert_return (invoke "ref_test_i31" (i32.const 3)) (i32.const 2))
(assert_return (invoke "ref_test_i31" (i32.const 4)) (i32.const 0))
(assert_return (invoke "ref_test_i31" (i32.const 5)) (i32.const 0))
(assert_return (invoke "ref_test_i31" (i32.const 6)) (i32.const 0))
(assert_return (invoke "ref_test_i31" (i32.const 7)) (i32.const 1))
(assert_return (invoke "ref_test_struct" (i32.const 0)) (i32.const 1))
(assert_return (invoke "ref_test_struct" (i32.const 1)) (i32.const 1))
(assert_return (invoke "ref_test_struct" (i32.const 2)) (i32.const 1))
(assert_return (invoke "ref_test_struct" (i32.const 3)) (i32.const 0))
(assert_return (invoke "ref_test_struct" (i32.const 4)) (i32.const 2))
(assert_return (invoke "ref_test_struct" (i32.const 5)) (i32.const 0))
(assert_return (invoke "ref_test_struct" (i32.const 6)) (i32.const 0))
(assert_return (invoke "ref_test_struct" (i32.const 7)) (i32.const 1))
(assert_return (invoke "ref_test_array" (i32.const 0)) (i32.const 1))
(assert_return (invoke "ref_test_array" (i32.const 1)) (i32.const 1))
(assert_return (invoke "ref_test_array" (i32.const 2)) (i32.const 1))
(assert_return (invoke "ref_test_array" (i32.const 3)) (i32.const 0))
(assert_return (invoke "ref_test_array" (i32.const 4)) (i32.const 0))
(assert_return (invoke "ref_test_array" (i32.const 5)) (i32.const 2))
(assert_return (invoke "ref_test_array" (i32.const 6)) (i32.const 0))
(assert_return (invoke "ref_test_array" (i32.const 7)) (i32.const 1))
(assert_return (invoke "ref_test_null_func" (i32.const 0)) (i32.const 2))
(assert_return (invoke "ref_test_null_func" (i32.const 1)) (i32.const 2))
(assert_return (invoke "ref_test_null_func" (i32.const 2)) (i32.const 0))
(assert_return (invoke "ref_test_func" (i32.const 0)) (i32.const 1))
(assert_return (invoke "ref_test_func" (i32.const 1)) (i32.const 1))
(assert_return (invoke "ref_test_func" (i32.const 2)) (i32.const 2))
(assert_return (invoke "ref_test_null_extern" (i32.const 0)) (i32.const 2))
(assert_return (invoke "ref_test_null_extern" (i32.const 1)) (i32.const 2))
(assert_return (invoke "ref_test_null_extern" (i32.const 2)) (i32.const 0))
(assert_return (invoke "ref_test_null_extern" (i32.const 3)) (i32.const 0))
(assert_return (invoke "ref_test_null_extern" (i32.const 4)) (i32.const 0))
(assert_return (invoke "ref_test_null_extern" (i32.const 5)) (i32.const 2))
(assert_return (invoke "ref_test_extern" (i32.const 0)) (i32.const 1))
(assert_return (invoke "ref_test_extern" (i32.const 1)) (i32.const 1))
(assert_return (invoke "ref_test_extern" (i32.const 2)) (i32.const 2))
(assert_return (invoke "ref_test_extern" (i32.const 3)) (i32.const 2))
(assert_return (invoke "ref_test_extern" (i32.const 4)) (i32.const 2))
(assert_return (invoke "ref_test_extern" (i32.const 5)) (i32.const 1))
;; Concrete Types
(module
(type $t0 (sub (struct)))
(type $t1 (sub $t0 (struct (field i32))))
(type $t1' (sub $t0 (struct (field i32))))
(type $t2 (sub $t1 (struct (field i32 i32))))
(type $t2' (sub $t1' (struct (field i32 i32))))
(type $t3 (sub $t0 (struct (field i32 i32))))
(type $t0' (sub $t0 (struct)))
(type $t4 (sub $t0' (struct (field i32 i32))))
(table 20 (ref null struct))
(func $init
(table.set (i32.const 0) (struct.new_default $t0))
(table.set (i32.const 10) (struct.new_default $t0))
(table.set (i32.const 1) (struct.new_default $t1))
(table.set (i32.const 11) (struct.new_default $t1'))
(table.set (i32.const 2) (struct.new_default $t2))
(table.set (i32.const 12) (struct.new_default $t2'))
(table.set (i32.const 3) (struct.new_default $t3))
(table.set (i32.const 4) (struct.new_default $t4))
)
(func (export "test-sub")
(call $init)
(block $l
;; must hold
(br_if $l (i32.eqz (ref.test (ref null $t0) (ref.null struct))))
(br_if $l (i32.eqz (ref.test (ref null $t0) (ref.null $t0))))
(br_if $l (i32.eqz (ref.test (ref null $t0) (ref.null $t1))))
(br_if $l (i32.eqz (ref.test (ref null $t0) (ref.null $t2))))
(br_if $l (i32.eqz (ref.test (ref null $t0) (ref.null $t3))))
(br_if $l (i32.eqz (ref.test (ref null $t0) (ref.null $t4))))
(br_if $l (i32.eqz (ref.test (ref null $t0) (table.get (i32.const 0)))))
(br_if $l (i32.eqz (ref.test (ref null $t0) (table.get (i32.const 1)))))
(br_if $l (i32.eqz (ref.test (ref null $t0) (table.get (i32.const 2)))))
(br_if $l (i32.eqz (ref.test (ref null $t0) (table.get (i32.const 3)))))
(br_if $l (i32.eqz (ref.test (ref null $t0) (table.get (i32.const 4)))))
(br_if $l (i32.eqz (ref.test (ref null $t1) (ref.null struct))))
(br_if $l (i32.eqz (ref.test (ref null $t1) (ref.null $t0))))
(br_if $l (i32.eqz (ref.test (ref null $t1) (ref.null $t1))))
(br_if $l (i32.eqz (ref.test (ref null $t1) (ref.null $t2))))
(br_if $l (i32.eqz (ref.test (ref null $t1) (ref.null $t3))))
(br_if $l (i32.eqz (ref.test (ref null $t1) (ref.null $t4))))
(br_if $l (i32.eqz (ref.test (ref null $t1) (table.get (i32.const 1)))))
(br_if $l (i32.eqz (ref.test (ref null $t1) (table.get (i32.const 2)))))
(br_if $l (i32.eqz (ref.test (ref null $t2) (ref.null struct))))
(br_if $l (i32.eqz (ref.test (ref null $t2) (ref.null $t0))))
(br_if $l (i32.eqz (ref.test (ref null $t2) (ref.null $t1))))
(br_if $l (i32.eqz (ref.test (ref null $t2) (ref.null $t2))))
(br_if $l (i32.eqz (ref.test (ref null $t2) (ref.null $t3))))
(br_if $l (i32.eqz (ref.test (ref null $t2) (ref.null $t4))))
(br_if $l (i32.eqz (ref.test (ref null $t2) (table.get (i32.const 2)))))
(br_if $l (i32.eqz (ref.test (ref null $t3) (ref.null struct))))
(br_if $l (i32.eqz (ref.test (ref null $t3) (ref.null $t0))))
(br_if $l (i32.eqz (ref.test (ref null $t3) (ref.null $t1))))
(br_if $l (i32.eqz (ref.test (ref null $t3) (ref.null $t2))))
(br_if $l (i32.eqz (ref.test (ref null $t3) (ref.null $t3))))
(br_if $l (i32.eqz (ref.test (ref null $t3) (ref.null $t4))))
(br_if $l (i32.eqz (ref.test (ref null $t3) (table.get (i32.const 3)))))
(br_if $l (i32.eqz (ref.test (ref null $t4) (ref.null struct))))
(br_if $l (i32.eqz (ref.test (ref null $t4) (ref.null $t0))))
(br_if $l (i32.eqz (ref.test (ref null $t4) (ref.null $t1))))
(br_if $l (i32.eqz (ref.test (ref null $t4) (ref.null $t2))))
(br_if $l (i32.eqz (ref.test (ref null $t4) (ref.null $t3))))
(br_if $l (i32.eqz (ref.test (ref null $t4) (ref.null $t4))))
(br_if $l (i32.eqz (ref.test (ref null $t4) (table.get (i32.const 4)))))
(br_if $l (i32.eqz (ref.test (ref $t0) (table.get (i32.const 0)))))
(br_if $l (i32.eqz (ref.test (ref $t0) (table.get (i32.const 1)))))
(br_if $l (i32.eqz (ref.test (ref $t0) (table.get (i32.const 2)))))
(br_if $l (i32.eqz (ref.test (ref $t0) (table.get (i32.const 3)))))
(br_if $l (i32.eqz (ref.test (ref $t0) (table.get (i32.const 4)))))
(br_if $l (i32.eqz (ref.test (ref $t1) (table.get (i32.const 1)))))
(br_if $l (i32.eqz (ref.test (ref $t1) (table.get (i32.const 2)))))
(br_if $l (i32.eqz (ref.test (ref $t2) (table.get (i32.const 2)))))
(br_if $l (i32.eqz (ref.test (ref $t3) (table.get (i32.const 3)))))
(br_if $l (i32.eqz (ref.test (ref $t4) (table.get (i32.const 4)))))
;; must not hold
(br_if $l (ref.test (ref $t0) (ref.null struct)))
(br_if $l (ref.test (ref $t1) (ref.null struct)))
(br_if $l (ref.test (ref $t2) (ref.null struct)))
(br_if $l (ref.test (ref $t3) (ref.null struct)))
(br_if $l (ref.test (ref $t4) (ref.null struct)))
(br_if $l (ref.test (ref $t1) (table.get (i32.const 0))))
(br_if $l (ref.test (ref $t1) (table.get (i32.const 3))))
(br_if $l (ref.test (ref $t1) (table.get (i32.const 4))))
(br_if $l (ref.test (ref $t2) (table.get (i32.const 0))))
(br_if $l (ref.test (ref $t2) (table.get (i32.const 1))))
(br_if $l (ref.test (ref $t2) (table.get (i32.const 3))))
(br_if $l (ref.test (ref $t2) (table.get (i32.const 4))))
(br_if $l (ref.test (ref $t3) (table.get (i32.const 0))))
(br_if $l (ref.test (ref $t3) (table.get (i32.const 1))))
(br_if $l (ref.test (ref $t3) (table.get (i32.const 2))))
(br_if $l (ref.test (ref $t3) (table.get (i32.const 4))))
(br_if $l (ref.test (ref $t4) (table.get (i32.const 0))))
(br_if $l (ref.test (ref $t4) (table.get (i32.const 1))))
(br_if $l (ref.test (ref $t4) (table.get (i32.const 2))))
(br_if $l (ref.test (ref $t4) (table.get (i32.const 3))))
(return)
)
(unreachable)
)
(func (export "test-canon")
(call $init)
(block $l
(br_if $l (i32.eqz (ref.test (ref $t0) (table.get (i32.const 0)))))
(br_if $l (i32.eqz (ref.test (ref $t0) (table.get (i32.const 1)))))
(br_if $l (i32.eqz (ref.test (ref $t0) (table.get (i32.const 2)))))
(br_if $l (i32.eqz (ref.test (ref $t0) (table.get (i32.const 3)))))
(br_if $l (i32.eqz (ref.test (ref $t0) (table.get (i32.const 4)))))
(br_if $l (i32.eqz (ref.test (ref $t0) (table.get (i32.const 10)))))
(br_if $l (i32.eqz (ref.test (ref $t0) (table.get (i32.const 11)))))
(br_if $l (i32.eqz (ref.test (ref $t0) (table.get (i32.const 12)))))
;; Must have explicit sub relationship
;; (br_if $l (i32.eqz (ref.test (ref $t1') (table.get (i32.const 1)))))
;; (br_if $l (i32.eqz (ref.test (ref $t1') (table.get (i32.const 2)))))
;; (br_if $l (i32.eqz (ref.test (ref $t1) (table.get (i32.const 11)))))
;; (br_if $l (i32.eqz (ref.test (ref $t1) (table.get (i32.const 12)))))
;; (br_if $l (i32.eqz (ref.test (ref $t2') (table.get (i32.const 2)))))
;; (br_if $l (i32.eqz (ref.test (ref $t2) (table.get (i32.const 12)))))
(return)
)
(unreachable)
)
)
(assert_return (invoke "test-sub"))
(assert_return (invoke "test-canon"))

View File

@ -0,0 +1,376 @@
;; 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")
(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 1200)) (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 1200)) (i64.const 44))
(assert_return (invoke "even" (i64.const 1201)) (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 1200)) (i64.const 99))
(assert_return (invoke "odd" (i64.const 1119)) (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)
(unreachable)
(return_call_ref $t)
)
)
(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)
(ref.func $f)
(return_call_ref $t)
)
)
(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)
(i32.const 0)
(ref.func $f)
(return_call_ref $t)
(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"
)

View File

@ -0,0 +1,592 @@
(module
;; Auxiliary
(func $dummy)
(table $tab funcref (elem $dummy))
(memory 1)
(func (export "select-i32") (param i32 i32 i32) (result i32)
(select (local.get 0) (local.get 1) (local.get 2))
)
(func (export "select-i64") (param i64 i64 i32) (result i64)
(select (local.get 0) (local.get 1) (local.get 2))
)
(func (export "select-f32") (param f32 f32 i32) (result f32)
(select (local.get 0) (local.get 1) (local.get 2))
)
(func (export "select-f64") (param f64 f64 i32) (result f64)
(select (local.get 0) (local.get 1) (local.get 2))
)
(func (export "select-i32-t") (param i32 i32 i32) (result i32)
(select (result i32) (local.get 0) (local.get 1) (local.get 2))
)
(func (export "select-i64-t") (param i64 i64 i32) (result i64)
(select (result i64) (local.get 0) (local.get 1) (local.get 2))
)
(func (export "select-f32-t") (param f32 f32 i32) (result f32)
(select (result f32) (local.get 0) (local.get 1) (local.get 2))
)
(func (export "select-f64-t") (param f64 f64 i32) (result f64)
(select (result f64) (local.get 0) (local.get 1) (local.get 2))
)
(func (export "select-funcref") (param funcref funcref i32) (result funcref)
(select (result funcref) (local.get 0) (local.get 1) (local.get 2))
)
(func (export "select-externref") (param externref externref i32) (result externref)
(select (result externref) (local.get 0) (local.get 1) (local.get 2))
)
(type $t (func))
(func $tf) (elem declare func $tf)
(func (export "join-funcnull") (param i32) (result (ref null func))
(select (result (ref null func))
(ref.func $tf)
(ref.null func)
(local.get 0)
)
)
;; Check that both sides of the select are evaluated
(func (export "select-trap-left") (param $cond i32) (result i32)
(select (unreachable) (i32.const 0) (local.get $cond))
)
(func (export "select-trap-right") (param $cond i32) (result i32)
(select (i32.const 0) (unreachable) (local.get $cond))
)
(func (export "select-unreached")
(unreachable) (select)
(unreachable) (i32.const 0) (select)
(unreachable) (i32.const 0) (i32.const 0) (select)
(unreachable) (i32.const 0) (i32.const 0) (i32.const 0) (select)
(unreachable) (f32.const 0) (i32.const 0) (select)
(unreachable)
)
(func (export "select_unreached_result_1") (result i32)
(unreachable) (i32.add (select))
)
(func (export "select_unreached_result_2") (result i64)
(unreachable) (i64.add (select (i64.const 0) (i32.const 0)))
)
;; As the argument of control constructs and instructions
(func (export "as-select-first") (param i32) (result i32)
(select (select (i32.const 0) (i32.const 1) (local.get 0)) (i32.const 2) (i32.const 3))
)
(func (export "as-select-mid") (param i32) (result i32)
(select (i32.const 2) (select (i32.const 0) (i32.const 1) (local.get 0)) (i32.const 3))
)
(func (export "as-select-last") (param i32) (result i32)
(select (i32.const 2) (i32.const 3) (select (i32.const 0) (i32.const 1) (local.get 0)))
)
(func (export "as-loop-first") (param i32) (result i32)
(loop (result i32) (select (i32.const 2) (i32.const 3) (local.get 0)) (call $dummy) (call $dummy))
)
(func (export "as-loop-mid") (param i32) (result i32)
(loop (result i32) (call $dummy) (select (i32.const 2) (i32.const 3) (local.get 0)) (call $dummy))
)
(func (export "as-loop-last") (param i32) (result i32)
(loop (result i32) (call $dummy) (call $dummy) (select (i32.const 2) (i32.const 3) (local.get 0)))
)
(func (export "as-if-condition") (param i32)
(select (i32.const 2) (i32.const 3) (local.get 0)) (if (then (call $dummy)))
)
(func (export "as-if-then") (param i32) (result i32)
(if (result i32) (i32.const 1) (then (select (i32.const 2) (i32.const 3) (local.get 0))) (else (i32.const 4)))
)
(func (export "as-if-else") (param i32) (result i32)
(if (result i32) (i32.const 0) (then (i32.const 2)) (else (select (i32.const 2) (i32.const 3) (local.get 0))))
)
(func (export "as-br_if-first") (param i32) (result i32)
(block (result i32) (br_if 0 (select (i32.const 2) (i32.const 3) (local.get 0)) (i32.const 4)))
)
(func (export "as-br_if-last") (param i32) (result i32)
(block (result i32) (br_if 0 (i32.const 2) (select (i32.const 2) (i32.const 3) (local.get 0))))
)
(func (export "as-br_table-first") (param i32) (result i32)
(block (result i32) (select (i32.const 2) (i32.const 3) (local.get 0)) (i32.const 2) (br_table 0 0))
)
(func (export "as-br_table-last") (param i32) (result i32)
(block (result i32) (i32.const 2) (select (i32.const 2) (i32.const 3) (local.get 0)) (br_table 0 0))
)
(func $func (param i32 i32) (result i32) (local.get 0))
(type $check (func (param i32 i32) (result i32)))
(table $t funcref (elem $func))
(func (export "as-call_indirect-first") (param i32) (result i32)
(block (result i32)
(call_indirect $t (type $check)
(select (i32.const 2) (i32.const 3) (local.get 0)) (i32.const 1) (i32.const 0)
)
)
)
(func (export "as-call_indirect-mid") (param i32) (result i32)
(block (result i32)
(call_indirect $t (type $check)
(i32.const 1) (select (i32.const 2) (i32.const 3) (local.get 0)) (i32.const 0)
)
)
)
(func (export "as-call_indirect-last") (param i32) (result i32)
(block (result i32)
(call_indirect $t (type $check)
(i32.const 1) (i32.const 4) (select (i32.const 2) (i32.const 3) (local.get 0))
)
)
)
(func (export "as-store-first") (param i32)
(select (i32.const 0) (i32.const 4) (local.get 0)) (i32.const 1) (i32.store)
)
(func (export "as-store-last") (param i32)
(i32.const 8) (select (i32.const 1) (i32.const 2) (local.get 0)) (i32.store)
)
(func (export "as-memory.grow-value") (param i32) (result i32)
(memory.grow (select (i32.const 1) (i32.const 2) (local.get 0)))
)
(func $f (param i32) (result i32) (local.get 0))
(func (export "as-call-value") (param i32) (result i32)
(call $f (select (i32.const 1) (i32.const 2) (local.get 0)))
)
(func (export "as-return-value") (param i32) (result i32)
(select (i32.const 1) (i32.const 2) (local.get 0)) (return)
)
(func (export "as-drop-operand") (param i32)
(drop (select (i32.const 1) (i32.const 2) (local.get 0)))
)
(func (export "as-br-value") (param i32) (result i32)
(block (result i32) (br 0 (select (i32.const 1) (i32.const 2) (local.get 0))))
)
(func (export "as-local.set-value") (param i32) (result i32)
(local i32) (local.set 0 (select (i32.const 1) (i32.const 2) (local.get 0))) (local.get 0)
)
(func (export "as-local.tee-value") (param i32) (result i32)
(local.tee 0 (select (i32.const 1) (i32.const 2) (local.get 0)))
)
(global $a (mut i32) (i32.const 10))
(func (export "as-global.set-value") (param i32) (result i32)
(global.set $a (select (i32.const 1) (i32.const 2) (local.get 0)))
(global.get $a)
)
(func (export "as-load-operand") (param i32) (result i32)
(i32.load (select (i32.const 0) (i32.const 4) (local.get 0)))
)
(func (export "as-unary-operand") (param i32) (result i32)
(i32.eqz (select (i32.const 0) (i32.const 1) (local.get 0)))
)
(func (export "as-binary-operand") (param i32) (result i32)
(i32.mul
(select (i32.const 1) (i32.const 2) (local.get 0))
(select (i32.const 1) (i32.const 2) (local.get 0))
)
)
(func (export "as-test-operand") (param i32) (result i32)
(block (result i32)
(i32.eqz (select (i32.const 0) (i32.const 1) (local.get 0)))
)
)
(func (export "as-compare-left") (param i32) (result i32)
(block (result i32)
(i32.le_s (select (i32.const 1) (i32.const 2) (local.get 0)) (i32.const 1))
)
)
(func (export "as-compare-right") (param i32) (result i32)
(block (result i32)
(i32.ne (i32.const 1) (select (i32.const 0) (i32.const 1) (local.get 0)))
)
)
(func (export "as-convert-operand") (param i32) (result i32)
(block (result i32)
(i32.wrap_i64 (select (i64.const 1) (i64.const 0) (local.get 0)))
)
)
)
(assert_return (invoke "select-i32" (i32.const 1) (i32.const 2) (i32.const 1)) (i32.const 1))
(assert_return (invoke "select-i64" (i64.const 2) (i64.const 1) (i32.const 1)) (i64.const 2))
(assert_return (invoke "select-f32" (f32.const 1) (f32.const 2) (i32.const 1)) (f32.const 1))
(assert_return (invoke "select-f64" (f64.const 1) (f64.const 2) (i32.const 1)) (f64.const 1))
(assert_return (invoke "select-i32" (i32.const 1) (i32.const 2) (i32.const 0)) (i32.const 2))
(assert_return (invoke "select-i32" (i32.const 2) (i32.const 1) (i32.const 0)) (i32.const 1))
(assert_return (invoke "select-i64" (i64.const 2) (i64.const 1) (i32.const -1)) (i64.const 2))
(assert_return (invoke "select-i64" (i64.const 2) (i64.const 1) (i32.const 0xf0f0f0f0)) (i64.const 2))
(assert_return (invoke "select-f32" (f32.const nan) (f32.const 1) (i32.const 1)) (f32.const nan))
(assert_return (invoke "select-f32" (f32.const nan:0x20304) (f32.const 1) (i32.const 1)) (f32.const nan:0x20304))
(assert_return (invoke "select-f32" (f32.const nan) (f32.const 1) (i32.const 0)) (f32.const 1))
(assert_return (invoke "select-f32" (f32.const nan:0x20304) (f32.const 1) (i32.const 0)) (f32.const 1))
(assert_return (invoke "select-f32" (f32.const 2) (f32.const nan) (i32.const 1)) (f32.const 2))
(assert_return (invoke "select-f32" (f32.const 2) (f32.const nan:0x20304) (i32.const 1)) (f32.const 2))
(assert_return (invoke "select-f32" (f32.const 2) (f32.const nan) (i32.const 0)) (f32.const nan))
(assert_return (invoke "select-f32" (f32.const 2) (f32.const nan:0x20304) (i32.const 0)) (f32.const nan:0x20304))
(assert_return (invoke "select-f64" (f64.const nan) (f64.const 1) (i32.const 1)) (f64.const nan))
(assert_return (invoke "select-f64" (f64.const nan:0x20304) (f64.const 1) (i32.const 1)) (f64.const nan:0x20304))
(assert_return (invoke "select-f64" (f64.const nan) (f64.const 1) (i32.const 0)) (f64.const 1))
(assert_return (invoke "select-f64" (f64.const nan:0x20304) (f64.const 1) (i32.const 0)) (f64.const 1))
(assert_return (invoke "select-f64" (f64.const 2) (f64.const nan) (i32.const 1)) (f64.const 2))
(assert_return (invoke "select-f64" (f64.const 2) (f64.const nan:0x20304) (i32.const 1)) (f64.const 2))
(assert_return (invoke "select-f64" (f64.const 2) (f64.const nan) (i32.const 0)) (f64.const nan))
(assert_return (invoke "select-f64" (f64.const 2) (f64.const nan:0x20304) (i32.const 0)) (f64.const nan:0x20304))
(assert_return (invoke "select-i32-t" (i32.const 1) (i32.const 2) (i32.const 1)) (i32.const 1))
(assert_return (invoke "select-i64-t" (i64.const 2) (i64.const 1) (i32.const 1)) (i64.const 2))
(assert_return (invoke "select-f32-t" (f32.const 1) (f32.const 2) (i32.const 1)) (f32.const 1))
(assert_return (invoke "select-f64-t" (f64.const 1) (f64.const 2) (i32.const 1)) (f64.const 1))
(assert_return (invoke "select-funcref" (ref.null func) (ref.null func) (i32.const 1)) (ref.null func))
(assert_return (invoke "select-externref" (ref.extern 1) (ref.extern 2) (i32.const 1)) (ref.extern 1))
(assert_return (invoke "select-i32-t" (i32.const 1) (i32.const 2) (i32.const 0)) (i32.const 2))
(assert_return (invoke "select-i32-t" (i32.const 2) (i32.const 1) (i32.const 0)) (i32.const 1))
(assert_return (invoke "select-i64-t" (i64.const 2) (i64.const 1) (i32.const -1)) (i64.const 2))
(assert_return (invoke "select-i64-t" (i64.const 2) (i64.const 1) (i32.const 0xf0f0f0f0)) (i64.const 2))
(assert_return (invoke "select-externref" (ref.extern 1) (ref.extern 2) (i32.const 0)) (ref.extern 2))
(assert_return (invoke "select-externref" (ref.extern 2) (ref.extern 1) (i32.const 0)) (ref.extern 1))
(assert_return (invoke "select-f32-t" (f32.const nan) (f32.const 1) (i32.const 1)) (f32.const nan))
(assert_return (invoke "select-f32-t" (f32.const nan:0x20304) (f32.const 1) (i32.const 1)) (f32.const nan:0x20304))
(assert_return (invoke "select-f32-t" (f32.const nan) (f32.const 1) (i32.const 0)) (f32.const 1))
(assert_return (invoke "select-f32-t" (f32.const nan:0x20304) (f32.const 1) (i32.const 0)) (f32.const 1))
(assert_return (invoke "select-f32-t" (f32.const 2) (f32.const nan) (i32.const 1)) (f32.const 2))
(assert_return (invoke "select-f32-t" (f32.const 2) (f32.const nan:0x20304) (i32.const 1)) (f32.const 2))
(assert_return (invoke "select-f32-t" (f32.const 2) (f32.const nan) (i32.const 0)) (f32.const nan))
(assert_return (invoke "select-f32-t" (f32.const 2) (f32.const nan:0x20304) (i32.const 0)) (f32.const nan:0x20304))
(assert_return (invoke "select-f64-t" (f64.const nan) (f64.const 1) (i32.const 1)) (f64.const nan))
(assert_return (invoke "select-f64-t" (f64.const nan:0x20304) (f64.const 1) (i32.const 1)) (f64.const nan:0x20304))
(assert_return (invoke "select-f64-t" (f64.const nan) (f64.const 1) (i32.const 0)) (f64.const 1))
(assert_return (invoke "select-f64-t" (f64.const nan:0x20304) (f64.const 1) (i32.const 0)) (f64.const 1))
(assert_return (invoke "select-f64-t" (f64.const 2) (f64.const nan) (i32.const 1)) (f64.const 2))
(assert_return (invoke "select-f64-t" (f64.const 2) (f64.const nan:0x20304) (i32.const 1)) (f64.const 2))
(assert_return (invoke "select-f64-t" (f64.const 2) (f64.const nan) (i32.const 0)) (f64.const nan))
(assert_return (invoke "select-f64-t" (f64.const 2) (f64.const nan:0x20304) (i32.const 0)) (f64.const nan:0x20304))
(assert_return (invoke "join-funcnull" (i32.const 1)) (ref.func))
(assert_return (invoke "join-funcnull" (i32.const 0)) (ref.null func)) ;; we require type in expected results
(assert_trap (invoke "select-trap-left" (i32.const 1)) "unreachable")
(assert_trap (invoke "select-trap-left" (i32.const 0)) "unreachable")
(assert_trap (invoke "select-trap-right" (i32.const 1)) "unreachable")
(assert_trap (invoke "select-trap-right" (i32.const 0)) "unreachable")
(assert_return (invoke "as-select-first" (i32.const 0)) (i32.const 1))
(assert_return (invoke "as-select-first" (i32.const 1)) (i32.const 0))
(assert_return (invoke "as-select-mid" (i32.const 0)) (i32.const 2))
(assert_return (invoke "as-select-mid" (i32.const 1)) (i32.const 2))
(assert_return (invoke "as-select-last" (i32.const 0)) (i32.const 2))
(assert_return (invoke "as-select-last" (i32.const 1)) (i32.const 3))
(assert_return (invoke "as-loop-first" (i32.const 0)) (i32.const 3))
(assert_return (invoke "as-loop-first" (i32.const 1)) (i32.const 2))
(assert_return (invoke "as-loop-mid" (i32.const 0)) (i32.const 3))
(assert_return (invoke "as-loop-mid" (i32.const 1)) (i32.const 2))
(assert_return (invoke "as-loop-last" (i32.const 0)) (i32.const 3))
(assert_return (invoke "as-loop-last" (i32.const 1)) (i32.const 2))
(assert_return (invoke "as-if-condition" (i32.const 0)))
(assert_return (invoke "as-if-condition" (i32.const 1)))
(assert_return (invoke "as-if-then" (i32.const 0)) (i32.const 3))
(assert_return (invoke "as-if-then" (i32.const 1)) (i32.const 2))
(assert_return (invoke "as-if-else" (i32.const 0)) (i32.const 3))
(assert_return (invoke "as-if-else" (i32.const 1)) (i32.const 2))
(assert_return (invoke "as-br_if-first" (i32.const 0)) (i32.const 3))
(assert_return (invoke "as-br_if-first" (i32.const 1)) (i32.const 2))
(assert_return (invoke "as-br_if-last" (i32.const 0)) (i32.const 2))
(assert_return (invoke "as-br_if-last" (i32.const 1)) (i32.const 2))
(assert_return (invoke "as-br_table-first" (i32.const 0)) (i32.const 3))
(assert_return (invoke "as-br_table-first" (i32.const 1)) (i32.const 2))
(assert_return (invoke "as-br_table-last" (i32.const 0)) (i32.const 2))
(assert_return (invoke "as-br_table-last" (i32.const 1)) (i32.const 2))
(assert_return (invoke "as-call_indirect-first" (i32.const 0)) (i32.const 3))
(assert_return (invoke "as-call_indirect-first" (i32.const 1)) (i32.const 2))
(assert_return (invoke "as-call_indirect-mid" (i32.const 0)) (i32.const 1))
(assert_return (invoke "as-call_indirect-mid" (i32.const 1)) (i32.const 1))
(assert_trap (invoke "as-call_indirect-last" (i32.const 0)) "undefined element")
(assert_trap (invoke "as-call_indirect-last" (i32.const 1)) "undefined element")
(assert_return (invoke "as-store-first" (i32.const 0)))
(assert_return (invoke "as-store-first" (i32.const 1)))
(assert_return (invoke "as-store-last" (i32.const 0)))
(assert_return (invoke "as-store-last" (i32.const 1)))
(assert_return (invoke "as-memory.grow-value" (i32.const 0)) (i32.const 1))
(assert_return (invoke "as-memory.grow-value" (i32.const 1)) (i32.const 3))
(assert_return (invoke "as-call-value" (i32.const 0)) (i32.const 2))
(assert_return (invoke "as-call-value" (i32.const 1)) (i32.const 1))
(assert_return (invoke "as-return-value" (i32.const 0)) (i32.const 2))
(assert_return (invoke "as-return-value" (i32.const 1)) (i32.const 1))
(assert_return (invoke "as-drop-operand" (i32.const 0)))
(assert_return (invoke "as-drop-operand" (i32.const 1)))
(assert_return (invoke "as-br-value" (i32.const 0)) (i32.const 2))
(assert_return (invoke "as-br-value" (i32.const 1)) (i32.const 1))
(assert_return (invoke "as-local.set-value" (i32.const 0)) (i32.const 2))
(assert_return (invoke "as-local.set-value" (i32.const 1)) (i32.const 1))
(assert_return (invoke "as-local.tee-value" (i32.const 0)) (i32.const 2))
(assert_return (invoke "as-local.tee-value" (i32.const 1)) (i32.const 1))
(assert_return (invoke "as-global.set-value" (i32.const 0)) (i32.const 2))
(assert_return (invoke "as-global.set-value" (i32.const 1)) (i32.const 1))
(assert_return (invoke "as-load-operand" (i32.const 0)) (i32.const 1))
(assert_return (invoke "as-load-operand" (i32.const 1)) (i32.const 1))
(assert_return (invoke "as-unary-operand" (i32.const 0)) (i32.const 0))
(assert_return (invoke "as-unary-operand" (i32.const 1)) (i32.const 1))
(assert_return (invoke "as-binary-operand" (i32.const 0)) (i32.const 4))
(assert_return (invoke "as-binary-operand" (i32.const 1)) (i32.const 1))
(assert_return (invoke "as-test-operand" (i32.const 0)) (i32.const 0))
(assert_return (invoke "as-test-operand" (i32.const 1)) (i32.const 1))
(assert_return (invoke "as-compare-left" (i32.const 0)) (i32.const 0))
(assert_return (invoke "as-compare-left" (i32.const 1)) (i32.const 1))
(assert_return (invoke "as-compare-right" (i32.const 0)) (i32.const 0))
(assert_return (invoke "as-compare-right" (i32.const 1)) (i32.const 1))
(assert_return (invoke "as-convert-operand" (i32.const 0)) (i32.const 0))
(assert_return (invoke "as-convert-operand" (i32.const 1)) (i32.const 1))
(assert_invalid
(module (func $arity-0-implicit (select (nop) (nop) (i32.const 1))))
"type mismatch"
)
(assert_invalid
(module (func $arity-0 (select (result) (nop) (nop) (i32.const 1))))
"invalid result arity"
)
(assert_invalid
(module (func $arity-2 (result i32 i32)
(select (result i32 i32)
(i32.const 0) (i32.const 0)
(i32.const 0) (i32.const 0)
(i32.const 1)
)
))
"invalid result arity"
)
(assert_invalid
(module (type $t (func))
(func $type-ref-implicit (param $r (ref $t))
(drop (select (local.get $r) (local.get $r) (i32.const 1)))
)
)
"type mismatch"
)
(assert_invalid
(module (func $type-funcref-implicit (param $r funcref)
(drop (select (local.get $r) (local.get $r) (i32.const 1)))
))
"type mismatch"
)
(assert_invalid
(module (func $type-externref-implicit (param $r externref)
(drop (select (local.get $r) (local.get $r) (i32.const 1)))
))
"type mismatch"
)
(module (func $type-unreachable-ref-implicit
(drop (ref.is_null (select (unreachable) (i32.const 1))))
))
(assert_invalid
(module (func $type-num-vs-num
(drop (select (i32.const 1) (i64.const 1) (i32.const 1)))
))
"type mismatch"
)
(assert_invalid
(module (func $type-num-vs-num
(drop (select (i32.const 1) (f32.const 1.0) (i32.const 1)))
))
"type mismatch"
)
(assert_invalid
(module (func $type-num-vs-num
(drop (select (i32.const 1) (f64.const 1.0) (i32.const 1)))
))
"type mismatch"
)
(assert_invalid
(module (func $type-num-vs-num (select (i32.const 1) (i64.const 1) (i32.const 1)) (drop)))
"type mismatch"
)
(assert_invalid
(module (func $type-num-vs-num (select (i32.const 1) (f32.const 1.0) (i32.const 1)) (drop)))
"type mismatch"
)
(assert_invalid
(module (func $type-num-vs-num (select (i32.const 1) (i64.const 1) (i32.const 1)) (drop)))
"type mismatch"
)
(assert_invalid
(module (func $type-num-vs-num (select (i32.const 1) (f32.const 1.0) (i32.const 1)) (drop)))
"type mismatch"
)
(assert_invalid
(module (func $type-num-vs-num (select (i32.const 1) (f64.const 1.0) (i32.const 1)) (drop)))
"type mismatch"
)
(assert_invalid
(module
(func $type-1st-operand-empty
(select) (drop)
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-2nd-operand-empty
(i32.const 0) (select) (drop)
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-3rd-operand-empty
(i32.const 0) (i32.const 0) (select) (drop)
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-1st-operand-empty-in-block
(i32.const 0) (i32.const 0) (i32.const 0)
(block (select) (drop))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-2nd-operand-empty-in-block
(i32.const 0) (i32.const 0)
(block (i32.const 0) (select) (drop))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-3rd-operand-empty-in-block
(i32.const 0)
(block (i32.const 0) (i32.const 0) (select) (drop))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-1st-operand-empty-in-loop
(i32.const 0) (i32.const 0) (i32.const 0)
(loop (select) (drop))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-2nd-operand-empty-in-loop
(i32.const 0) (i32.const 0)
(loop (i32.const 0) (select) (drop))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-3rd-operand-empty-in-loop
(i32.const 0)
(loop (i32.const 0) (i32.const 0) (select) (drop))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-1st-operand-empty-in-then
(i32.const 0) (i32.const 0) (i32.const 0)
(if (then (select) (drop)))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-2nd-operand-empty-in-then
(i32.const 0) (i32.const 0)
(if (then (i32.const 0) (select) (drop)))
)
)
"type mismatch"
)
(assert_invalid
(module
(func $type-3rd-operand-empty-in-then
(i32.const 0)
(if (then (i32.const 0) (i32.const 0) (select) (drop)))
)
)
"type mismatch"
)
;; Third operand must be i32
(assert_invalid
(module (func (select (i32.const 1) (i32.const 1) (i64.const 1)) (drop)))
"type mismatch"
)
(assert_invalid
(module (func (select (i32.const 1) (i32.const 1) (f32.const 1)) (drop)))
"type mismatch"
)
(assert_invalid
(module (func (select (i32.const 1) (i32.const 1) (f64.const 1)) (drop)))
"type mismatch"
)
;; Result of select has type of first two operands
(assert_invalid
(module (func (result i32) (select (i64.const 1) (i64.const 1) (i32.const 1))))
"type mismatch"
)
;; Flat syntax
(module
(table 1 funcref)
(func (result i32) unreachable select)
(func (result i32) unreachable select nop)
(func (result i32) unreachable select (select))
(func (result i32) unreachable select select)
(func (result i32) unreachable select select select)
(func (result i32) unreachable select (result i32))
(func (result i32) unreachable select (result i32) (result))
(func (result i32) unreachable select (result i32) (result) select)
(func (result i32) unreachable select (result) (result i32) select (result i32))
(func (result i32) unreachable select call_indirect)
(func (result i32) unreachable select call_indirect select)
)

View File

@ -0,0 +1,229 @@
;; Type syntax
(module
(type (struct))
(type (struct (field)))
(type (struct (field i8)))
(type (struct (field i8 i8 i8 i8)))
(type (struct (field $x1 i32) (field $y1 i32)))
(type (struct (field i8 i16 i32 i64 f32 f64 anyref funcref (ref 0) (ref null 1))))
(type (struct (field i32 i64 i8) (field) (field) (field (ref null i31) anyref)))
(type (struct (field $x2 i32) (field f32 f64) (field $y2 i32)))
)
(assert_malformed
(module quote
"(type (struct (field $x i32) (field $x i32)))"
)
"duplicate field"
)
;; Binding structure
(module
(rec
(type $s0 (struct (field (ref 0) (ref 1) (ref $s0) (ref $s1))))
(type $s1 (struct (field (ref 0) (ref 1) (ref $s0) (ref $s1))))
)
(func (param (ref $forward)))
(type $forward (struct))
)
(assert_invalid
(module (type (struct (field (ref 1)))))
"unknown type"
)
(assert_invalid
(module (type (struct (field (mut (ref 1))))))
"unknown type"
)
;; Field names
(module
(type (struct (field $x i32)))
(type $t1 (struct (field i32) (field $x f32)))
(type $t2 (struct (field i32 i32) (field $x i64)))
(func (param (ref 0)) (result i32) (struct.get 0 $x (local.get 0)))
(func (param (ref $t1)) (result f32) (struct.get 1 $x (local.get 0)))
(func (param (ref $t2)) (result i64) (struct.get $t2 $x (local.get 0)))
)
(assert_invalid
(module
(type (struct (field $x i64)))
(type $t (struct (field $x i32)))
(func (param (ref 0)) (result i32) (struct.get 0 $x (local.get 0)))
)
"type mismatch"
)
;; Basic instructions
(module
(type $vec (struct (field f32) (field $y (mut f32)) (field $z f32)))
(global (ref $vec) (struct.new $vec (f32.const 1) (f32.const 2) (f32.const 3)))
(global (ref $vec) (struct.new_default $vec))
(func (export "new") (result anyref)
(struct.new_default $vec)
)
(func $get_0_0 (param $v (ref $vec)) (result f32)
(struct.get 0 0 (local.get $v))
)
(func (export "get_0_0") (result f32)
(call $get_0_0 (struct.new_default $vec))
)
(func $get_vec_0 (param $v (ref $vec)) (result f32)
(struct.get $vec 0 (local.get $v))
)
(func (export "get_vec_0") (result f32)
(call $get_vec_0 (struct.new_default $vec))
)
(func $get_0_y (param $v (ref $vec)) (result f32)
(struct.get 0 $y (local.get $v))
)
(func (export "get_0_y") (result f32)
(call $get_0_y (struct.new_default $vec))
)
(func $get_vec_y (param $v (ref $vec)) (result f32)
(struct.get $vec $y (local.get $v))
)
(func (export "get_vec_y") (result f32)
(call $get_vec_y (struct.new_default $vec))
)
(func $set_get_y (param $v (ref $vec)) (param $y f32) (result f32)
(struct.set $vec $y (local.get $v) (local.get $y))
(struct.get $vec $y (local.get $v))
)
(func (export "set_get_y") (param $y f32) (result f32)
(call $set_get_y (struct.new_default $vec) (local.get $y))
)
(func $set_get_1 (param $v (ref $vec)) (param $y f32) (result f32)
(struct.set $vec 1 (local.get $v) (local.get $y))
(struct.get $vec $y (local.get $v))
)
(func (export "set_get_1") (param $y f32) (result f32)
(call $set_get_1 (struct.new_default $vec) (local.get $y))
)
)
(assert_return (invoke "new") (ref.struct))
(assert_return (invoke "get_0_0") (f32.const 0))
(assert_return (invoke "get_vec_0") (f32.const 0))
(assert_return (invoke "get_0_y") (f32.const 0))
(assert_return (invoke "get_vec_y") (f32.const 0))
(assert_return (invoke "set_get_y" (f32.const 7)) (f32.const 7))
(assert_return (invoke "set_get_1" (f32.const 7)) (f32.const 7))
(assert_invalid
(module
(type $s (struct (field i64)))
(func (export "struct.set-immutable") (param $s (ref $s))
(struct.set $s 0 (local.get $s) (i64.const 1))
)
)
"field is immutable"
)
;; Null dereference
(module
(type $t (struct (field i32 (mut i32))))
(func (export "struct.get-null")
(local (ref null $t)) (drop (struct.get $t 1 (local.get 0)))
)
(func (export "struct.set-null")
(local (ref null $t)) (struct.set $t 1 (local.get 0) (i32.const 0))
)
)
(assert_trap (invoke "struct.get-null") "null structure")
(assert_trap (invoke "struct.set-null") "null structure")
;; Packed field instructions
(module
(type $s (struct (field i8) (field (mut i8)) (field i16) (field (mut i16))))
(global (export "g0") (ref $s) (struct.new $s (i32.const 0) (i32.const 1) (i32.const 2) (i32.const 3)))
(global (export "g1") (ref $s) (struct.new $s (i32.const 254) (i32.const 255) (i32.const 65534) (i32.const 65535)))
(func (export "get_packed_g0_0") (result i32 i32)
(struct.get_s 0 0 (global.get 0))
(struct.get_u 0 0 (global.get 0))
)
(func (export "get_packed_g1_0") (result i32 i32)
(struct.get_s 0 0 (global.get 1))
(struct.get_u 0 0 (global.get 1))
)
(func (export "get_packed_g0_1") (result i32 i32)
(struct.get_s 0 1 (global.get 0))
(struct.get_u 0 1 (global.get 0))
)
(func (export "get_packed_g1_1") (result i32 i32)
(struct.get_s 0 1 (global.get 1))
(struct.get_u 0 1 (global.get 1))
)
(func (export "get_packed_g0_2") (result i32 i32)
(struct.get_s 0 2 (global.get 0))
(struct.get_u 0 2 (global.get 0))
)
(func (export "get_packed_g1_2") (result i32 i32)
(struct.get_s 0 2 (global.get 1))
(struct.get_u 0 2 (global.get 1))
)
(func (export "get_packed_g0_3") (result i32 i32)
(struct.get_s 0 3 (global.get 0))
(struct.get_u 0 3 (global.get 0))
)
(func (export "get_packed_g1_3") (result i32 i32)
(struct.get_s 0 3 (global.get 1))
(struct.get_u 0 3 (global.get 1))
)
(func (export "set_get_packed_g0_1") (param i32) (result i32 i32)
(struct.set 0 1 (global.get 0) (local.get 0))
(struct.get_s 0 1 (global.get 0))
(struct.get_u 0 1 (global.get 0))
)
(func (export "set_get_packed_g0_3") (param i32) (result i32 i32)
(struct.set 0 3 (global.get 0) (local.get 0))
(struct.get_s 0 3 (global.get 0))
(struct.get_u 0 3 (global.get 0))
)
)
(assert_return (invoke "get_packed_g0_0") (i32.const 0) (i32.const 0))
(assert_return (invoke "get_packed_g1_0") (i32.const -2) (i32.const 254))
(assert_return (invoke "get_packed_g0_1") (i32.const 1) (i32.const 1))
(assert_return (invoke "get_packed_g1_1") (i32.const -1) (i32.const 255))
(assert_return (invoke "get_packed_g0_2") (i32.const 2) (i32.const 2))
(assert_return (invoke "get_packed_g1_2") (i32.const -2) (i32.const 65534))
(assert_return (invoke "get_packed_g0_3") (i32.const 3) (i32.const 3))
(assert_return (invoke "get_packed_g1_3") (i32.const -1) (i32.const 65535))
(assert_return (invoke "set_get_packed_g0_1" (i32.const 257)) (i32.const 1) (i32.const 1))
(assert_return (invoke "set_get_packed_g0_3" (i32.const 257)) (i32.const 257) (i32.const 257))

View File

@ -0,0 +1,157 @@
(module
(table $t 10 externref)
(func (export "fill") (param $i i32) (param $r externref) (param $n i32)
(table.fill $t (local.get $i) (local.get $r) (local.get $n))
)
(func (export "fill-abbrev") (param $i i32) (param $r externref) (param $n i32)
(table.fill (local.get $i) (local.get $r) (local.get $n))
)
(func (export "get") (param $i i32) (result externref)
(table.get $t (local.get $i))
)
)
(assert_return (invoke "get" (i32.const 1)) (ref.null extern))
(assert_return (invoke "get" (i32.const 2)) (ref.null extern))
(assert_return (invoke "get" (i32.const 3)) (ref.null extern))
(assert_return (invoke "get" (i32.const 4)) (ref.null extern))
(assert_return (invoke "get" (i32.const 5)) (ref.null extern))
(assert_return (invoke "fill" (i32.const 2) (ref.extern 1) (i32.const 3)))
(assert_return (invoke "get" (i32.const 1)) (ref.null extern))
(assert_return (invoke "get" (i32.const 2)) (ref.extern 1))
(assert_return (invoke "get" (i32.const 3)) (ref.extern 1))
(assert_return (invoke "get" (i32.const 4)) (ref.extern 1))
(assert_return (invoke "get" (i32.const 5)) (ref.null extern))
(assert_return (invoke "fill" (i32.const 4) (ref.extern 2) (i32.const 2)))
(assert_return (invoke "get" (i32.const 3)) (ref.extern 1))
(assert_return (invoke "get" (i32.const 4)) (ref.extern 2))
(assert_return (invoke "get" (i32.const 5)) (ref.extern 2))
(assert_return (invoke "get" (i32.const 6)) (ref.null extern))
(assert_return (invoke "fill" (i32.const 4) (ref.extern 3) (i32.const 0)))
(assert_return (invoke "get" (i32.const 3)) (ref.extern 1))
(assert_return (invoke "get" (i32.const 4)) (ref.extern 2))
(assert_return (invoke "get" (i32.const 5)) (ref.extern 2))
(assert_return (invoke "fill" (i32.const 8) (ref.extern 4) (i32.const 2)))
(assert_return (invoke "get" (i32.const 7)) (ref.null extern))
(assert_return (invoke "get" (i32.const 8)) (ref.extern 4))
(assert_return (invoke "get" (i32.const 9)) (ref.extern 4))
(assert_return (invoke "fill-abbrev" (i32.const 9) (ref.null extern) (i32.const 1)))
(assert_return (invoke "get" (i32.const 8)) (ref.extern 4))
(assert_return (invoke "get" (i32.const 9)) (ref.null extern))
(assert_return (invoke "fill" (i32.const 10) (ref.extern 5) (i32.const 0)))
(assert_return (invoke "get" (i32.const 9)) (ref.null extern))
(assert_trap
(invoke "fill" (i32.const 8) (ref.extern 6) (i32.const 3))
"out of bounds table access"
)
(assert_return (invoke "get" (i32.const 7)) (ref.null extern))
(assert_return (invoke "get" (i32.const 8)) (ref.extern 4))
(assert_return (invoke "get" (i32.const 9)) (ref.null extern))
(assert_trap
(invoke "fill" (i32.const 11) (ref.null extern) (i32.const 0))
"out of bounds table access"
)
(assert_trap
(invoke "fill" (i32.const 11) (ref.null extern) (i32.const 10))
"out of bounds table access"
)
;; Type errors
(assert_invalid
(module
(table $t 10 externref)
(func $type-index-value-length-empty-vs-i32-i32
(table.fill $t)
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t 10 externref)
(func $type-index-empty-vs-i32
(table.fill $t (ref.null extern) (i32.const 1))
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t 10 externref)
(func $type-value-empty-vs
(table.fill $t (i32.const 1) (i32.const 1))
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t 10 externref)
(func $type-length-empty-vs-i32
(table.fill $t (i32.const 1) (ref.null extern))
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t 0 externref)
(func $type-index-f32-vs-i32
(table.fill $t (f32.const 1) (ref.null extern) (i32.const 1))
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t 0 funcref)
(func $type-value-vs-funcref (param $r externref)
(table.fill $t (i32.const 1) (local.get $r) (i32.const 1))
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t 0 externref)
(func $type-length-f32-vs-i32
(table.fill $t (i32.const 1) (ref.null extern) (f32.const 1))
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t1 1 externref)
(table $t2 1 funcref)
(func $type-value-externref-vs-funcref-multi (param $r externref)
(table.fill $t2 (i32.const 0) (local.get $r) (i32.const 1))
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t 1 externref)
(func $type-result-empty-vs-num (result i32)
(table.fill $t (i32.const 0) (ref.null extern) (i32.const 1))
)
)
"type mismatch"
)

View File

@ -0,0 +1,88 @@
(module
(table $t2 2 externref)
(table $t3 3 funcref)
(elem (table $t3) (i32.const 1) func $dummy)
(func $dummy)
(func (export "init") (param $r externref)
(table.set $t2 (i32.const 1) (local.get $r))
(table.set $t3 (i32.const 2) (table.get $t3 (i32.const 1)))
)
(func (export "get-externref") (param $i i32) (result externref)
(table.get (local.get $i))
)
(func $f3 (export "get-funcref") (param $i i32) (result funcref)
(table.get $t3 (local.get $i))
)
(func (export "is_null-funcref") (param $i i32) (result i32)
(ref.is_null (call $f3 (local.get $i)))
)
)
(invoke "init" (ref.extern 1))
(assert_return (invoke "get-externref" (i32.const 0)) (ref.null extern))
(assert_return (invoke "get-externref" (i32.const 1)) (ref.extern 1))
(assert_return (invoke "get-funcref" (i32.const 0)) (ref.null func))
(assert_return (invoke "is_null-funcref" (i32.const 1)) (i32.const 0))
(assert_return (invoke "is_null-funcref" (i32.const 2)) (i32.const 0))
(assert_trap (invoke "get-externref" (i32.const 2)) "out of bounds table access")
(assert_trap (invoke "get-funcref" (i32.const 3)) "out of bounds table access")
(assert_trap (invoke "get-externref" (i32.const -1)) "out of bounds table access")
(assert_trap (invoke "get-funcref" (i32.const -1)) "out of bounds table access")
;; Type errors
(assert_invalid
(module
(table $t 10 externref)
(func $type-index-empty-vs-i32 (result externref)
(table.get $t)
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t 10 externref)
(func $type-index-f32-vs-i32 (result externref)
(table.get $t (f32.const 1))
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t 10 externref)
(func $type-result-externref-vs-empty
(table.get $t (i32.const 0))
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t 10 externref)
(func $type-result-externref-vs-funcref (result funcref)
(table.get $t (i32.const 1))
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t1 1 funcref)
(table $t2 1 externref)
(func $type-result-externref-vs-funcref-multi (result funcref)
(table.get $t2 (i32.const 0))
)
)
"type mismatch"
)

View File

@ -0,0 +1,176 @@
(module
(table $t 0 externref)
(func (export "get") (param $i i32) (result externref) (table.get $t (local.get $i)))
(func (export "set") (param $i i32) (param $r externref) (table.set $t (local.get $i) (local.get $r)))
(func (export "grow") (param $sz i32) (param $init externref) (result i32)
(table.grow $t (local.get $init) (local.get $sz))
)
(func (export "grow-abbrev") (param $sz i32) (param $init externref) (result i32)
(table.grow (local.get $init) (local.get $sz))
)
(func (export "size") (result i32) (table.size $t))
)
(assert_return (invoke "size") (i32.const 0))
(assert_trap (invoke "set" (i32.const 0) (ref.extern 2)) "out of bounds table access")
(assert_trap (invoke "get" (i32.const 0)) "out of bounds table access")
(assert_return (invoke "grow" (i32.const 1) (ref.null extern)) (i32.const 0))
(assert_return (invoke "size") (i32.const 1))
(assert_return (invoke "get" (i32.const 0)) (ref.null extern))
(assert_return (invoke "set" (i32.const 0) (ref.extern 2)))
(assert_return (invoke "get" (i32.const 0)) (ref.extern 2))
(assert_trap (invoke "set" (i32.const 1) (ref.extern 2)) "out of bounds table access")
(assert_trap (invoke "get" (i32.const 1)) "out of bounds table access")
(assert_return (invoke "grow-abbrev" (i32.const 4) (ref.extern 3)) (i32.const 1))
(assert_return (invoke "size") (i32.const 5))
(assert_return (invoke "get" (i32.const 0)) (ref.extern 2))
(assert_return (invoke "set" (i32.const 0) (ref.extern 2)))
(assert_return (invoke "get" (i32.const 0)) (ref.extern 2))
(assert_return (invoke "get" (i32.const 1)) (ref.extern 3))
(assert_return (invoke "get" (i32.const 4)) (ref.extern 3))
(assert_return (invoke "set" (i32.const 4) (ref.extern 4)))
(assert_return (invoke "get" (i32.const 4)) (ref.extern 4))
(assert_trap (invoke "set" (i32.const 5) (ref.extern 2)) "out of bounds table access")
(assert_trap (invoke "get" (i32.const 5)) "out of bounds table access")
;; Reject growing to size outside i32 value range
(module
(table $t 0x10 funcref)
(elem declare func $f)
(func $f (export "grow") (result i32)
(table.grow $t (ref.func $f) (i32.const 0xffff_fff0))
)
)
(assert_return (invoke "grow") (i32.const -1))
(module
(table $t 0 externref)
(func (export "grow") (param i32) (result i32)
(table.grow $t (ref.null extern) (local.get 0))
)
)
(assert_return (invoke "grow" (i32.const 0)) (i32.const 0))
(assert_return (invoke "grow" (i32.const 1)) (i32.const 0))
(assert_return (invoke "grow" (i32.const 0)) (i32.const 1))
(assert_return (invoke "grow" (i32.const 2)) (i32.const 1))
(assert_return (invoke "grow" (i32.const 800)) (i32.const 3))
(module
(table $t 0 10 externref)
(func (export "grow") (param i32) (result i32)
(table.grow $t (ref.null extern) (local.get 0))
)
)
(assert_return (invoke "grow" (i32.const 0)) (i32.const 0))
(assert_return (invoke "grow" (i32.const 1)) (i32.const 0))
(assert_return (invoke "grow" (i32.const 1)) (i32.const 1))
(assert_return (invoke "grow" (i32.const 2)) (i32.const 2))
(assert_return (invoke "grow" (i32.const 6)) (i32.const 4))
(assert_return (invoke "grow" (i32.const 0)) (i32.const 10))
(assert_return (invoke "grow" (i32.const 1)) (i32.const -1))
(assert_return (invoke "grow" (i32.const 0x10000)) (i32.const -1))
(module
(table $t 10 funcref)
(func (export "grow") (param i32) (result i32)
(table.grow $t (ref.null func) (local.get 0))
)
(elem declare func 1)
(func (export "check-table-null") (param i32 i32) (result funcref)
(local funcref)
(local.set 2 (ref.func 1))
(block
(loop
(local.set 2 (table.get $t (local.get 0)))
(br_if 1 (i32.eqz (ref.is_null (local.get 2))))
(br_if 1 (i32.ge_u (local.get 0) (local.get 1)))
(local.set 0 (i32.add (local.get 0) (i32.const 1)))
(br_if 0 (i32.le_u (local.get 0) (local.get 1)))
)
)
(local.get 2)
)
)
(assert_return (invoke "check-table-null" (i32.const 0) (i32.const 9)) (ref.null func))
(assert_return (invoke "grow" (i32.const 10)) (i32.const 10))
(assert_return (invoke "check-table-null" (i32.const 0) (i32.const 19)) (ref.null func))
;; Type errors
(assert_invalid
(module
(table $t 0 externref)
(func $type-init-size-empty-vs-i32-externref (result i32)
(table.grow $t)
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t 0 externref)
(func $type-size-empty-vs-i32 (result i32)
(table.grow $t (ref.null extern))
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t 0 externref)
(func $type-init-empty-vs-externref (result i32)
(table.grow $t (i32.const 1))
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t 0 externref)
(func $type-size-f32-vs-i32 (result i32)
(table.grow $t (ref.null extern) (f32.const 1))
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t 0 funcref)
(func $type-init-externref-vs-funcref (param $r externref) (result i32)
(table.grow $t (local.get $r) (i32.const 1))
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t 1 externref)
(func $type-result-i32-vs-empty
(table.grow $t (ref.null extern) (i32.const 0))
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t 1 externref)
(func $type-result-i32-vs-f32 (result f32)
(table.grow $t (ref.null extern) (i32.const 0))
)
)
"type mismatch"
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,119 @@
(module
(table $t2 1 externref)
(table $t3 2 funcref)
(elem (table $t3) (i32.const 1) func $dummy)
(func $dummy)
(func (export "get-externref") (param $i i32) (result externref)
(table.get $t2 (local.get $i))
)
(func $f3 (export "get-funcref") (param $i i32) (result funcref)
(table.get $t3 (local.get $i))
)
(func (export "set-externref") (param $i i32) (param $r externref)
(table.set (local.get $i) (local.get $r))
)
(func (export "set-funcref") (param $i i32) (param $r funcref)
(table.set $t3 (local.get $i) (local.get $r))
)
(func (export "set-funcref-from") (param $i i32) (param $j i32)
(table.set $t3 (local.get $i) (table.get $t3 (local.get $j)))
)
(func (export "is_null-funcref") (param $i i32) (result i32)
(ref.is_null (call $f3 (local.get $i)))
)
)
(assert_return (invoke "get-externref" (i32.const 0)) (ref.null extern))
(assert_return (invoke "set-externref" (i32.const 0) (ref.extern 1)))
(assert_return (invoke "get-externref" (i32.const 0)) (ref.extern 1))
(assert_return (invoke "set-externref" (i32.const 0) (ref.null extern)))
(assert_return (invoke "get-externref" (i32.const 0)) (ref.null extern))
(assert_return (invoke "get-funcref" (i32.const 0)) (ref.null func))
(assert_return (invoke "set-funcref-from" (i32.const 0) (i32.const 1)))
(assert_return (invoke "is_null-funcref" (i32.const 0)) (i32.const 0))
(assert_return (invoke "set-funcref" (i32.const 0) (ref.null func)))
(assert_return (invoke "get-funcref" (i32.const 0)) (ref.null func))
(assert_trap (invoke "set-externref" (i32.const 2) (ref.null extern)) "out of bounds table access")
(assert_trap (invoke "set-funcref" (i32.const 3) (ref.null func)) "out of bounds table access")
(assert_trap (invoke "set-externref" (i32.const -1) (ref.null extern)) "out of bounds table access")
(assert_trap (invoke "set-funcref" (i32.const -1) (ref.null func)) "out of bounds table access")
(assert_trap (invoke "set-externref" (i32.const 2) (ref.extern 0)) "out of bounds table access")
(assert_trap (invoke "set-funcref-from" (i32.const 3) (i32.const 1)) "out of bounds table access")
(assert_trap (invoke "set-externref" (i32.const -1) (ref.extern 0)) "out of bounds table access")
(assert_trap (invoke "set-funcref-from" (i32.const -1) (i32.const 1)) "out of bounds table access")
;; Type errors
(assert_invalid
(module
(table $t 10 externref)
(func $type-index-value-empty-vs-i32-externref
(table.set $t)
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t 10 externref)
(func $type-index-empty-vs-i32
(table.set $t (ref.null extern))
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t 10 externref)
(func $type-value-empty-vs-externref
(table.set $t (i32.const 1))
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t 10 externref)
(func $type-size-f32-vs-i32
(table.set $t (f32.const 1) (ref.null extern))
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t 10 funcref)
(func $type-value-externref-vs-funcref (param $r externref)
(table.set $t (i32.const 1) (local.get $r))
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t1 1 externref)
(table $t2 1 funcref)
(func $type-value-externref-vs-funcref-multi (param $r externref)
(table.set $t2 (i32.const 0) (local.get $r))
)
)
"type mismatch"
)
(assert_invalid
(module
(table $t 10 externref)
(func $type-result-empty-vs-num (result i32)
(table.set $t (i32.const 0) (ref.null extern))
)
)
"type mismatch"
)

View File

@ -0,0 +1,804 @@
;; Definitions
(module
(type $e0 (sub (array i32)))
(type $e1 (sub $e0 (array i32)))
(type $e2 (sub (array anyref)))
(type $e3 (sub (array (ref null $e0))))
(type $e4 (sub (array (ref $e1))))
(type $m1 (sub (array (mut i32))))
(type $m2 (sub $m1 (array (mut i32))))
)
(module
(type $e0 (sub (struct)))
(type $e1 (sub $e0 (struct)))
(type $e2 (sub $e1 (struct (field i32))))
(type $e3 (sub $e2 (struct (field i32 (ref null $e0)))))
(type $e4 (sub $e3 (struct (field i32 (ref $e0) (mut i64)))))
(type $e5 (sub $e4 (struct (field i32 (ref $e1) (mut i64)))))
)
(module
(type $s (sub (struct)))
(type $s' (sub $s (struct)))
(type $f1 (sub (func (param (ref $s')) (result anyref))))
(type $f2 (sub $f1 (func (param (ref $s)) (result (ref any)))))
(type $f3 (sub $f2 (func (param (ref null $s)) (result (ref $s)))))
(type $f4 (sub $f3 (func (param (ref null struct)) (result (ref $s')))))
)
;; Recursive definitions
(module
(type $t (sub (struct (field anyref))))
(rec (type $r (sub $t (struct (field (ref $r))))))
(type $t' (sub $r (struct (field (ref $r) i32))))
)
(module
(rec
(type $r1 (sub (struct (field i32 (ref $r1)))))
)
(rec
(type $r2 (sub $r1 (struct (field i32 (ref $r3)))))
(type $r3 (sub $r1 (struct (field i32 (ref $r2)))))
)
)
(module
(rec
(type $a1 (sub (struct (field i32 (ref $a2)))))
(type $a2 (sub (struct (field i64 (ref $a1)))))
)
(rec
(type $b1 (sub $a2 (struct (field i64 (ref $a1) i32))))
(type $b2 (sub $a1 (struct (field i32 (ref $a2) i32))))
(type $b3 (sub $a2 (struct (field i64 (ref $b2) i32))))
)
)
;; Subsumption
(module
(rec
(type $t1 (sub (func (param i32 (ref $t3)))))
(type $t2 (sub $t1 (func (param i32 (ref $t2)))))
(type $t3 (sub $t2 (func (param i32 (ref $t1)))))
)
(func $f1 (param $r (ref $t1))
(call $f1 (local.get $r))
)
(func $f2 (param $r (ref $t2))
(call $f1 (local.get $r))
(call $f2 (local.get $r))
)
(func $f3 (param $r (ref $t3))
(call $f1 (local.get $r))
(call $f2 (local.get $r))
(call $f3 (local.get $r))
)
)
(module
(rec
(type $t1 (sub (func (result i32 (ref $u1)))))
(type $u1 (sub (func (result f32 (ref $t1)))))
)
(rec
(type $t2 (sub $t1 (func (result i32 (ref $u3)))))
(type $u2 (sub $u1 (func (result f32 (ref $t3)))))
(type $t3 (sub $t1 (func (result i32 (ref $u2)))))
(type $u3 (sub $u1 (func (result f32 (ref $t2)))))
)
(func $f1 (param $r (ref $t1))
(call $f1 (local.get $r))
)
(func $f2 (param $r (ref $t2))
(call $f1 (local.get $r))
(call $f2 (local.get $r))
)
(func $f3 (param $r (ref $t3))
(call $f1 (local.get $r))
(call $f3 (local.get $r))
)
)
(module
(rec (type $f1 (sub (func))) (type (struct (field (ref $f1)))))
(rec (type $f2 (sub (func))) (type (struct (field (ref $f2)))))
(rec (type $g1 (sub $f1 (func))) (type (struct)))
(rec (type $g2 (sub $f2 (func))) (type (struct)))
(func $g (type $g2))
(global (ref $g1) (ref.func $g))
)
(module
(rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1))))))
(rec (type $f2 (sub (func))) (type $s2 (sub (struct (field (ref $f2))))))
(rec
(type $g1 (sub $f1 (func)))
(type (sub $s1 (struct (field (ref $f1) (ref $f1) (ref $f2) (ref $f2) (ref $g1)))))
)
(rec
(type $g2 (sub $f2 (func)))
(type (sub $s2 (struct (field (ref $f1) (ref $f2) (ref $f1) (ref $f2) (ref $g2)))))
)
(func $g (type $g2))
(global (ref $g1) (ref.func $g))
)
(assert_invalid
(module
(rec (type $f1 (sub (func))) (type (struct (field (ref $f1)))))
(rec (type $f2 (sub (func))) (type (struct (field (ref $f1)))))
(rec (type $g1 (sub $f1 (func))) (type (struct)))
(rec (type $g2 (sub $f2 (func))) (type (struct)))
(func $g (type $g2))
(global (ref $g1) (ref.func $g))
)
"type mismatch"
)
(module
(rec (type $f1 (sub (func))) (type (struct (field (ref $f1)))))
(rec (type $f2 (sub (func))) (type (struct (field (ref $f2)))))
(rec (type $g (sub $f1 (func))) (type (struct)))
(func $g (type $g))
(global (ref $f1) (ref.func $g))
)
(module
(rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1))))))
(rec (type $f2 (sub (func))) (type $s2 (sub (struct (field (ref $f2))))))
(rec
(type $g1 (sub $f1 (func)))
(type (sub $s1 (struct (field (ref $f1) (ref $f1) (ref $f2) (ref $f2) (ref $g1)))))
)
(rec
(type $g2 (sub $f2 (func)))
(type (sub $s2 (struct (field (ref $f1) (ref $f2) (ref $f1) (ref $f2) (ref $g2)))))
)
(rec (type $h (sub $g2 (func))) (type (struct)))
(func $h (type $h))
(global (ref $f1) (ref.func $h))
(global (ref $g1) (ref.func $h))
)
(module
(rec (type $f11 (sub (func (result (ref func))))) (type $f12 (sub $f11 (func (result (ref $f11))))))
(rec (type $f21 (sub (func (result (ref func))))) (type $f22 (sub $f21 (func (result (ref $f21))))))
(func $f11 (type $f11) (unreachable))
(func $f12 (type $f12) (unreachable))
(global (ref $f11) (ref.func $f11))
(global (ref $f21) (ref.func $f11))
(global (ref $f12) (ref.func $f12))
(global (ref $f22) (ref.func $f12))
)
(module
(rec (type $f11 (sub (func (result (ref func))))) (type $f12 (sub $f11 (func (result (ref $f11))))))
(rec (type $f21 (sub (func (result (ref func))))) (type $f22 (sub $f21 (func (result (ref $f21))))))
(rec (type $g11 (sub $f11 (func (result (ref func))))) (type $g12 (sub $g11 (func (result (ref $g11))))))
(rec (type $g21 (sub $f21 (func (result (ref func))))) (type $g22 (sub $g21 (func (result (ref $g21))))))
(func $g11 (type $g11) (unreachable))
(func $g12 (type $g12) (unreachable))
(global (ref $f11) (ref.func $g11))
(global (ref $f21) (ref.func $g11))
(global (ref $f11) (ref.func $g12))
(global (ref $f21) (ref.func $g12))
(global (ref $g11) (ref.func $g11))
(global (ref $g21) (ref.func $g11))
(global (ref $g12) (ref.func $g12))
(global (ref $g22) (ref.func $g12))
)
(assert_invalid
(module
(rec (type $f11 (sub (func))) (type $f12 (sub $f11 (func))))
(rec (type $f21 (sub (func))) (type $f22 (sub $f11 (func))))
(func $f (type $f21))
(global (ref $f11) (ref.func $f))
)
"type mismatch"
)
(assert_invalid
(module
(rec (type $f01 (sub (func))) (type $f02 (sub $f01 (func))))
(rec (type $f11 (sub (func))) (type $f12 (sub $f01 (func))))
(rec (type $f21 (sub (func))) (type $f22 (sub $f11 (func))))
(func $f (type $f21))
(global (ref $f11) (ref.func $f))
)
"type mismatch"
)
;; Runtime types
(module
(type $t0 (sub (func (result (ref null func)))))
(rec (type $t1 (sub $t0 (func (result (ref null $t1))))))
(rec (type $t2 (sub $t1 (func (result (ref null $t2))))))
(func $f0 (type $t0) (ref.null func))
(func $f1 (type $t1) (ref.null $t1))
(func $f2 (type $t2) (ref.null $t2))
(table funcref (elem $f0 $f1 $f2))
(func (export "run")
(block (result (ref null func)) (call_indirect (type $t0) (i32.const 0)))
(block (result (ref null func)) (call_indirect (type $t0) (i32.const 1)))
(block (result (ref null func)) (call_indirect (type $t0) (i32.const 2)))
(block (result (ref null $t1)) (call_indirect (type $t1) (i32.const 1)))
(block (result (ref null $t1)) (call_indirect (type $t1) (i32.const 2)))
(block (result (ref null $t2)) (call_indirect (type $t2) (i32.const 2)))
(block (result (ref null $t0)) (ref.cast (ref $t0) (table.get (i32.const 0))))
(block (result (ref null $t0)) (ref.cast (ref $t0) (table.get (i32.const 1))))
(block (result (ref null $t0)) (ref.cast (ref $t0) (table.get (i32.const 2))))
(block (result (ref null $t1)) (ref.cast (ref $t1) (table.get (i32.const 1))))
(block (result (ref null $t1)) (ref.cast (ref $t1) (table.get (i32.const 2))))
(block (result (ref null $t2)) (ref.cast (ref $t2) (table.get (i32.const 2))))
(br 0)
)
(func (export "fail1")
(block (result (ref null $t1)) (call_indirect (type $t1) (i32.const 0)))
(br 0)
)
(func (export "fail2")
(block (result (ref null $t1)) (call_indirect (type $t2) (i32.const 0)))
(br 0)
)
(func (export "fail3")
(block (result (ref null $t1)) (call_indirect (type $t2) (i32.const 1)))
(br 0)
)
(func (export "fail4")
(ref.cast (ref $t1) (table.get (i32.const 0)))
(br 0)
)
(func (export "fail5")
(ref.cast (ref $t2) (table.get (i32.const 0)))
(br 0)
)
(func (export "fail6")
(ref.cast (ref $t2) (table.get (i32.const 1)))
(br 0)
)
)
(assert_return (invoke "run"))
(assert_trap (invoke "fail1") "indirect call")
(assert_trap (invoke "fail2") "indirect call")
(assert_trap (invoke "fail3") "indirect call")
(assert_trap (invoke "fail4") "cast")
(assert_trap (invoke "fail5") "cast")
(assert_trap (invoke "fail6") "cast")
(module
(type $t1 (sub (func)))
(type $t2 (sub final (func)))
(func $f1 (type $t1))
(func $f2 (type $t2))
(table funcref (elem $f1 $f2))
(func (export "fail1")
(block (call_indirect (type $t1) (i32.const 1)))
)
(func (export "fail2")
(block (call_indirect (type $t2) (i32.const 0)))
)
(func (export "fail3")
(ref.cast (ref $t1) (table.get (i32.const 1)))
(drop)
)
(func (export "fail4")
(ref.cast (ref $t2) (table.get (i32.const 0)))
(drop)
)
)
(assert_trap (invoke "fail1") "indirect call")
(assert_trap (invoke "fail2") "indirect call")
(assert_trap (invoke "fail3") "cast")
(assert_trap (invoke "fail4") "cast")
(module
(rec (type $f1 (sub (func))) (type (struct (field (ref $f1)))))
(rec (type $f2 (sub (func))) (type (struct (field (ref $f2)))))
(rec (type $g1 (sub $f1 (func))) (type (struct)))
(rec (type $g2 (sub $f2 (func))) (type (struct)))
(func $g (type $g2)) (elem declare func $g)
(func (export "run") (result i32)
(ref.test (ref $g1) (ref.func $g))
)
)
(assert_return (invoke "run") (i32.const 1))
(module
(rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1))))))
(rec (type $f2 (sub (func))) (type $s2 (sub (struct (field (ref $f2))))))
(rec
(type $g1 (sub $f1 (func)))
(type (sub $s1 (struct (field (ref $f1) (ref $f1) (ref $f2) (ref $f2) (ref $g1)))))
)
(rec
(type $g2 (sub $f2 (func)))
(type (sub $s2 (struct (field (ref $f1) (ref $f2) (ref $f1) (ref $f2) (ref $g2)))))
)
(func $g (type $g2)) (elem declare func $g)
(func (export "run") (result i32)
(ref.test (ref $g1) (ref.func $g))
)
)
(assert_return (invoke "run") (i32.const 1))
(module
(rec (type $f1 (sub (func))) (type (struct (field (ref $f1)))))
(rec (type $f2 (sub (func))) (type (struct (field (ref $f1)))))
(rec (type $g1 (sub $f1 (func))) (type (struct)))
(rec (type $g2 (sub $f2 (func))) (type (struct)))
(func $g (type $g2)) (elem declare func $g)
(func (export "run") (result i32)
(ref.test (ref $g1) (ref.func $g))
)
)
(assert_return (invoke "run") (i32.const 0))
(module
(rec (type $f1 (sub (func))) (type (struct (field (ref $f1)))))
(rec (type $f2 (sub (func))) (type (struct (field (ref $f2)))))
(rec (type $g (sub $f1 (func))) (type (struct)))
(func $g (type $g)) (elem declare func $g)
(func (export "run") (result i32)
(ref.test (ref $f1) (ref.func $g))
)
)
(assert_return (invoke "run") (i32.const 1))
(module
(rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1))))))
(rec (type $f2 (sub (func))) (type $s2 (sub (struct (field (ref $f2))))))
(rec
(type $g1 (sub $f1 (func)))
(type (sub $s1 (struct (field (ref $f1) (ref $f1) (ref $f2) (ref $f2) (ref $g1)))))
)
(rec
(type $g2 (sub $f2 (func)))
(type (sub $s2 (struct (field (ref $f1) (ref $f2) (ref $f1) (ref $f2) (ref $g2)))))
)
(rec (type $h (sub $g2 (func))) (type (struct)))
(func $h (type $h)) (elem declare func $h)
(func (export "run") (result i32 i32)
(ref.test (ref $f1) (ref.func $h))
(ref.test (ref $g1) (ref.func $h))
)
)
(assert_return (invoke "run") (i32.const 1) (i32.const 1))
(module
(rec (type $f11 (sub (func (result (ref func))))) (type $f12 (sub $f11 (func (result (ref $f11))))))
(rec (type $f21 (sub (func (result (ref func))))) (type $f22 (sub $f21 (func (result (ref $f21))))))
(func $f11 (type $f11) (unreachable)) (elem declare func $f11)
(func $f12 (type $f12) (unreachable)) (elem declare func $f12)
(func (export "run") (result i32 i32 i32 i32)
(ref.test (ref $f11) (ref.func $f11))
(ref.test (ref $f21) (ref.func $f11))
(ref.test (ref $f12) (ref.func $f12))
(ref.test (ref $f22) (ref.func $f12))
)
)
(assert_return (invoke "run")
(i32.const 1) (i32.const 1) (i32.const 1) (i32.const 1)
)
(module
(rec (type $f11 (sub (func (result (ref func))))) (type $f12 (sub $f11 (func (result (ref $f11))))))
(rec (type $f21 (sub (func (result (ref func))))) (type $f22 (sub $f21 (func (result (ref $f21))))))
(rec (type $g11 (sub $f11 (func (result (ref func))))) (type $g12 (sub $g11 (func (result (ref $g11))))))
(rec (type $g21 (sub $f21 (func (result (ref func))))) (type $g22 (sub $g21 (func (result (ref $g21))))))
(func $g11 (type $g11) (unreachable)) (elem declare func $g11)
(func $g12 (type $g12) (unreachable)) (elem declare func $g12)
(func (export "run") (result i32 i32 i32 i32 i32 i32 i32 i32)
(ref.test (ref $f11) (ref.func $g11))
(ref.test (ref $f21) (ref.func $g11))
(ref.test (ref $f11) (ref.func $g12))
(ref.test (ref $f21) (ref.func $g12))
(ref.test (ref $g11) (ref.func $g11))
(ref.test (ref $g21) (ref.func $g11))
(ref.test (ref $g12) (ref.func $g12))
(ref.test (ref $g22) (ref.func $g12))
)
)
(assert_return (invoke "run")
(i32.const 1) (i32.const 1) (i32.const 1) (i32.const 1)
(i32.const 1) (i32.const 1) (i32.const 1) (i32.const 1)
)
(module
(rec (type $f11 (sub (func))) (type $f12 (sub $f11 (func))))
(rec (type $f21 (sub (func))) (type $f22 (sub $f11 (func))))
(func $f (type $f21)) (elem declare func $f)
(func (export "run") (result i32)
(ref.test (ref $f11) (ref.func $f))
)
)
(assert_return (invoke "run") (i32.const 0))
(module
(rec (type $f01 (sub (func))) (type $f02 (sub $f01 (func))))
(rec (type $f11 (sub (func))) (type $f12 (sub $f01 (func))))
(rec (type $f21 (sub (func))) (type $f22 (sub $f11 (func))))
(func $f (type $f21)) (elem declare func $f)
(func (export "run") (result i32)
(ref.test (ref $f11) (ref.func $f))
)
)
(assert_return (invoke "run") (i32.const 0))
;; Linking
(module
(type $t0 (sub (func (result (ref null func)))))
(rec (type $t1 (sub $t0 (func (result (ref null $t1))))))
(rec (type $t2 (sub $t1 (func (result (ref null $t2))))))
(func (export "f0") (type $t0) (ref.null func))
(func (export "f1") (type $t1) (ref.null $t1))
(func (export "f2") (type $t2) (ref.null $t2))
)
(register "M")
(module
(type $t0 (sub (func (result (ref null func)))))
(rec (type $t1 (sub $t0 (func (result (ref null $t1))))))
(rec (type $t2 (sub $t1 (func (result (ref null $t2))))))
(func (import "M" "f0") (type $t0))
(func (import "M" "f1") (type $t0))
(func (import "M" "f1") (type $t1))
(func (import "M" "f2") (type $t0))
(func (import "M" "f2") (type $t1))
(func (import "M" "f2") (type $t2))
)
(assert_unlinkable
(module
(type $t0 (sub (func (result (ref null func)))))
(rec (type $t1 (sub $t0 (func (result (ref null $t1))))))
(rec (type $t2 (sub $t1 (func (result (ref null $t2))))))
(func (import "M" "f0") (type $t1))
)
"incompatible import type"
)
(assert_unlinkable
(module
(type $t0 (sub (func (result (ref null func)))))
(rec (type $t1 (sub $t0 (func (result (ref null $t1))))))
(rec (type $t2 (sub $t1 (func (result (ref null $t2))))))
(func (import "M" "f0") (type $t2))
)
"incompatible import type"
)
(assert_unlinkable
(module
(type $t0 (sub (func (result (ref null func)))))
(rec (type $t1 (sub $t0 (func (result (ref null $t1))))))
(rec (type $t2 (sub $t1 (func (result (ref null $t2))))))
(func (import "M" "f1") (type $t2))
)
"incompatible import type"
)
(module
(type $t1 (sub (func)))
(type $t2 (sub final (func)))
(func (export "f1") (type $t1))
(func (export "f2") (type $t2))
)
(register "M2")
(assert_unlinkable
(module
(type $t1 (sub (func)))
(type $t2 (sub final (func)))
(func (import "M2" "f1") (type $t2))
)
"incompatible import type"
)
(assert_unlinkable
(module
(type $t1 (sub (func)))
(type $t2 (sub final (func)))
(func (import "M2" "f2") (type $t1))
)
"incompatible import type"
)
(module
(rec (type $f2 (sub (func))) (type (struct (field (ref $f2)))))
(rec (type $g2 (sub $f2 (func))) (type (struct)))
(func (export "g") (type $g2))
)
(register "M3")
(module
(rec (type $f1 (sub (func))) (type (struct (field (ref $f1)))))
(rec (type $g1 (sub $f1 (func))) (type (struct)))
(func (import "M3" "g") (type $g1))
)
(module
(rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1))))))
(rec (type $f2 (sub (func))) (type $s2 (sub (struct (field (ref $f2))))))
(rec
(type $g2 (sub $f2 (func)))
(type (sub $s2 (struct (field (ref $f1) (ref $f2) (ref $f1) (ref $f2) (ref $g2)))))
)
(func (export "g") (type $g2))
)
(register "M4")
(module
(rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1))))))
(rec (type $f2 (sub (func))) (type $s2 (sub (struct (field (ref $f2))))))
(rec
(type $g1 (sub $f1 (func)))
(type (sub $s1 (struct (field (ref $f1) (ref $f1) (ref $f2) (ref $f2) (ref $g1)))))
)
(func (import "M4" "g") (type $g1))
)
(module
(rec (type $f1 (sub (func))) (type (struct (field (ref $f1)))))
(rec (type $f2 (sub (func))) (type (struct (field (ref $f1)))))
(rec (type $g2 (sub $f2 (func))) (type (struct)))
(func (export "g") (type $g2))
)
(register "M5")
(assert_unlinkable
(module
(rec (type $f1 (sub (func))) (type (struct (field (ref $f1)))))
(rec (type $g1 (sub $f1 (func))) (type (struct)))
(func (import "M5" "g") (type $g1))
)
"incompatible import"
)
(module
(rec (type $f1 (sub (func))) (type (struct (field (ref $f1)))))
(rec (type $f2 (sub (func))) (type (struct (field (ref $f2)))))
(rec (type $g (sub $f1 (func))) (type (struct)))
(func (export "g") (type $g))
)
(register "M6")
(module
(rec (type $f1 (sub (func))) (type (struct (field (ref $f1)))))
(rec (type $f2 (sub (func))) (type (struct (field (ref $f2)))))
(rec (type $g (sub $f1 (func))) (type (struct)))
(func (import "M6" "g") (type $f1))
)
(module
(rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1))))))
(rec (type $f2 (sub (func))) (type $s2 (sub (struct (field (ref $f2))))))
(rec
(type $g2 (sub $f2 (func)))
(type (sub $s2 (struct (field (ref $f1) (ref $f2) (ref $f1) (ref $f2) (ref $g2)))))
)
(rec (type $h (sub $g2 (func))) (type (struct)))
(func (export "h") (type $h))
)
;; (register "M7")
(module
(rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1))))))
(rec (type $f2 (sub (func))) (type $s2 (sub (struct (field (ref $f2))))))
(rec
(type $g1 (sub $f1 (func)))
(type (sub $s1 (struct (field (ref $f1) (ref $f1) (ref $f2) (ref $f2) (ref $g1)))))
)
(rec (type $h (sub $g1 (func))) (type (struct)))
(func (import "M7" "h") (type $f1))
(func (import "M7" "h") (type $g1))
)
(module
(rec (type $f11 (sub (func (result (ref func))))) (type $f12 (sub $f11 (func (result (ref $f11))))))
(rec (type $f21 (sub (func (result (ref func))))) (type $f22 (sub $f21 (func (result (ref $f21))))))
(func (export "f11") (type $f11) (unreachable))
(func (export "f12") (type $f12) (unreachable))
)
(register "M8")
(module
(rec (type $f11 (sub (func (result (ref func))))) (type $f12 (sub $f11 (func (result (ref $f11))))))
(rec (type $f21 (sub (func (result (ref func))))) (type $f22 (sub $f21 (func (result (ref $f21))))))
(func (import "M8" "f11") (type $f11))
(func (import "M8" "f11") (type $f21))
(func (import "M8" "f12") (type $f12))
(func (import "M8" "f12") (type $f22))
)
(module
(rec (type $f11 (sub (func (result (ref func))))) (type $f12 (sub $f11 (func (result (ref $f11))))))
(rec (type $f21 (sub (func (result (ref func))))) (type $f22 (sub $f21 (func (result (ref $f21))))))
(rec (type $g11 (sub $f11 (func (result (ref func))))) (type $g12 (sub $g11 (func (result (ref $g11))))))
(rec (type $g21 (sub $f21 (func (result (ref func))))) (type $g22 (sub $g21 (func (result (ref $g21))))))
(func (export "g11") (type $g11) (unreachable))
(func (export "g12") (type $g12) (unreachable))
)
(register "M9")
(module
(rec (type $f11 (sub (func (result (ref func))))) (type $f12 (sub $f11 (func (result (ref $f11))))))
(rec (type $f21 (sub (func (result (ref func))))) (type $f22 (sub $f21 (func (result (ref $f21))))))
(rec (type $g11 (sub $f11 (func (result (ref func))))) (type $g12 (sub $g11 (func (result (ref $g11))))))
(rec (type $g21 (sub $f21 (func (result (ref func))))) (type $g22 (sub $g21 (func (result (ref $g21))))))
(func (import "M9" "g11") (type $f11))
(func (import "M9" "g11") (type $f21))
(func (import "M9" "g12") (type $f11))
(func (import "M9" "g12") (type $f21))
(func (import "M9" "g11") (type $g11))
(func (import "M9" "g11") (type $g21))
(func (import "M9" "g12") (type $g12))
(func (import "M9" "g12") (type $g22))
)
(module
(rec (type $f11 (sub (func))) (type $f12 (sub $f11 (func))))
(rec (type $f21 (sub (func))) (type $f22 (sub $f11 (func))))
(func (export "f") (type $f21))
)
(register "M10")
(assert_unlinkable
(module
(rec (type $f11 (sub (func))) (type $f12 (sub $f11 (func))))
(func (import "M10" "f") (type $f11))
)
"incompatible import"
)
(module
(rec (type $f01 (sub (func))) (type $f02 (sub $f01 (func))))
(rec (type $f11 (sub (func))) (type $f12 (sub $f01 (func))))
(rec (type $f21 (sub (func))) (type $f22 (sub $f11 (func))))
(func (export "f") (type $f21))
)
(register "M11")
(assert_unlinkable
(module
(rec (type $f01 (sub (func))) (type $f02 (sub $f01 (func))))
(rec (type $f11 (sub (func))) (type $f12 (sub $f01 (func))))
(func (import "M11" "f") (type $f11))
)
"incompatible import"
)
;; Finality violation
(assert_invalid
(module
(type $t (func))
(type $s (sub $t (func)))
)
"sub type"
)
(assert_invalid
(module
(type $t (struct))
(type $s (sub $t (struct)))
)
"sub type"
)
(assert_invalid
(module
(type $t (sub final (func)))
(type $s (sub $t (func)))
)
"sub type"
)
(assert_invalid
(module
(type $t (sub (func)))
(type $s (sub final $t (func)))
(type $u (sub $s (func)))
)
"sub type"
)
;; Invalid subtyping definitions
(assert_invalid
(module
(type $a0 (sub (array i32)))
(type $s0 (sub $a0 (struct)))
)
"sub type"
)
(assert_invalid
(module
(type $f0 (sub (func (param i32) (result i32))))
(type $s0 (sub $f0 (struct)))
)
"sub type"
)
(assert_invalid
(module
(type $s0 (sub (struct)))
(type $a0 (sub $s0 (array i32)))
)
"sub type"
)
(assert_invalid
(module
(type $f0 (sub (func (param i32) (result i32))))
(type $a0 (sub $f0 (array i32)))
)
"sub type"
)
(assert_invalid
(module
(type $s0 (sub (struct)))
(type $f0 (sub $s0 (func (param i32) (result i32))))
)
"sub type"
)
(assert_invalid
(module
(type $a0 (sub (array i32)))
(type $f0 (sub $a0 (func (param i32) (result i32))))
)
"sub type"
)
(assert_invalid
(module
(type $a0 (sub (array i32)))
(type $a1 (sub $a0 (array i64)))
)
"sub type"
)
(assert_invalid
(module
(type $s0 (sub (struct (field i32))))
(type $s1 (sub $s0 (struct (field i64))))
)
"sub type"
)
(assert_invalid
(module
(type $f0 (sub (func)))
(type $f1 (sub $f0 (func (param i32))))
)
"sub type"
)

View File

@ -0,0 +1,215 @@
#!/usr/bin/python3
#
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
import os
import sys
import argparse
from typing import Dict, Tuple, List
import importlib
import inspect
import csv
REQUIREMENT_TESTS_DIR = "../../requirement-engineering"
SUBREQUIREMENT_DESCRIPTIONS = {}
# To use this empty function to do signature check
def expected_build_func_template(verbose: bool) -> None:
pass
# To use this empty function to do signature check
# The actual implementation of the return value should has following information:
#
def expected_run_func_template(
output_dir: str, subrequirement_ids: List[int]
) -> Dict[int, Dict[Tuple[str, str], bool]]:
pass
def dynamic_import(requirement_dir: str):
# Declare that we intend to modify the global variable
global SUBREQUIREMENT_DESCRIPTIONS
sys.path.append(requirement_dir)
os.chdir(requirement_dir)
try:
build_module = importlib.import_module("build")
build_function = getattr(build_module, "build")
except AttributeError:
raise ImportError("'build' function not found in the specified build.py file.")
try:
run_module = importlib.import_module("run")
run_function = getattr(run_module, "run")
SUBREQUIREMENT_DESCRIPTIONS = getattr(run_module, "SUBREQUIREMENT_DESCRIPTIONS")
except AttributeError:
raise ImportError(
"'run' function or 'SUBREQUIREMENT_DESCRIPTIONS' not found in the specified run.py file."
)
# Do signature check
expected_signature = inspect.signature(expected_build_func_template)
actual_signature = inspect.signature(build_function)
assert (
actual_signature == expected_signature
), "The build function doesn't have the expected signature"
expected_signature = inspect.signature(expected_run_func_template)
actual_signature = inspect.signature(run_function)
assert (
actual_signature == expected_signature
), "The run function doesn't have the expected signature"
# Check if the variable is a dictionary
if not isinstance(SUBREQUIREMENT_DESCRIPTIONS, dict):
raise TypeError("SUBREQUIREMENT_DESCRIPTIONS is not a dictionary")
# Check the types of keys and values in the dictionary
for key, value in SUBREQUIREMENT_DESCRIPTIONS.items():
if not isinstance(key, int):
raise TypeError("Key in SUBREQUIREMENT_DESCRIPTIONS is not an int")
if not (
isinstance(value, tuple)
and len(value) == 2
and all(isinstance(elem, str) for elem in value)
):
raise TypeError(
"Value in SUBREQUIREMENT_DESCRIPTIONS is not a Tuple[str, str]"
)
return build_function, run_function
def cmd_line_summary(
requirement_name: str, result_dict: dict, subrequirement_descriptions: dict
):
# command line summary
total, total_pass_nums, total_fail_nums = 0, 0, 0
print(f"\n============ Start: Summary of {requirement_name} test ============")
for subrequirement_id in result_dict.keys():
sub_total = len(result_dict[subrequirement_id])
pass_nums = len(
[_ for _, result in result_dict[subrequirement_id].items() if result]
)
fail_nums = len(
[_ for _, result in result_dict[subrequirement_id].items() if not result]
)
issue_number, subrequirement_description = subrequirement_descriptions.get(
subrequirement_id, ""
)
print(f"\nTest Sub-requirement id: {subrequirement_id}")
print(f"Issue Number: {issue_number}")
print(f"Sub-requirement description: {subrequirement_description}")
print(f"Number of test cases: {sub_total}")
print(f"Pass: {pass_nums}")
print(f"Fail: {fail_nums}\n")
print(
"----------------------------------------------------------------------------"
)
total += sub_total
total_pass_nums += pass_nums
total_fail_nums += fail_nums
print(f"\nTotal Number of test cases: {total}")
print(f"Pass: {total_pass_nums}")
print(f"Fail: {total_fail_nums}\n")
print(f"============= End: Summary of {requirement_name} test =============\n")
def generate_report(output_filename: str, result_dict: dict):
# create a list of column names
column_names = [
"subrequirement id",
"issue number",
"subrequirement description",
"running mode",
"test case name",
"test case description",
"test case executing result",
]
# open the output file in write mode
with open(output_filename + ".csv", "w") as output_file:
# create a csv writer object
csv_writer = csv.writer(output_file)
# write the column names as the first row
csv_writer.writerow(column_names)
# loop through the result_dict
for subrequirement_id, test_cases in result_dict.items():
# get the subrequirement description from the subrequirement_descriptions dict
issue_number, subrequirement_description = SUBREQUIREMENT_DESCRIPTIONS.get(
subrequirement_id, ""
)
# loop through the test cases
for test_case, result in test_cases.items():
# unpack the test case name and description from the tuple
test_case_name, test_case_description = test_case
# convert the result to pass or fail
result = "pass" if result else "fail"
# create a list of values for the current row
row_values = [
subrequirement_id,
issue_number,
subrequirement_description,
"AOT",
test_case_name,
test_case_description,
result,
]
# write the row values to the output file
csv_writer.writerow(row_values)
def run_requirement(
requirement_name: str, output_dir: str, subrequirement_ids: List[int]
):
requirement_dir = os.path.join(REQUIREMENT_TESTS_DIR, requirement_name)
if not os.path.isdir(requirement_dir):
print(f"No such requirement in directory {requirement_dir} exists")
sys.exit(1)
output_path = os.path.join(output_dir, requirement_name)
build_requirement_func, run_requirement_func = dynamic_import(requirement_dir)
build_requirement_func(verbose=False)
result_dict = run_requirement_func(output_path, subrequirement_ids)
cmd_line_summary(requirement_name, result_dict, SUBREQUIREMENT_DESCRIPTIONS)
generate_report(output_path, result_dict)
def main():
parser = argparse.ArgumentParser(description="Process command line options.")
# Define the '-o' option for output directory
parser.add_argument(
"-o", "--output_directory", required=True, help="Report output directory"
)
# Define the '-r' option for requirement name
parser.add_argument(
"-r", "--requirement_name", required=True, help="Requirement name"
)
# Define the subrequirement IDs as a list of integers
parser.add_argument(
"subrequirement_ids", nargs="*", type=int, help="Subrequirement IDs (optional)"
)
# Parse the arguments
args = parser.parse_args()
run_requirement(
args.requirement_name, args.output_directory, list(args.subrequirement_ids)
)
if __name__ == "__main__":
main()

View File

@ -28,6 +28,7 @@ function help()
echo "-e enable exception handling"
echo "-x test SGX"
echo "-w enable WASI threads"
echo "-a test all runtimes in sightglass suite"
echo "-b use the wabt binary release package instead of compiling from the source code"
echo "-g build iwasm with debug version"
echo "-v enable GC heap verification"
@ -37,6 +38,10 @@ function help()
echo "-C enable code coverage collect"
echo "-j set the platform to test"
echo "-T set sanitizer to use in tests(ubsan|tsan|asan)"
echo "-r [requirement name] [N [N ...]] specify a requirement name followed by one or more"
echo " subrequirement IDs, if no subrequirement is specificed,"
echo " it will run all subrequirements. When this optin is used,"
echo " only run requirement tests"
}
OPT_PARSED=""
@ -73,8 +78,11 @@ QEMU_FIRMWARE=""
WASI_TESTSUITE_COMMIT="ee807fc551978490bf1c277059aabfa1e589a6c2"
TARGET_LIST=("AARCH64" "AARCH64_VFP" "ARMV7" "ARMV7_VFP" "THUMBV7" "THUMBV7_VFP" \
"RISCV32" "RISCV32_ILP32F" "RISCV32_ILP32D" "RISCV64" "RISCV64_LP64F" "RISCV64_LP64D")
REQUIREMENT_NAME=""
# Initialize an empty array for subrequirement IDs
SUBREQUIREMENT_IDS=()
while getopts ":s:cabgvt:m:MCpSXexwWPGQF:j:T:" opt
while getopts ":s:cabgvt:m:MCpSXexwWPGQF:j:T:r:" opt
do
OPT_PARSED="TRUE"
case $opt in
@ -192,6 +200,19 @@ do
echo "sanitizer is " ${OPTARG}
WAMR_BUILD_SANITIZER=${OPTARG}
;;
r)
REQUIREMENT_NAME=$OPTARG
# get next arg if there are multiple values after -r
eval "nxarg=\${$((OPTIND))}"
# loop until the next symbol '-' or the end of arguments
while [[ "${nxarg}" =~ ^[0-9]+$ ]]; do
SUBREQUIREMENT_IDS+=("$nxarg")
OPTIND=$((OPTIND+1))
eval "nxarg=\${$((OPTIND))}"
done
echo "Only Test requirement name: ${REQUIREMENT_NAME}"
[[ ${#SUBREQUIREMENT_IDS[@]} -ne 0 ]] && echo "Choose subrequirement IDs: ${SUBREQUIREMENT_IDS[@]}"
;;
?)
help
exit 1
@ -219,6 +240,7 @@ readonly REPORT_DIR=${WORK_DIR}/report/${DATE}
mkdir -p ${REPORT_DIR}
readonly WAMR_DIR=${WORK_DIR}/../../..
readonly REQUIREMENT_SCRIPT_DIR=${WORK_DIR}/../requirement-engineering-test-script
if [[ ${SGX_OPT} == "--sgx" ]];then
readonly IWASM_LINUX_ROOT_DIR="${WAMR_DIR}/product-mini/platforms/linux-sgx"
@ -442,17 +464,17 @@ function spec_test()
popd
if [ ! -d "exception-handling" ];then
echo "exception-handling not exist, clone it from github"
git clone -b master --single-branch https://github.com/WebAssembly/exception-handling
git clone -b master --single-branch https://github.com/WebAssembly/exception-handling
fi
pushd exception-handling
# restore and clean everything
git reset --hard 51c721661b671bb7dc4b3a3acb9e079b49778d36
if [[ ${ENABLE_MULTI_MODULE} == 0 ]]; then
git apply ../../spec-test-script/exception_handling.patch
fi
popd
echo $(pwd)
fi
@ -731,6 +753,8 @@ function collect_standalone()
./collect_coverage.sh "${CODE_COV_FILE}" "${STANDALONE_DIR}/test-running-modes/c-embed/build"
echo "Collect code coverage of standalone test-ts2"
./collect_coverage.sh "${CODE_COV_FILE}" "${STANDALONE_DIR}/test-ts2/build"
echo "Collect code coverage of standalone test-module-malloc"
./collect_coverage.sh "${CODE_COV_FILE}" "${STANDALONE_DIR}/test-module-malloc/build"
popd > /dev/null 2>&1
fi
@ -858,6 +882,13 @@ function collect_coverage()
function trigger()
{
# Check if REQUIREMENT_NAME is set, if set, only calling requirement test and early return
if [[ -n $REQUIREMENT_NAME ]]; then
python ${REQUIREMENT_SCRIPT_DIR}/run_requirement.py -o ${REPORT_DIR}/ -r "$REQUIREMENT_NAME" "${SUBREQUIREMENT_IDS[@]}"
# early return with the python script exit status
return $?
fi
local EXTRA_COMPILE_FLAGS=""
# default enabled features
EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_BULK_MEMORY=1"
@ -907,6 +938,7 @@ function trigger()
EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_EXCE_HANDLING=1"
EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_TAIL_CALL=1"
fi
echo "SANITIZER IS" $WAMR_BUILD_SANITIZER
if [[ "$WAMR_BUILD_SANITIZER" == "ubsan" ]]; then