Bladeren bron

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

Zhang, Yi 1 jaar geleden
bovenliggende
commit
f729da7656
30 gewijzigde bestanden met toevoegingen van 9995 en 4 verwijderingen
  1. 74 0
      tests/requirement-engineering/README.md
  2. 74 0
      tests/requirement-engineering/gc-aot/build.py
  3. 23 0
      tests/requirement-engineering/gc-aot/build_spec_interpreter.sh
  4. 103 0
      tests/requirement-engineering/gc-aot/run.py
  5. 1589 0
      tests/requirement-engineering/gc-aot/runtest.py
  6. 115 0
      tests/requirement-engineering/gc-aot/test_cases.json
  7. 308 0
      tests/requirement-engineering/gc-aot/wasm-apps/array.wast
  8. 139 0
      tests/requirement-engineering/gc-aot/wasm-apps/array_copy.wast
  9. 81 0
      tests/requirement-engineering/gc-aot/wasm-apps/array_fill.wast
  10. 267 0
      tests/requirement-engineering/gc-aot/wasm-apps/br_on_cast.wast
  11. 282 0
      tests/requirement-engineering/gc-aot/wasm-apps/br_on_cast_fail.wast
  12. 208 0
      tests/requirement-engineering/gc-aot/wasm-apps/call_ref.wast
  13. 54 0
      tests/requirement-engineering/gc-aot/wasm-apps/extern.wast
  14. 51 0
      tests/requirement-engineering/gc-aot/wasm-apps/i31.wast
  15. 362 0
      tests/requirement-engineering/gc-aot/wasm-apps/local_set.wast
  16. 639 0
      tests/requirement-engineering/gc-aot/wasm-apps/local_tee.wast
  17. 186 0
      tests/requirement-engineering/gc-aot/wasm-apps/ref_cast.wast
  18. 168 0
      tests/requirement-engineering/gc-aot/wasm-apps/ref_eq.wast
  19. 331 0
      tests/requirement-engineering/gc-aot/wasm-apps/ref_test.wast
  20. 376 0
      tests/requirement-engineering/gc-aot/wasm-apps/return_call_ref.wast
  21. 592 0
      tests/requirement-engineering/gc-aot/wasm-apps/select.wast
  22. 229 0
      tests/requirement-engineering/gc-aot/wasm-apps/struct.wast
  23. 157 0
      tests/requirement-engineering/gc-aot/wasm-apps/table_fill.wast
  24. 88 0
      tests/requirement-engineering/gc-aot/wasm-apps/table_get.wast
  25. 176 0
      tests/requirement-engineering/gc-aot/wasm-apps/table_grow.wast
  26. 2149 0
      tests/requirement-engineering/gc-aot/wasm-apps/table_init.wast
  27. 119 0
      tests/requirement-engineering/gc-aot/wasm-apps/table_set.wast
  28. 804 0
      tests/requirement-engineering/gc-aot/wasm-apps/type_subtyping.wast
  29. 215 0
      tests/wamr-test-suites/requirement-engineering-test-script/run_requirement.py
  30. 36 4
      tests/wamr-test-suites/test_wamr.sh

+ 74 - 0
tests/requirement-engineering/README.md

@@ -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"
+   ```

+ 74 - 0
tests/requirement-engineering/gc-aot/build.py

@@ -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)

+ 23 - 0
tests/requirement-engineering/gc-aot/build_spec_interpreter.sh

@@ -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

+ 103 - 0
tests/requirement-engineering/gc-aot/run.py

@@ -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)

+ 1589 - 0
tests/requirement-engineering/gc-aot/runtest.py

@@ -0,0 +1,1589 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2019 Intel Corporation.  All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+#
+
+from __future__ import print_function
+import platform
+
+import argparse
+import array
+import atexit
+import math
+import os
+import re
+import shutil
+import struct
+import subprocess
+import sys
+import tempfile
+import time
+import threading
+import traceback
+from select import select
+from queue import Queue
+from subprocess import PIPE, STDOUT, Popen
+from typing import BinaryIO, Optional, Tuple
+
+if sys.version_info[0] == 2:
+    IS_PY_3 = False
+else:
+    IS_PY_3 = True
+
+test_aot = False
+# Available targets:
+#   "aarch64" "aarch64_vfp" "armv7" "armv7_vfp" "thumbv7" "thumbv7_vfp"
+#   "riscv32" "riscv32_ilp32f" "riscv32_ilp32d" "riscv64" "riscv64_lp64f" "riscv64_lp64d"
+test_target = "x86_64"
+
+debug_file = None
+log_file = None
+
+# to save the register module with self-define name
+temp_file_repo = []
+
+# to save the mapping of module files in /tmp by name
+temp_module_table = {}
+
+# AOT compilation options mapping
+aot_target_options_map = {
+    "i386": ["--target=i386"],
+    "x86_32": ["--target=i386"],
+    "x86_64": ["--target=x86_64", "--cpu=skylake"],
+    "aarch64": ["--target=aarch64", "--target-abi=eabi", "--cpu=cortex-a53"],
+    "aarch64_vfp": ["--target=aarch64", "--target-abi=gnueabihf", "--cpu=cortex-a53"],
+    "armv7": ["--target=armv7", "--target-abi=eabi", "--cpu=cortex-a9", "--cpu-features=-neon"],
+    "armv7_vfp": ["--target=armv7", "--target-abi=gnueabihf", "--cpu=cortex-a9"],
+    "thumbv7": ["--target=thumbv7", "--target-abi=eabi", "--cpu=cortex-a9", "--cpu-features=-neon,-vfpv3"],
+    "thumbv7_vfp": ["--target=thumbv7", "--target-abi=gnueabihf", "--cpu=cortex-a9", "--cpu-features=-neon"],
+    "riscv32": ["--target=riscv32", "--target-abi=ilp32", "--cpu=generic-rv32", "--cpu-features=+m,+a,+c"],
+    "riscv32_ilp32f": ["--target=riscv32", "--target-abi=ilp32f", "--cpu=generic-rv32", "--cpu-features=+m,+a,+c,+f"],
+    "riscv32_ilp32d": ["--target=riscv32", "--target-abi=ilp32d", "--cpu=generic-rv32", "--cpu-features=+m,+a,+c,+f,+d"],
+    "riscv64": ["--target=riscv64", "--target-abi=lp64", "--cpu=generic-rv64", "--cpu-features=+m,+a,+c"],
+    "riscv64_lp64f": ["--target=riscv64", "--target-abi=lp64f", "--cpu=generic-rv64", "--cpu-features=+m,+a,+c,+f"],
+    "riscv64_lp64d": ["--target=riscv64", "--target-abi=lp64d", "--cpu=generic-rv64", "--cpu-features=+m,+a,+c,+f,+d"],
+}
+
+
+def debug(data):
+    if debug_file:
+        debug_file.write(data)
+        debug_file.flush()
+
+
+def log(data, end='\n'):
+    if log_file:
+        log_file.write(data + end)
+        log_file.flush()
+    print(data, end=end)
+    sys.stdout.flush()
+
+
+def create_tmp_file(suffix: str) -> str:
+    with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as tmp_file:
+        return tmp_file.name
+
+
+# TODO: do we need to support '\n' too
+
+if platform.system().find("CYGWIN_NT") >= 0:
+    # TODO: this is weird, is this really right on Cygwin?
+    sep = "\n\r\n"
+else:
+    sep = "\r\n"
+rundir = None
+
+
+class AsyncStreamReader:
+    def __init__(self, stream: BinaryIO) -> None:
+        self._queue = Queue()
+        self._reader_thread = threading.Thread(
+            daemon=True,
+            target=AsyncStreamReader._stdout_reader,
+            args=(self._queue, stream))
+        self._reader_thread.start()
+
+    def read(self) -> Optional[bytes]:
+        return self._queue.get()
+
+    def cleanup(self) -> None:
+        self._reader_thread.join()
+
+    @staticmethod
+    def _stdout_reader(queue: Queue, stdout: BinaryIO) -> None:
+        while True:
+            try:
+                queue.put(stdout.read(1))
+            except ValueError as e:
+                if stdout.closed:
+                    queue.put(None)
+                    break
+                raise e
+
+
+class Runner():
+    def __init__(self, args, no_pty=False):
+        self.no_pty = no_pty
+
+        # Cleanup child process on exit
+        atexit.register(self.cleanup)
+
+        self.process = None
+        env = os.environ
+        env['TERM'] = 'dumb'
+        env['INPUTRC'] = '/dev/null'
+        env['PERL_RL'] = 'false'
+        if no_pty:
+            self.process = Popen(args, bufsize=0,
+                                 stdin=PIPE, stdout=PIPE, stderr=STDOUT,
+                                 env=env)
+            self.stdin = self.process.stdin
+            self.stdout = self.process.stdout
+        else:
+            import fcntl
+            # Pseudo-TTY and terminal manipulation
+            import pty
+            import termios
+            # Use tty to setup an interactive environment
+            master, slave = pty.openpty()
+
+            # Set terminal size large so that readline will not send
+            # ANSI/VT escape codes when the lines are long.
+            buf = array.array('h', [100, 200, 0, 0])
+            fcntl.ioctl(master, termios.TIOCSWINSZ, buf, True)
+
+            self.process = Popen(args, bufsize=0,
+                                 stdin=slave, stdout=slave, stderr=STDOUT,
+                                 preexec_fn=os.setsid,
+                                 env=env)
+            # Now close slave so that we will get an exception from
+            # read when the child exits early
+            # http://stackoverflow.com/questions/11165521
+            os.close(slave)
+            self.stdin = os.fdopen(master, 'r+b', 0)
+            self.stdout = self.stdin
+
+        if platform.system().lower() == "windows":
+            self._stream_reader = AsyncStreamReader(self.stdout)
+        else:
+            self._stream_reader = None
+
+        self.buf = ""
+
+    def _read_stdout_byte(self) -> Tuple[bool, Optional[bytes]]:
+        if self._stream_reader:
+            return True, self._stream_reader.read()
+        else:
+            # select doesn't work on file descriptors on Windows.
+            # however, this method is much faster than using
+            # queue, so we keep it for non-windows platforms.
+            [outs, _, _] = select([self.stdout], [], [], 1)
+            if self.stdout in outs:
+                return True, self.stdout.read(1)
+            else:
+                return False, None
+
+    def read_to_prompt(self, prompts, timeout):
+        wait_until = time.time() + timeout
+        while time.time() < wait_until:
+            has_value, read_byte = self._read_stdout_byte()
+            if not has_value:
+                continue
+            if not read_byte:
+                # EOF on macOS ends up here.
+                break
+            read_byte = read_byte.decode('utf-8') if IS_PY_3 else read_byte
+
+            debug(read_byte)
+            if self.no_pty:
+                self.buf += read_byte.replace('\n', '\r\n')
+            else:
+                self.buf += read_byte
+            self.buf = self.buf.replace('\r\r', '\r')
+
+            # filter the prompts
+            for prompt in prompts:
+                pattern = re.compile(prompt)
+                match = pattern.search(self.buf)
+                if match:
+                    end = match.end()
+                    buf = self.buf[0:end-len(prompt)]
+                    self.buf = self.buf[end:]
+                    return buf
+        return None
+
+    def writeline(self, str):
+        str_to_write = str + '\n'
+        str_to_write = bytes(
+            str_to_write, 'utf-8') if IS_PY_3 else str_to_write
+
+        self.stdin.write(str_to_write)
+
+    def cleanup(self):
+        atexit.unregister(self.cleanup)
+
+        if self.process:
+            try:
+                self.writeline("__exit__")
+                time.sleep(.020)
+                self.process.kill()
+            except OSError:
+                pass
+            except IOError:
+                pass
+            self.process = None
+            self.stdin.close()
+            if self.stdin != self.stdout:
+                self.stdout.close()
+            self.stdin = None
+            self.stdout = None
+            if not IS_PY_3:
+                sys.exc_clear()
+            if self._stream_reader:
+                self._stream_reader.cleanup()
+
+
+def assert_prompt(runner, prompts, timeout, is_need_execute_result):
+    # Wait for the initial prompt
+    header = runner.read_to_prompt(prompts, timeout=timeout)
+    if not header and is_need_execute_result:
+        log(" ---------- will terminate cause the case needs result while there is none inside of buf. ----------")
+        sys.exit(1)
+    if not header == None:
+        if header:
+            log("Started with:\n%s" % header)
+    else:
+        log("Did not one of following prompt(s): %s" % repr(prompts))
+        log("    Got      : %s" % repr(r.buf))
+        sys.exit(1)
+
+
+# WebAssembly specific
+
+parser = argparse.ArgumentParser(
+    description="Run a test file against a WebAssembly interpreter")
+parser.add_argument('--wast2wasm', type=str,
+                    default=os.environ.get("WAST2WASM", "wast2wasm"),
+                    help="Path to wast2wasm program")
+parser.add_argument('--interpreter', type=str,
+                    default=os.environ.get("IWASM_CMD", "iwasm"),
+                    help="Path to WebAssembly interpreter")
+parser.add_argument('--aot-compiler', type=str,
+                    default=os.environ.get("WAMRC_CMD", "wamrc"),
+                    help="Path to WebAssembly AoT compiler")
+
+parser.add_argument('--no_cleanup', action='store_true',
+                    help="Keep temporary *.wasm files")
+
+parser.add_argument('--rundir',
+                    help="change to the directory before running tests")
+parser.add_argument('--start-timeout', default=30, type=int,
+                    help="default timeout for initial prompt")
+parser.add_argument('--test-timeout', default=20, type=int,
+                    help="default timeout for each individual test action")
+parser.add_argument('--no-pty', action='store_true',
+                    help="Use direct pipes instead of pseudo-tty")
+parser.add_argument('--log-file', type=str,
+                    help="Write messages to the named file in addition the screen")
+parser.add_argument('--log-dir', type=str,
+                    help="The log directory to save the case file if test failed")
+parser.add_argument('--debug-file', type=str,
+                    help="Write all test interaction the named file")
+
+parser.add_argument('test_file', type=argparse.FileType('r'),
+                    help="a WebAssembly *.wast test file")
+
+parser.add_argument('--aot', action='store_true',
+                    help="Test with AOT")
+
+parser.add_argument('--target', type=str,
+                    default="x86_64",
+                    help="Set running target")
+
+parser.add_argument('--sgx', action='store_true',
+                    help="Test SGX")
+
+parser.add_argument('--simd', default=False, action='store_true',
+                    help="Enable SIMD")
+
+parser.add_argument('--xip', default=False, action='store_true',
+                    help="Enable XIP")
+
+parser.add_argument('--multi-module', default=False, action='store_true',
+                    help="Enable Multi-thread")
+
+parser.add_argument('--multi-thread', default=False, action='store_true',
+                    help="Enable Multi-thread")
+
+parser.add_argument('--gc', default=False, action='store_true',
+                    help='Test with GC')
+
+parser.add_argument('--qemu', default=False, action='store_true',
+                    help="Enable QEMU")
+
+parser.add_argument('--qemu-firmware', default='',
+                    help="Firmware required by qemu")
+
+parser.add_argument('--verbose', default=False, action='store_true',
+                    help='show more logs')
+
+# regex patterns of tests to skip
+C_SKIP_TESTS = ()
+PY_SKIP_TESTS = (
+    # names.wast
+    'invoke \"~!',
+    # conversions.wast
+    '18446742974197923840.0',
+    '18446744073709549568.0',
+    '9223372036854775808',
+    'reinterpret_f.*nan',
+    # endianness
+    '.const 0x1.fff')
+
+
+def read_forms(string):
+    forms = []
+    form = ""
+    depth = 0
+    line = 0
+    pos = 0
+    while pos < len(string):
+        # Keep track of line number
+        if string[pos] == '\n':
+            line += 1
+
+        # Handle top-level elements
+        if depth == 0:
+            # Add top-level comments
+            if string[pos:pos+2] == ";;":
+                end = string.find("\n", pos)
+                if end == -1:
+                    end == len(string)
+                forms.append(string[pos:end])
+                pos = end
+                continue
+
+            # TODO: handle nested multi-line comments
+            if string[pos:pos+2] == "(;":
+                # Skip multi-line comment
+                end = string.find(";)", pos)
+                if end == -1:
+                    raise Exception("mismatch multiline comment on line %d: '%s'" % (
+                        line, string[pos:pos+80]))
+                pos = end+2
+                continue
+
+            # Ignore whitespace between top-level forms
+            if string[pos] in (' ', '\n', '\t'):
+                pos += 1
+                continue
+
+        # Read a top-level form
+        if string[pos] == '(':
+            depth += 1
+        if string[pos] == ')':
+            depth -= 1
+        if depth == 0 and not form:
+            raise Exception("garbage on line %d: '%s'" % (
+                line, string[pos:pos+80]))
+        form += string[pos]
+        if depth == 0 and form:
+            forms.append(form)
+            form = ""
+        pos += 1
+    return forms
+
+
+def get_module_exp_from_assert(string):
+    depth = 0
+    pos = 0
+    module = ""
+    exception = ""
+    start_record = False
+    result = []
+    while pos < len(string):
+        # record from the " (module "
+        if string[pos:pos+7] == "(module":
+            start_record = True
+        if start_record:
+            if string[pos] == '(':
+                depth += 1
+            if string[pos] == ')':
+                depth -= 1
+            module += string[pos]
+            # if we get all (module ) .
+            if depth == 0 and module:
+                result.append(module)
+                start_record = False
+        # get expected exception
+        if string[pos] == '"':
+            end = string.find("\"", pos+1)
+            if end != -1:
+                end_rel = string.find("\"", end+1)
+                if end_rel == -1:
+                    result.append(string[pos+1:end])
+        pos += 1
+    return result
+
+
+def string_to_unsigned(number_in_string, lane_type):
+    if not lane_type in ['i8x16', 'i16x8', 'i32x4', 'i64x2']:
+        raise Exception("invalid value {} and type {} and lane_type {}".format(
+            number_in_string, type, lane_type))
+
+    number = int(number_in_string, 16) if '0x' in number_in_string else int(
+        number_in_string)
+
+    if "i8x16" == lane_type:
+        if number < 0:
+            packed = struct.pack('b', number)
+            number = struct.unpack('B', packed)[0]
+    elif "i16x8" == lane_type:
+        if number < 0:
+            packed = struct.pack('h', number)
+            number = struct.unpack('H', packed)[0]
+    elif "i32x4" == lane_type:
+        if number < 0:
+            packed = struct.pack('i', number)
+            number = struct.unpack('I', packed)[0]
+    else:  # "i64x2" == lane_type:
+        if number < 0:
+            packed = struct.pack('q', number)
+            number = struct.unpack('Q', packed)[0]
+
+    return number
+
+
+def cast_v128_to_i64x2(numbers, type, lane_type):
+    numbers = [n.replace("_", "") for n in numbers]
+
+    if "i8x16" == lane_type:
+        assert (16 == len(numbers)), "{} should like {}".format(
+            numbers, lane_type)
+        # str -> int
+        numbers = [string_to_unsigned(n, lane_type) for n in numbers]
+        # i8 -> i64
+        packed = struct.pack(16 * "B", *numbers)
+    elif "i16x8" == lane_type:
+        assert (8 == len(numbers)), "{} should like {}".format(
+            numbers, lane_type)
+        # str -> int
+        numbers = [string_to_unsigned(n, lane_type) for n in numbers]
+        # i16 -> i64
+        packed = struct.pack(8 * "H", *numbers)
+    elif "i32x4" == lane_type:
+        assert (4 == len(numbers)), "{} should like {}".format(
+            numbers, lane_type)
+        # str -> int
+        numbers = [string_to_unsigned(n, lane_type) for n in numbers]
+        # i32 -> i64
+        packed = struct.pack(4 * "I", *numbers)
+    elif "i64x2" == lane_type:
+        assert (2 == len(numbers)), "{} should like {}".format(
+            numbers, lane_type)
+        # str -> int
+        numbers = [string_to_unsigned(n, lane_type) for n in numbers]
+        # i64 -> i64
+        packed = struct.pack(2 * "Q", *numbers)
+    elif "f32x4" == lane_type:
+        assert (4 == len(numbers)), "{} should like {}".format(
+            numbers, lane_type)
+        # str -> int
+        numbers = [parse_simple_const_w_type(n, "f32")[0] for n in numbers]
+        # f32 -> i64
+        packed = struct.pack(4 * "f", *numbers)
+    elif "f64x2" == lane_type:
+        assert (2 == len(numbers)), "{} should like {}".format(
+            numbers, lane_type)
+        # str -> int
+        numbers = [parse_simple_const_w_type(n, "f64")[0] for n in numbers]
+        # f64 -> i64
+        packed = struct.pack(2 * "d", *numbers)
+    else:
+        raise Exception("invalid value {} and type {} and lane_type {}".format(
+            numbers, type, lane_type))
+
+    assert (packed)
+    unpacked = struct.unpack("Q Q", packed)
+    return unpacked, f"[{unpacked[0]:#x} {unpacked[1]:#x}]:{lane_type}:v128"
+
+
+def parse_simple_const_w_type(number, type):
+    number = number.replace('_', '')
+    number = re.sub(r"nan\((ind|snan)\)", "nan", number)
+    if type in ["i32", "i64"]:
+        number = int(number, 16) if '0x' in number else int(number)
+        return number, "0x{:x}:{}".format(number, type) \
+            if number >= 0 \
+            else "-0x{:x}:{}".format(0 - number, type)
+    elif type in ["f32", "f64"]:
+        if "nan:" in number:
+            return float('nan'), "nan:{}".format(type)
+        else:
+            number = float.fromhex(number) if '0x' in number else float(number)
+            return number, "{:.7g}:{}".format(number, type)
+    elif type == "ref.null":
+        if number == "func":
+            return "func", "func:ref.null"
+        elif number == "extern":
+            return "extern", "extern:ref.null"
+        elif number == "any":
+            return "any", "any:ref.null"
+        else:
+            raise Exception(
+                "invalid value {} and type {}".format(number, type))
+    elif type == "ref.extern":
+        number = int(number, 16) if '0x' in number else int(number)
+        return number, "0x{:x}:ref.extern".format(number)
+    elif type == "ref.host":
+        number = int(number, 16) if '0x' in number else int(number)
+        return number, "0x{:x}:ref.host".format(number)
+    else:
+        raise Exception("invalid value {} and type {}".format(number, type))
+
+
+def parse_assertion_value(val):
+    """
+    Parse something like:
+    "ref.null extern" in (assert_return (invoke "get-externref" (i32.const 0)) (ref.null extern))
+    "ref.extern 1" in (assert_return (invoke "get-externref" (i32.const 1)) (ref.extern 1))
+    "i32.const 0" in (assert_return (invoke "is_null-funcref" (i32.const 1)) (i32.const 0))
+
+    in summary:
+    type.const (sub-type) (val1 val2 val3 val4) ...
+    type.const val
+    ref.extern val
+    ref.null ref_type
+    ref.array
+    ref.struct
+    ref.func
+    ref.i31
+    """
+    if not val:
+        return None, ""
+
+    splitted = re.split('\s+', val)
+    splitted = [s for s in splitted if s]
+    type = splitted[0].split(".")[0]
+    lane_type = splitted[1] if len(splitted) > 2 else ""
+    numbers = splitted[2:] if len(splitted) > 2 else splitted[1:]
+
+    if type in ["i32", "i64", "f32", "f64"]:
+        return parse_simple_const_w_type(numbers[0], type)
+    elif type == "ref":
+        if splitted[0] in ["ref.array", "ref.struct", "ref.func", "ref.i31"]:
+            return splitted[0]
+        # need to distinguish between "ref.null" and "ref.extern"
+        return parse_simple_const_w_type(numbers[0], splitted[0])
+    else:
+        return cast_v128_to_i64x2(numbers, type, lane_type)
+
+
+def int2uint32(i):
+    return i & 0xffffffff
+
+
+def int2int32(i):
+    val = i & 0xffffffff
+    if val & 0x80000000:
+        return val - 0x100000000
+    else:
+        return val
+
+
+def int2uint64(i):
+    return i & 0xffffffffffffffff
+
+
+def int2int64(i):
+    val = i & 0xffffffffffffffff
+    if val & 0x8000000000000000:
+        return val - 0x10000000000000000
+    else:
+        return val
+
+
+def num_repr(i):
+    if isinstance(i, int) or isinstance(i, long):
+        return re.sub("L$", "", hex(i))
+    else:
+        return "%.16g" % i
+
+
+def hexpad16(i):
+    return "0x%04x" % i
+
+
+def hexpad24(i):
+    return "0x%06x" % i
+
+
+def hexpad32(i):
+    return "0x%08x" % i
+
+
+def hexpad64(i):
+    return "0x%016x" % i
+
+
+def invoke(r, args, cmd):
+    r.writeline(cmd)
+
+    return r.read_to_prompt(['\r\nwebassembly> ', '\nwebassembly> '],
+                            timeout=args.test_timeout)
+
+
+def vector_value_comparison(out, expected):
+    """
+    out likes "<number number>:v128"
+    expected likes "[number number]:v128"
+    """
+    # print("vector value comparision {} vs {}".format(out, expected))
+
+    out_val, out_type = out.split(':')
+    # <number nubmer> => number number
+    out_val = out_val[1:-1]
+
+    expected_val, lane_type, expected_type = expected.split(':')
+    # [number nubmer] => number number
+    expected_val = expected_val[1:-1]
+
+    assert ("v128" == out_type), "out_type should be v128"
+    assert ("v128" == expected_type), "expected_type should be v128"
+
+    if out_type != expected_type:
+        return False
+
+    out_val = out_val.split(" ")
+    expected_val = expected_val.split(" ")
+
+    # since i64x2
+    out_packed = struct.pack("QQ", int(out_val[0], 16), int(out_val[1], 16))
+    expected_packed = struct.pack("QQ",
+                                  int(expected_val[0]) if not "0x" in expected_val[0] else int(
+                                      expected_val[0], 16),
+                                  int(expected_val[1]) if not "0x" in expected_val[1] else int(expected_val[1], 16))
+
+    if lane_type in ["i8x16", "i16x8", "i32x4", "i64x2"]:
+        return out_packed == expected_packed
+    else:
+        assert (lane_type in ["f32x4", "f64x2"]), "unexpected lane_type"
+
+        if "f32x4" == lane_type:
+            out_unpacked = struct.unpack("ffff", out_packed)
+            expected_unpacked = struct.unpack("ffff", expected_packed)
+        else:
+            out_unpacked = struct.unpack("dd", out_packed)
+            expected_unpacked = struct.unpack("dd", expected_packed)
+
+        out_is_nan = [math.isnan(o) for o in out_unpacked]
+        expected_is_nan = [math.isnan(e) for e in expected_unpacked]
+        if any(out_is_nan):
+            nan_comparision = [o == e for o, e in zip(
+                out_is_nan, expected_is_nan)]
+            if all(nan_comparision):
+                print(f"Pass NaN comparision")
+                return True
+
+        # print(f"compare {out_unpacked} and {expected_unpacked}")
+        result = [o == e for o, e in zip(out_unpacked, expected_unpacked)]
+        if not all(result):
+            result = [
+                "{:.7g}".format(o) == "{:.7g}".format(e)
+                for o, e in zip(out_unpacked, expected_packed)
+            ]
+
+        return all(result)
+
+
+def simple_value_comparison(out, expected):
+    """
+    compare out of simple types which may like val:i32, val:f64 and so on
+    """
+    if expected == "2.360523e+13:f32" and out == "2.360522e+13:f32":
+        # one case in float_literals.wast, due to float precision of python
+        return True
+
+    if expected == "1.797693e+308:f64" and out == "inf:f64":
+        # one case in float_misc.wast:
+        # (assert_return (invoke "f64.add" (f64.const 0x1.fffffffffffffp+1023)
+        #                                  (f64.const 0x1.fffffffffffffp+969))
+        #                                  (f64.const 0x1.fffffffffffffp+1023))
+        # the add result in x86_32 is inf
+        return True
+
+    out_val, out_type = out.split(':')
+    expected_val, expected_type = expected.split(':')
+
+    if not out_type == expected_type:
+        return False
+
+    out_val, _ = parse_simple_const_w_type(out_val, out_type)
+    expected_val, _ = parse_simple_const_w_type(expected_val, expected_type)
+
+    if out_val == expected_val \
+            or (math.isnan(out_val) and math.isnan(expected_val)):
+        return True
+
+    if "i32" == expected_type:
+        out_val_binary = struct.pack('I', out_val) if out_val > 0 \
+            else struct.pack('i', out_val)
+        expected_val_binary = struct.pack('I', expected_val) \
+            if expected_val > 0 \
+            else struct.pack('i', expected_val)
+    elif "i64" == expected_type:
+        out_val_binary = struct.pack('Q', out_val) if out_val > 0 \
+            else struct.pack('q', out_val)
+        expected_val_binary = struct.pack('Q', expected_val) \
+            if expected_val > 0 \
+            else struct.pack('q', expected_val)
+    elif "f32" == expected_type:
+        out_val_binary = struct.pack('f', out_val)
+        expected_val_binary = struct.pack('f', expected_val)
+    elif "f64" == expected_type:
+        out_val_binary = struct.pack('d', out_val)
+        expected_val_binary = struct.pack('d', expected_val)
+    elif "ref.extern" == expected_type:
+        out_val_binary = out_val
+        expected_val_binary = expected_val
+    elif "ref.host" == expected_type:
+        out_val_binary = out_val
+        expected_val_binary = expected_val
+    else:
+        assert (0), "unknown 'expected_type' {}".format(expected_type)
+
+    if out_val_binary == expected_val_binary:
+        return True
+
+    if expected_type in ["f32", "f64"]:
+        # compare with a lower precision
+        out_str = "{:.7g}".format(out_val)
+        expected_str = "{:.7g}".format(expected_val)
+        if out_str == expected_str:
+            return True
+
+    return False
+
+
+def value_comparison(out, expected):
+    if out == expected:
+        return True
+
+    if not expected:
+        return False
+
+    if not out in ["ref.array", "ref.struct", "ref.func", "ref.any", "ref.i31"]:
+        assert (
+            ':' in out), "out should be in a form likes numbers:type, but {}".format(out)
+    if not expected in ["ref.array", "ref.struct", "ref.func", "ref.any", "ref.i31"]:
+        assert (':' in expected), "expected should be in a form likes numbers:type, but {}".format(
+            expected)
+
+    if 'v128' in out:
+        return vector_value_comparison(out, expected)
+    else:
+        return simple_value_comparison(out, expected)
+
+
+def is_result_match_expected(out, expected):
+    # compare value instead of comparing strings of values
+    return value_comparison(out, expected)
+
+
+def test_assert(r, opts, mode, cmd, expected):
+    log("Testing(%s) %s = %s" % (mode, cmd, expected))
+    out = invoke(r, opts, cmd)
+    if '\n' in out or ' ' in out:
+        outs = [''] + out.split('\n')[1:]
+        out = outs[-1]
+
+    if mode == 'trap':
+        o = re.sub('^Exception: ', '', out)
+        e = re.sub('^Exception: ', '', expected)
+        if o.find(e) >= 0 or e.find(o) >= 0:
+            return True
+
+    if mode == 'exhaustion':
+        o = re.sub('^Exception: ', '', out)
+        expected = 'Exception: stack overflow'
+        e = re.sub('^Exception: ', '', expected)
+        if o.find(e) >= 0 or e.find(o) >= 0:
+            return True
+
+    # 0x9:i32,-0x1:i32 -> ['0x9:i32', '-0x1:i32']
+    expected_list = re.split(',', expected)
+    out_list = re.split(',', out)
+    if len(expected_list) != len(out_list):
+        raise Exception(
+            "Failed:\n Results count incorrect:\n expected: '%s'\n  got: '%s'" % (expected, out))
+    for i in range(len(expected_list)):
+        if not is_result_match_expected(out_list[i], expected_list[i]):
+            raise Exception("Failed:\n Result %d incorrect:\n expected: '%s'\n  got: '%s'" % (
+                i, expected_list[i], out_list[i]))
+
+    return True
+
+
+def test_assert_return(r, opts, form):
+    """
+    m. to search a pattern like (assert_return (invoke function_name ... ) ...)
+    n. to search a pattern like (assert_return (invoke $module_name function_name ... ) ...)
+    """
+    # params, return
+    m = re.search(
+        '^\(assert_return\s+\(invoke\s+"((?:[^"]|\\\")*)"\s+(\(.*\))\s*\)\s*(\(.*\))\s*\)\s*$', form, re.S)
+    # judge if assert_return cmd includes the module name
+    n = re.search(
+        '^\(assert_return\s+\(invoke\s+\$((?:[^\s])*)\s+"((?:[^"]|\\\")*)"\s+(\(.*\))\s*\)\s*(\(.*\))\s*\)\s*$', form, re.S)
+
+    # print("assert_return with {}".format(form))
+
+    if not m:
+        # no params, return
+        m = re.search(
+            '^\(assert_return\s+\(invoke\s+"((?:[^"]|\\\")*)"\s*\)\s+()(\(.*\))\s*\)\s*$', form, re.S)
+    if not m:
+        # params, no return
+        m = re.search(
+            '^\(assert_return\s+\(invoke\s+"([^"]*)"\s+(\(.*\))()\s*\)\s*\)\s*$', form, re.S)
+    if not m:
+        # no params, no return
+        m = re.search(
+            '^\(assert_return\s+\(invoke\s+"([^"]*)"\s*()()\)\s*\)\s*$', form, re.S)
+    if not m:
+        # params, return
+        if not n:
+            # no params, return
+            n = re.search(
+                '^\(assert_return\s+\(invoke\s+\$((?:[^\s])*)\s+"((?:[^"]|\\\")*)"\s*\)\s+()(\(.*\))\s*\)\s*$', form, re.S)
+        if not n:
+            # params, no return
+            n = re.search(
+                '^\(assert_return\s+\(invoke\s+\$((?:[^\s])*)\s+"([^"]*)"\s+(\(.*\))()\s*\)\s*\)\s*$', form, re.S)
+        if not n:
+            # no params, no return
+            n = re.search(
+                '^\(assert_return\s+\(invoke\s+\$((?:[^\s])*)\s+"([^"]*)"*()()\)\s*\)\s*$', form, re.S)
+    if not m and not n:
+        if re.search('^\(assert_return\s+\(get.*\).*\)$', form, re.S):
+            log("ignoring assert_return get")
+            return
+        else:
+            raise Exception("unparsed assert_return: '%s'" % form)
+    if m and not n:
+        func = m.group(1)
+        if ' ' in func:
+            func = func.replace(' ', '\\')
+
+        if m.group(2) == '':
+            args = []
+        else:
+            # args = [re.split(' +', v)[1].replace('_', "") for v in re.split("\)\s*\(", m.group(2)[1:-1])]
+            # split arguments with ')spaces(', remove leading and tailing ) and (
+            args_type_and_value = re.split(r'\)\s+\(', m.group(2)[1:-1])
+            args_type_and_value = [s.replace('_', '')
+                                   for s in args_type_and_value]
+            # args are in two forms:
+            # f32.const -0x1.000001fffffffffffp-50
+            # v128.const i32x4 0 0 0 0
+            args = []
+            for arg in args_type_and_value:
+                # remove leading and tailing spaces, it might confuse following assertions
+                arg = arg.strip()
+                splitted = re.split('\s+', arg)
+                splitted = [s for s in splitted if s]
+
+                if splitted[0] in ["i32.const", "i64.const"]:
+                    assert (2 == len(splitted)
+                            ), "{} should have two parts".format(splitted)
+                    # in wast 01234 means 1234
+                    # in c 0123 means 83 in oct
+                    number, _ = parse_simple_const_w_type(
+                        splitted[1], splitted[0][:3])
+                    args.append(str(number))
+                elif splitted[0] in ["f32.const", "f64.const"]:
+                    # let strtof or strtod handle original arguments
+                    assert (2 == len(splitted)
+                            ), "{} should have two parts".format(splitted)
+                    args.append(splitted[1])
+                elif "v128.const" == splitted[0]:
+                    assert (len(splitted) > 2), "{} should have more than two parts".format(
+                        splitted)
+                    numbers, _ = cast_v128_to_i64x2(
+                        splitted[2:], 'v128', splitted[1])
+
+                    assert (len(numbers) ==
+                            2), "has to reform arguments into i64x2"
+                    args.append(f"{numbers[0]:#x}\{numbers[1]:#x}")
+                elif "ref.null" == splitted[0]:
+                    args.append("null")
+                elif "ref.extern" == splitted[0]:
+                    number, _ = parse_simple_const_w_type(
+                        splitted[1], splitted[0])
+                    args.append(str(number))
+                elif "ref.host" == splitted[0]:
+                    number, _ = parse_simple_const_w_type(
+                        splitted[1], splitted[0])
+                    args.append(str(number))
+                else:
+                    assert (0), "an unkonwn parameter type"
+
+        if m.group(3) == '':
+            returns = []
+        else:
+            returns = re.split("\)\s*\(", m.group(3)[1:-1])
+        # processed numbers in strings
+        if len(returns) == 1 and returns[0] in ["ref.array", "ref.struct", "ref.i31",
+                                                "ref.eq", "ref.any", "ref.extern",
+                                                "ref.func", "ref.null"]:
+            expected = [returns[0]]
+        elif len(returns) == 1 and returns[0] in ["func:ref.null", "any:ref.null",
+                                                  "extern:ref.null"]:
+            expected = [returns[0]]
+        else:
+            expected = [parse_assertion_value(v)[1] for v in returns]
+        expected = ",".join(expected)
+
+        test_assert(r, opts, "return", "%s %s" %
+                    (func, " ".join(args)), expected)
+    elif not m and n:
+        module = temp_module_table[n.group(1)].split(".wasm")[0]
+        # assume the cmd is (assert_return(invoke $ABC "func")).
+        # run the ABC.wasm firstly
+        if test_aot:
+            r = compile_wasm_to_aot(
+                module+".wasm", module+".aot", True, opts, r)
+            try:
+                assert_prompt(r, ['Compile success'],
+                              opts.start_timeout, False)
+            except:
+                _, exc, _ = sys.exc_info()
+                log("Run wamrc failed:\n  got: '%s'" % r.buf)
+                ret_code = 1
+                sys.exit(1)
+        r = run_wasm_with_repl(module+".wasm", module +
+                               ".aot" if test_aot else module, opts, r)
+        # Wait for the initial prompt
+        try:
+            assert_prompt(r, ['webassembly> '], opts.start_timeout, False)
+        except:
+            _, exc, _ = sys.exc_info()
+            raise Exception("Failed:\n  expected: '%s'\n  got: '%s'" %
+                            (repr(exc), r.buf))
+        func = n.group(2)
+        if ' ' in func:
+            func = func.replace(' ', '\\')
+
+        if n.group(3) == '':
+            args = []
+        else:
+            # convert (ref.null extern/func) into (ref.null null)
+            n1 = n.group(3).replace("(ref.null extern)", "(ref.null null)")
+            n1 = n1.replace("ref.null func)", "(ref.null null)")
+            args = [re.split(' +', v)[1]
+                    for v in re.split("\)\s*\(", n1[1:-1])]
+
+        _, expected = parse_assertion_value(n.group(4)[1:-1])
+        test_assert(r, opts, "return", "%s %s" %
+                    (func, " ".join(args)), expected)
+
+
+def test_assert_trap(r, opts, form):
+    # params
+    m = re.search(
+        '^\(assert_trap\s+\(invoke\s+"([^"]*)"\s+(\(.*\))\s*\)\s*"([^"]+)"\s*\)\s*$', form)
+    # judge if assert_return cmd includes the module name
+    n = re.search(
+        '^\(assert_trap\s+\(invoke\s+\$((?:[^\s])*)\s+"([^"]*)"\s+(\(.*\))\s*\)\s*"([^"]+)"\s*\)\s*$', form, re.S)
+    if not m:
+        # no params
+        m = re.search(
+            '^\(assert_trap\s+\(invoke\s+"([^"]*)"\s*()\)\s*"([^"]+)"\s*\)\s*$', form)
+    if not m:
+        if not n:
+            # no params
+            n = re.search(
+                '^\(assert_trap\s+\(invoke\s+\$((?:[^\s])*)\s+"([^"]*)"\s*()\)\s*"([^"]+)"\s*\)\s*$', form, re.S)
+    if not m and not n:
+        raise Exception("unparsed assert_trap: '%s'" % form)
+
+    if m and not n:
+        func = m.group(1)
+        if m.group(2) == '':
+            args = []
+        else:
+            # convert (ref.null extern/func) into (ref.null null)
+            m1 = m.group(2).replace("(ref.null extern)", "(ref.null null)")
+            m1 = m1.replace("ref.null func)", "(ref.null null)")
+            args = [re.split(' +', v)[1]
+                    for v in re.split("\)\s*\(", m1[1:-1])]
+
+        expected = "Exception: %s" % m.group(3)
+        test_assert(r, opts, "trap", "%s %s" %
+                    (func, " ".join(args)), expected)
+
+    elif not m and n:
+        module = n.group(1)
+        module = tempfile.gettempdir() + "/" + module
+
+        # will trigger the module named in assert_return(invoke $ABC).
+        # run the ABC.wasm firstly
+        if test_aot:
+            r = compile_wasm_to_aot(
+                module+".wasm", module+".aot", True, opts, r)
+            try:
+                assert_prompt(r, ['Compile success'],
+                              opts.start_timeout, False)
+            except:
+                _, exc, _ = sys.exc_info()
+                log("Run wamrc failed:\n  got: '%s'" % r.buf)
+                ret_code = 1
+                sys.exit(1)
+        r = run_wasm_with_repl(module+".wasm", module +
+                               ".aot" if test_aot else module, opts, r)
+        # Wait for the initial prompt
+        try:
+            assert_prompt(r, ['webassembly> '], opts.start_timeout, False)
+        except:
+            _, exc, _ = sys.exc_info()
+            raise Exception("Failed:\n  expected: '%s'\n  got: '%s'" %
+                            (repr(exc), r.buf))
+
+        func = n.group(2)
+        if n.group(3) == '':
+            args = []
+        else:
+            args = [re.split(' +', v)[1]
+                    for v in re.split("\)\s*\(", n.group(3)[1:-1])]
+        expected = "Exception: %s" % n.group(4)
+        test_assert(r, opts, "trap", "%s %s" %
+                    (func, " ".join(args)), expected)
+
+
+def test_assert_exhaustion(r, opts, form):
+    # params
+    m = re.search(
+        '^\(assert_exhaustion\s+\(invoke\s+"([^"]*)"\s+(\(.*\))\s*\)\s*"([^"]+)"\s*\)\s*$', form)
+    if not m:
+        # no params
+        m = re.search(
+            '^\(assert_exhaustion\s+\(invoke\s+"([^"]*)"\s*()\)\s*"([^"]+)"\s*\)\s*$', form)
+    if not m:
+        raise Exception("unparsed assert_exhaustion: '%s'" % form)
+    func = m.group(1)
+    if m.group(2) == '':
+        args = []
+    else:
+        args = [re.split(' +', v)[1]
+                for v in re.split("\)\s*\(", m.group(2)[1:-1])]
+    expected = "Exception: %s\n" % m.group(3)
+    test_assert(r, opts, "exhaustion", "%s %s" %
+                (func, " ".join(args)), expected)
+
+
+def do_invoke(r, opts, form):
+    # params
+    m = re.search('^\(invoke\s+"([^"]+)"\s+(\(.*\))\s*\)\s*$', form)
+    if not m:
+        # no params
+        m = re.search('^\(invoke\s+"([^"]+)"\s*()\)\s*$', form)
+    if not m:
+        raise Exception("unparsed invoke: '%s'" % form)
+    func = m.group(1)
+
+    if ' ' in func:
+        func = func.replace(' ', '\\')
+
+    if m.group(2) == '':
+        args = []
+    else:
+        args = [re.split(' +', v)[1]
+                for v in re.split("\)\s*\(", m.group(2)[1:-1])]
+
+    log("Invoking %s(%s)" % (
+        func, ", ".join([str(a) for a in args])))
+
+    invoke(r, opts, "%s %s" % (func, " ".join(args)))
+
+
+def skip_test(form, skip_list):
+    for s in skip_list:
+        if re.search(s, form):
+            return True
+    return False
+
+
+def compile_wast_to_wasm(form, wast_tempfile, wasm_tempfile, opts):
+    log("Writing WAST module to '%s'" % wast_tempfile)
+    with open(wast_tempfile, 'w') as file:
+        file.write(form)
+    log("Compiling WASM to '%s'" % wasm_tempfile)
+
+    # default arguments
+    if opts.gc:
+        cmd = [opts.wast2wasm, "-u", "-d", wast_tempfile, "-o", wasm_tempfile]
+    else:
+        cmd = [opts.wast2wasm, "--enable-thread", "--no-check",
+               wast_tempfile, "-o", wasm_tempfile]
+
+    # remove reference-type and bulk-memory enabling options since a WABT
+    # commit 30c1e983d30b33a8004b39fd60cbd64477a7956c
+    # Enable reference types by default (#1729)
+
+    log("Running: %s" % " ".join(cmd))
+    try:
+        subprocess.check_call(cmd)
+    except subprocess.CalledProcessError as e:
+        print(str(e))
+        return False
+
+    return True
+
+
+def compile_wasm_to_aot(wasm_tempfile, aot_tempfile, runner, opts, r, output='default'):
+    log("Compiling '%s' to '%s'" % (wasm_tempfile, aot_tempfile))
+    cmd = [opts.aot_compiler]
+
+    if test_target in aot_target_options_map:
+        cmd += aot_target_options_map[test_target]
+
+    if opts.sgx:
+        cmd.append("-sgx")
+
+    if not opts.simd:
+        cmd.append("--disable-simd")
+
+    if opts.xip:
+        cmd.append("--enable-indirect-mode")
+        cmd.append("--disable-llvm-intrinsics")
+
+    if opts.multi_thread:
+        cmd.append("--enable-multi-thread")
+
+    if opts.gc:
+        cmd.append("--enable-gc")
+        cmd.append("--enable-tail-call")
+
+    if output == 'object':
+        cmd.append("--format=object")
+    elif output == 'ir':
+        cmd.append("--format=llvmir-opt")
+
+    # disable llvm link time optimization as it might convert
+    # code of tail call into code of dead loop, and stack overflow
+    # exception isn't thrown in several cases
+    cmd.append("--disable-llvm-lto")
+
+    # Bounds checks is disabled by default for 64-bit targets, to
+    # use the hardware based bounds checks. But it is not supported
+    # in QEMU with NuttX.
+    # Enable bounds checks explicitly for all targets if running in QEMU.
+    if opts.qemu:
+        cmd.append("--bounds-checks=1")
+
+    # RISCV64 requires -mcmodel=medany, which can be set by --size-level=1
+    if test_target.startswith("riscv64"):
+        cmd.append("--size-level=1")
+
+    cmd += ["-o", aot_tempfile, wasm_tempfile]
+
+    log("Running: %s" % " ".join(cmd))
+    if not runner:
+        subprocess.check_call(cmd)
+    else:
+        if (r != None):
+            r.cleanup()
+        r = Runner(cmd, no_pty=opts.no_pty)
+        return r
+
+
+def run_wasm_with_repl(wasm_tempfile, aot_tempfile, opts, r):
+    tmpfile = aot_tempfile if test_aot else wasm_tempfile
+    log("Starting interpreter for module '%s'" % tmpfile)
+
+    cmd_iwasm = [opts.interpreter, "--heap-size=0",
+                 "-v=5" if opts.verbose else "-v=0", "--repl", tmpfile]
+
+    if opts.multi_module:
+        cmd_iwasm.insert(1, "--module-path=" +
+                         (tempfile.gettempdir() if not opts.qemu else "/tmp"))
+
+    if opts.qemu:
+        if opts.qemu_firmware == '':
+            raise Exception("QEMU firmware missing")
+
+        if opts.target.startswith("aarch64"):
+            cmd = "qemu-system-aarch64 -cpu cortex-a53 -nographic -machine virt,virtualization=on,gic-version=3 -net none -chardev stdio,id=con,mux=on -serial chardev:con -mon chardev=con,mode=readline -kernel".split()
+            cmd.append(opts.qemu_firmware)
+        elif opts.target.startswith("thumbv7"):
+            cmd = "qemu-system-arm -semihosting -M sabrelite -m 1024 -smp 1 -nographic -kernel".split()
+            cmd.append(opts.qemu_firmware)
+        elif opts.target.startswith("riscv32"):
+            cmd = "qemu-system-riscv32 -semihosting -M virt,aclint=on -cpu rv32 -smp 1 -nographic -bios none -kernel".split()
+            cmd.append(opts.qemu_firmware)
+        elif opts.target.startswith("riscv64"):
+            cmd = "qemu-system-riscv64 -semihosting -M virt,aclint=on -cpu rv64 -smp 1 -nographic -bios none -kernel".split()
+            cmd.append(opts.qemu_firmware)
+        else:
+            raise Exception("Unknwon target for QEMU: %s" % opts.target)
+
+    else:
+        cmd = cmd_iwasm
+
+    log("Running: %s" % " ".join(cmd))
+    if (r != None):
+        r.cleanup()
+    r = Runner(cmd, no_pty=opts.no_pty)
+
+    if opts.qemu:
+        r.read_to_prompt(['nsh> '], 10)
+        r.writeline(
+            "mount -t hostfs -o fs={} /tmp".format(tempfile.gettempdir()))
+        r.read_to_prompt(['nsh> '], 10)
+        r.writeline(" ".join(cmd_iwasm))
+
+    return r
+
+
+def create_tmpfiles(wast_name):
+    tempfiles = []
+
+    tempfiles.append(create_tmp_file(".wast"))
+    tempfiles.append(create_tmp_file(".wasm"))
+    if test_aot:
+        tempfiles.append(create_tmp_file(".aot"))
+
+    # add these temp file to temporal repo, will be deleted when finishing the test
+    temp_file_repo.extend(tempfiles)
+    return tempfiles
+
+
+def test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile, opts, r, loadable=True):
+    details_inside_ast = get_module_exp_from_assert(form)
+    log("module is ....'%s'" % details_inside_ast[0])
+    log("exception is ....'%s'" % details_inside_ast[1])
+    # parse the module
+    module = details_inside_ast[0]
+    expected = details_inside_ast[1]
+
+    if not compile_wast_to_wasm(module, wast_tempfile, wasm_tempfile, opts):
+        raise Exception("compile wast to wasm failed")
+
+    if test_aot:
+        r = compile_wasm_to_aot(wasm_tempfile, aot_tempfile, True, opts, r)
+        try:
+            assert_prompt(r, ['Compile success'], opts.start_timeout, True)
+        except:
+            _, exc, _ = sys.exc_info()
+            if (r.buf.find(expected) >= 0):
+                log("Out exception includes expected one, pass:")
+                log("  Expected: %s" % expected)
+                log("  Got: %s" % r.buf)
+                return
+            else:
+                log("Run wamrc failed:\n  expected: '%s'\n  got: '%s'" %
+                    (expected, r.buf))
+                ret_code = 1
+                sys.exit(1)
+
+    r = run_wasm_with_repl(
+        wasm_tempfile, aot_tempfile if test_aot else None, opts, r)
+
+    # Some module couldn't load so will raise an error directly, so shell prompt won't show here
+
+    if loadable:
+        # Wait for the initial prompt
+        try:
+            assert_prompt(r, ['webassembly> '], opts.start_timeout, True)
+        except:
+            _, exc, _ = sys.exc_info()
+            if (r.buf.find(expected) >= 0):
+                log("Out exception includes expected one, pass:")
+                log("  Expected: %s" % expected)
+                log("  Got: %s" % r.buf)
+            else:
+                raise Exception("Failed:\n  expected: '%s'\n  got: '%s'" %
+                                (expected, r.buf))
+
+
+if __name__ == "__main__":
+    opts = parser.parse_args(sys.argv[1:])
+    # print('Input param :',opts)
+
+    if opts.aot:
+        test_aot = True
+    # default x86_64
+    test_target = opts.target
+
+    if opts.rundir:
+        os.chdir(opts.rundir)
+
+    if opts.log_file:
+        log_file = open(opts.log_file, "a")
+    if opts.debug_file:
+        debug_file = open(opts.debug_file, "a")
+
+    if opts.interpreter.endswith(".py"):
+        SKIP_TESTS = PY_SKIP_TESTS
+    else:
+        SKIP_TESTS = C_SKIP_TESTS
+
+    wast_tempfile = create_tmp_file(".wast")
+    wasm_tempfile = create_tmp_file(".wasm")
+    if test_aot:
+        aot_tempfile = create_tmp_file(".aot")
+
+    ret_code = 0
+    try:
+        log("\n################################################")
+        log("### Testing %s" % opts.test_file.name)
+        log("################################################")
+        forms = read_forms(opts.test_file.read())
+        r = None
+
+        for form in forms:
+            # log("\n### Current Case is " + form + "\n")
+            if ";;" == form[0:2]:
+                log(form)
+            elif skip_test(form, SKIP_TESTS):
+                log("Skipping test: %s" % form[0:60])
+            elif re.match("^\(assert_trap\s+\(module", form):
+                test_assert_with_exception(
+                    form, wast_tempfile, wasm_tempfile, aot_tempfile if test_aot else None, opts, r)
+            elif re.match("^\(assert_exhaustion\\b.*", form):
+                test_assert_exhaustion(r, opts, form)
+            elif re.match("^\(assert_unlinkable\\b.*", form):
+                test_assert_with_exception(
+                    form, wast_tempfile, wasm_tempfile, aot_tempfile if test_aot else None, opts, r, False)
+            elif re.match("^\(assert_malformed\\b.*", form):
+                # remove comments in wast
+                form, n = re.subn(";;.*\n", "", form)
+                m = re.match(
+                    "^\(assert_malformed\s*\(module binary\s*(\".*\").*\)\s*\"(.*)\"\s*\)$", form, re.DOTALL)
+
+                if m:
+                    # workaround: spec test changes error message to "malformed" while iwasm still use "invalid"
+                    error_msg = m.group(2).replace("malformed", "invalid")
+                    log("Testing(malformed)")
+                    with open(wasm_tempfile, 'wb') as f:
+                        s = m.group(1)
+                        while s:
+                            res = re.match(
+                                "[^\"]*\"([^\"]*)\"(.*)", s, re.DOTALL)
+                            if IS_PY_3:
+                                context = res.group(1).replace("\\", "\\x").encode(
+                                    "latin1").decode("unicode-escape").encode("latin1")
+                                f.write(context)
+                            else:
+                                f.write(res.group(1).replace(
+                                    "\\", "\\x").decode("string-escape"))
+                            s = res.group(2)
+
+                    # compile wasm to aot
+                    if test_aot:
+                        r = compile_wasm_to_aot(
+                            wasm_tempfile, aot_tempfile, True, opts, r)
+                        try:
+                            assert_prompt(r, ['Compile success'],
+                                          opts.start_timeout, True)
+                        except:
+                            _, exc, _ = sys.exc_info()
+                            if (r.buf.find(error_msg) >= 0):
+                                log("Out exception includes expected one, pass:")
+                                log("  Expected: %s" % error_msg)
+                                log("  Got: %s" % r.buf)
+                                continue
+                            # one case in binary.wast
+                            elif (error_msg == "unexpected end of section or function"
+                                  and r.buf.find("unexpected end")):
+                                continue
+                            # one case in binary.wast
+                            elif (error_msg == "invalid value type"
+                                  and r.buf.find("unexpected end")):
+                                continue
+                            # one case in binary.wast
+                            elif (error_msg == "integer too large"
+                                  and r.buf.find("tables cannot be shared")):
+                                continue
+                            # one case in binary.wast
+                            elif (error_msg == "zero byte expected"
+                                  and r.buf.find("unknown table")):
+                                continue
+                            # one case in binary.wast
+                            elif (error_msg == "invalid section id"
+                                  and r.buf.find("unexpected end of section or function")):
+                                continue
+                            # one case in binary.wast
+                            elif (error_msg == "illegal opcode"
+                                  and r.buf.find("unexpected end of section or function")):
+                                continue
+                            # one case in custom.wast
+                            elif (error_msg == "length out of bounds"
+                                  and r.buf.find("unexpected end")):
+                                continue
+                            # several cases in binary-leb128.wast
+                            elif (error_msg == "integer representation too long"
+                                  and r.buf.find("invalid section id")):
+                                continue
+                            else:
+                                log("Run wamrc failed:\n  expected: '%s'\n  got: '%s'" %
+                                    (error_msg, r.buf))
+                                ret_code = 1
+                                sys.exit(1)
+
+                    r = run_wasm_with_repl(
+                        wasm_tempfile, aot_tempfile if test_aot else None, opts, r)
+
+                elif re.match("^\(assert_malformed\s*\(module quote", form):
+                    log("ignoring assert_malformed module quote")
+                else:
+                    log("unrecognized assert_malformed")
+            elif re.match("^\(assert_return[_a-z]*_nan\\b.*", form):
+                log("ignoring assert_return_.*_nan")
+                pass
+            elif re.match(".*\(invoke\s+\$\\b.*", form):
+                # invoke a particular named module's function
+                if form.startswith("(assert_return"):
+                    test_assert_return(r, opts, form)
+                elif form.startswith("(assert_trap"):
+                    test_assert_trap(r, opts, form)
+            elif re.match("^\(module\\b.*", form):
+                # if the module includes the particular name startswith $
+                m = re.search("^\(module\s+\$.\S+", form)
+                if m:
+                    # get module name
+                    module_name = re.split('\$', m.group(0).strip())[1]
+                    if module_name:
+                        # create temporal files
+                        temp_files = create_tmpfiles(module_name)
+                        if not compile_wast_to_wasm(form, temp_files[0], temp_files[1], opts):
+                            raise Exception("compile wast to wasm failed")
+
+                        if test_aot:
+                            r = compile_wasm_to_aot(
+                                temp_files[1], temp_files[2], True, opts, r)
+                            try:
+                                assert_prompt(
+                                    r, ['Compile success'], opts.start_timeout, False)
+                            except:
+                                _, exc, _ = sys.exc_info()
+                                log("Run wamrc failed:\n  got: '%s'" % r.buf)
+                                ret_code = 1
+                                sys.exit(1)
+                        temp_module_table[module_name] = temp_files[1]
+                        r = run_wasm_with_repl(
+                            temp_files[1], temp_files[2] if test_aot else None, opts, r)
+                else:
+                    if not compile_wast_to_wasm(form, wast_tempfile, wasm_tempfile, opts):
+                        raise Exception("compile wast to wasm failed")
+
+                    if test_aot:
+                        r = compile_wasm_to_aot(
+                            wasm_tempfile, aot_tempfile, True, opts, r)
+                        try:
+                            assert_prompt(r, ['Compile success'],
+                                          opts.start_timeout, False)
+                        except:
+                            _, exc, _ = sys.exc_info()
+                            log("Run wamrc failed:\n  got: '%s'" % r.buf)
+                            ret_code = 1
+                            sys.exit(1)
+
+                    r = run_wasm_with_repl(
+                        wasm_tempfile, aot_tempfile if test_aot else None, opts, r)
+
+                # Wait for the initial prompt
+                try:
+                    assert_prompt(r, ['webassembly> '],
+                                  opts.start_timeout, False)
+                except:
+                    _, exc, _ = sys.exc_info()
+                    raise Exception("Failed:\n  expected: '%s'\n  got: '%s'" %
+                                    (repr(exc), r.buf))
+
+            elif re.match("^\(assert_return\\b.*", form):
+                assert (r), "iwasm repl runtime should be not null"
+                test_assert_return(r, opts, form)
+            elif re.match("^\(assert_trap\\b.*", form):
+                test_assert_trap(r, opts, form)
+            elif re.match("^\(invoke\\b.*", form):
+                assert (r), "iwasm repl runtime should be not null"
+                do_invoke(r, opts, form)
+            elif re.match("^\(assert_invalid\\b.*", form):
+                test_assert_with_exception(
+                    form, wast_tempfile, wasm_tempfile, aot_tempfile if test_aot else None, opts, r)
+            elif re.match("^\(register\\b.*", form):
+                # get module's new name from the register cmd
+                name_new = re.split('\"', re.search(
+                    '\".*\"', form).group(0))[1]
+                if name_new:
+                    new_module = os.path.join(
+                        tempfile.gettempdir(), name_new + ".wasm")
+                    shutil.copyfile(temp_module_table.get(
+                        name_new, wasm_tempfile), new_module)
+
+                    # add new_module copied from the old into temp_file_repo[]
+                    temp_file_repo.append(new_module)
+
+                    if test_aot:
+                        new_module_aot = os.path.join(
+                            tempfile.gettempdir(), name_new + ".aot")
+                        r = compile_wasm_to_aot(
+                            new_module, new_module_aot, True, opts, r)
+                        try:
+                            assert_prompt(r, ['Compile success'],
+                                          opts.start_timeout, True)
+                        except:
+                            raise Exception("compile wasm to aot failed")
+                        # add aot module into temp_file_repo[]
+                        temp_file_repo.append(new_module_aot)
+                else:
+                    # there is no name defined in register cmd
+                    raise Exception(
+                        "can not find module name from the register")
+            else:
+                raise Exception("unrecognized form '%s...'" % form[0:40])
+    except Exception as e:
+        traceback.print_exc()
+        print("THE FINAL EXCEPTION IS {}".format(e))
+        ret_code = 101
+
+        shutil.copyfile(wasm_tempfile, os.path.join(
+            opts.log_dir, os.path.basename(wasm_tempfile)))
+
+        if opts.aot or opts.xip:
+            shutil.copyfile(aot_tempfile, os.path.join(
+                opts.log_dir, os.path.basename(aot_tempfile)))
+            if "indirect-mode" in str(e):
+                compile_wasm_to_aot(
+                    wasm_tempfile, aot_tempfile, None, opts, None, "object")
+                shutil.copyfile(aot_tempfile, os.path.join(
+                    opts.log_dir, os.path.basename(aot_tempfile)+'.o'))
+                subprocess.check_call(["llvm-objdump", "-r", aot_tempfile])
+            compile_wasm_to_aot(wasm_tempfile, aot_tempfile,
+                                None, opts, None, "ir")
+            shutil.copyfile(aot_tempfile, os.path.join(
+                opts.log_dir, os.path.basename(aot_tempfile)+".ir"))
+
+    else:
+        ret_code = 0
+    finally:
+        if not opts.no_cleanup:
+            log("Removing tempfiles")
+            os.remove(wast_tempfile)
+            os.remove(wasm_tempfile)
+            if test_aot:
+                os.remove(aot_tempfile)
+
+            # remove the files under /tempfiles/ and copy of .wasm files
+            if temp_file_repo:
+                for t in temp_file_repo:
+                    if (len(str(t)) != 0 and os.path.exists(t)):
+                        os.remove(t)
+
+            log("### End testing %s" % opts.test_file.name)
+        else:
+            log("Leaving tempfiles: %s" % ([wast_tempfile, wasm_tempfile]))
+
+        sys.exit(ret_code)

+ 115 - 0
tests/requirement-engineering/gc-aot/test_cases.json

@@ -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'"
+        }
+      ]
+    }
+  ]
+}

+ 308 - 0
tests/requirement-engineering/gc-aot/wasm-apps/array.wast

@@ -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")

+ 139 - 0
tests/requirement-engineering/gc-aot/wasm-apps/array_copy.wast

@@ -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))

+ 81 - 0
tests/requirement-engineering/gc-aot/wasm-apps/array_fill.wast

@@ -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))

+ 267 - 0
tests/requirement-engineering/gc-aot/wasm-apps/br_on_cast.wast

@@ -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"
+)

+ 282 - 0
tests/requirement-engineering/gc-aot/wasm-apps/br_on_cast_fail.wast

@@ -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"
+)

+ 208 - 0
tests/requirement-engineering/gc-aot/wasm-apps/call_ref.wast

@@ -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"
+)

+ 54 - 0
tests/requirement-engineering/gc-aot/wasm-apps/extern.wast

@@ -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))

+ 51 - 0
tests/requirement-engineering/gc-aot/wasm-apps/i31.wast

@@ -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))

+ 362 - 0
tests/requirement-engineering/gc-aot/wasm-apps/local_set.wast

@@ -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"
+)
+

+ 639 - 0
tests/requirement-engineering/gc-aot/wasm-apps/local_tee.wast

@@ -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"
+)

+ 186 - 0
tests/requirement-engineering/gc-aot/wasm-apps/ref_cast.wast

@@ -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")

+ 168 - 0
tests/requirement-engineering/gc-aot/wasm-apps/ref_eq.wast

@@ -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"
+)

+ 331 - 0
tests/requirement-engineering/gc-aot/wasm-apps/ref_test.wast

@@ -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"))

+ 376 - 0
tests/requirement-engineering/gc-aot/wasm-apps/return_call_ref.wast

@@ -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"
+)

+ 592 - 0
tests/requirement-engineering/gc-aot/wasm-apps/select.wast

@@ -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)
+)

+ 229 - 0
tests/requirement-engineering/gc-aot/wasm-apps/struct.wast

@@ -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))

+ 157 - 0
tests/requirement-engineering/gc-aot/wasm-apps/table_fill.wast

@@ -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"
+)

+ 88 - 0
tests/requirement-engineering/gc-aot/wasm-apps/table_get.wast

@@ -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"
+)

+ 176 - 0
tests/requirement-engineering/gc-aot/wasm-apps/table_grow.wast

@@ -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"
+)

+ 2149 - 0
tests/requirement-engineering/gc-aot/wasm-apps/table_init.wast

@@ -0,0 +1,2149 @@
+;;
+;; Generated by ../meta/generate_table_init.js
+;; DO NOT EDIT THIS FILE.  CHANGE THE SOURCE AND REGENERATE.
+;;
+
+(module
+  (func (export "ef0") (result i32) (i32.const 0))
+  (func (export "ef1") (result i32) (i32.const 1))
+  (func (export "ef2") (result i32) (i32.const 2))
+  (func (export "ef3") (result i32) (i32.const 3))
+  (func (export "ef4") (result i32) (i32.const 4))
+)
+(register "a")
+
+(module
+  (type (func (result i32)))  ;; type #0
+  ;; aot mode does not support module linking
+  (func (result i32) (i32.const 0))    ;; index 0
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))    ;; index 4
+  (table $t0 30 30 funcref)
+  (table $t1 30 30 funcref)
+  (elem (table $t0) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t0) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 5))  ;; index 5
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))  ;; index 9
+  (func (export "test")
+    (table.init $t0 1 (i32.const 7) (i32.const 0) (i32.const 4)))
+  (func (export "check") (param i32) (result i32)
+    (call_indirect $t0 (type 0) (local.get 0)))
+)
+
+(invoke "test")
+(assert_trap (invoke "check" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 1)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "check" (i32.const 5)) (i32.const 1))
+(assert_trap (invoke "check" (i32.const 6)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 7)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 8)) (i32.const 7))
+(assert_return (invoke "check" (i32.const 9)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 10)) (i32.const 8))
+(assert_trap (invoke "check" (i32.const 11)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 12)) (i32.const 7))
+(assert_return (invoke "check" (i32.const 13)) (i32.const 5))
+(assert_return (invoke "check" (i32.const 14)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 15)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 16)) (i32.const 6))
+(assert_trap (invoke "check" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 29)) "uninitialized element")
+
+(module
+  (type (func (result i32)))  ;; type #0
+  ;; aot mode does not support module linking
+  (func (result i32) (i32.const 0))    ;; index 0
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))    ;; index 4
+  (table $t0 30 30 funcref)
+  (table $t1 30 30 funcref)
+  (elem (table $t0) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t0) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 5))  ;; index 5
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))  ;; index 9
+  (func (export "test")
+    (table.init $t0 3 (i32.const 15) (i32.const 1) (i32.const 3)))
+  (func (export "check") (param i32) (result i32)
+    (call_indirect $t0 (type 0) (local.get 0)))
+)
+
+(invoke "test")
+(assert_trap (invoke "check" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 1)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "check" (i32.const 5)) (i32.const 1))
+(assert_trap (invoke "check" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 11)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 12)) (i32.const 7))
+(assert_return (invoke "check" (i32.const 13)) (i32.const 5))
+(assert_return (invoke "check" (i32.const 14)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 15)) (i32.const 9))
+(assert_return (invoke "check" (i32.const 16)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 17)) (i32.const 7))
+(assert_trap (invoke "check" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 29)) "uninitialized element")
+
+(module
+  (type (func (result i32)))  ;; type #0
+  ;; aot mode does not support module linking
+  (func (result i32) (i32.const 0))    ;; index 0
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))    ;; index 4
+  (table $t0 30 30 funcref)
+  (table $t1 30 30 funcref)
+  (elem (table $t0) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t0) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 5))  ;; index 5
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))  ;; index 9
+  (func (export "test")
+    (table.init $t0 1 (i32.const 7) (i32.const 0) (i32.const 4))
+         (elem.drop 1)
+         (table.init $t0 3 (i32.const 15) (i32.const 1) (i32.const 3))
+         (elem.drop 3)
+         (table.copy $t0 0 (i32.const 20) (i32.const 15) (i32.const 5))
+         (table.copy $t0 0 (i32.const 21) (i32.const 29) (i32.const 1))
+         (table.copy $t0 0 (i32.const 24) (i32.const 10) (i32.const 1))
+         (table.copy $t0 0 (i32.const 13) (i32.const 11) (i32.const 4))
+         (table.copy $t0 0 (i32.const 19) (i32.const 20) (i32.const 5)))
+  (func (export "check") (param i32) (result i32)
+    (call_indirect $t0 (type 0) (local.get 0)))
+)
+
+(invoke "test")
+(assert_trap (invoke "check" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 1)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "check" (i32.const 5)) (i32.const 1))
+(assert_trap (invoke "check" (i32.const 6)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 7)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 8)) (i32.const 7))
+(assert_return (invoke "check" (i32.const 9)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 10)) (i32.const 8))
+(assert_trap (invoke "check" (i32.const 11)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 12)) (i32.const 7))
+(assert_trap (invoke "check" (i32.const 13)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 14)) (i32.const 7))
+(assert_return (invoke "check" (i32.const 15)) (i32.const 5))
+(assert_return (invoke "check" (i32.const 16)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 17)) (i32.const 7))
+(assert_trap (invoke "check" (i32.const 18)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 19)) (i32.const 9))
+(assert_trap (invoke "check" (i32.const 20)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 21)) (i32.const 7))
+(assert_trap (invoke "check" (i32.const 22)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 23)) (i32.const 8))
+(assert_return (invoke "check" (i32.const 24)) (i32.const 8))
+(assert_trap (invoke "check" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 29)) "uninitialized element")
+
+(module
+  (type (func (result i32)))  ;; type #0
+  ;; aot mode does not support module linking
+  (func (result i32) (i32.const 0))    ;; index 0
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))    ;; index 4
+  (table $t0 30 30 funcref)
+  (table $t1 30 30 funcref)
+  (elem (table $t1) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t1) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 5))  ;; index 5
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))  ;; index 9
+  (func (export "test")
+    (table.init $t1 1 (i32.const 7) (i32.const 0) (i32.const 4)))
+  (func (export "check") (param i32) (result i32)
+    (call_indirect $t1 (type 0) (local.get 0)))
+)
+
+(invoke "test")
+(assert_trap (invoke "check" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 1)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "check" (i32.const 5)) (i32.const 1))
+(assert_trap (invoke "check" (i32.const 6)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 7)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 8)) (i32.const 7))
+(assert_return (invoke "check" (i32.const 9)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 10)) (i32.const 8))
+(assert_trap (invoke "check" (i32.const 11)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 12)) (i32.const 7))
+(assert_return (invoke "check" (i32.const 13)) (i32.const 5))
+(assert_return (invoke "check" (i32.const 14)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 15)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 16)) (i32.const 6))
+(assert_trap (invoke "check" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 29)) "uninitialized element")
+
+(module
+  (type (func (result i32)))  ;; type #0
+  ;; aot mode does not support module linking
+  (func (result i32) (i32.const 0))    ;; index 0
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))    ;; index 4
+  (table $t0 30 30 funcref)
+  (table $t1 30 30 funcref)
+  (elem (table $t1) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t1) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 5))  ;; index 5
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))  ;; index 9
+  (func (export "test")
+    (table.init $t1 3 (i32.const 15) (i32.const 1) (i32.const 3)))
+  (func (export "check") (param i32) (result i32)
+    (call_indirect $t1 (type 0) (local.get 0)))
+)
+
+(invoke "test")
+(assert_trap (invoke "check" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 1)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "check" (i32.const 5)) (i32.const 1))
+(assert_trap (invoke "check" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 11)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 12)) (i32.const 7))
+(assert_return (invoke "check" (i32.const 13)) (i32.const 5))
+(assert_return (invoke "check" (i32.const 14)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 15)) (i32.const 9))
+(assert_return (invoke "check" (i32.const 16)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 17)) (i32.const 7))
+(assert_trap (invoke "check" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 29)) "uninitialized element")
+
+(module
+  (type (func (result i32)))  ;; type #0
+  ;; aot mode does not support module linking
+  (func (result i32) (i32.const 0))    ;; index 0
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))    ;; index 4
+  (table $t0 30 30 funcref)
+  (table $t1 30 30 funcref)
+  (elem (table $t1) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t1) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 5))  ;; index 5
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))  ;; index 9
+  (func (export "test")
+    (table.init $t1 1 (i32.const 7) (i32.const 0) (i32.const 4))
+         (elem.drop 1)
+         (table.init $t1 3 (i32.const 15) (i32.const 1) (i32.const 3))
+         (elem.drop 3)
+         (table.copy $t1 1 (i32.const 20) (i32.const 15) (i32.const 5))
+         (table.copy $t1 1 (i32.const 21) (i32.const 29) (i32.const 1))
+         (table.copy $t1 1 (i32.const 24) (i32.const 10) (i32.const 1))
+         (table.copy $t1 1 (i32.const 13) (i32.const 11) (i32.const 4))
+         (table.copy $t1 1 (i32.const 19) (i32.const 20) (i32.const 5)))
+  (func (export "check") (param i32) (result i32)
+    (call_indirect $t1 (type 0) (local.get 0)))
+)
+
+(invoke "test")
+(assert_trap (invoke "check" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 1)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "check" (i32.const 5)) (i32.const 1))
+(assert_trap (invoke "check" (i32.const 6)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 7)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 8)) (i32.const 7))
+(assert_return (invoke "check" (i32.const 9)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 10)) (i32.const 8))
+(assert_trap (invoke "check" (i32.const 11)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 12)) (i32.const 7))
+(assert_trap (invoke "check" (i32.const 13)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 14)) (i32.const 7))
+(assert_return (invoke "check" (i32.const 15)) (i32.const 5))
+(assert_return (invoke "check" (i32.const 16)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 17)) (i32.const 7))
+(assert_trap (invoke "check" (i32.const 18)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 19)) (i32.const 9))
+(assert_trap (invoke "check" (i32.const 20)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 21)) (i32.const 7))
+(assert_trap (invoke "check" (i32.const 22)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 23)) (i32.const 8))
+(assert_return (invoke "check" (i32.const 24)) (i32.const 8))
+(assert_trap (invoke "check" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 29)) "uninitialized element")
+(assert_invalid
+  (module
+    (func (export "test")
+      (elem.drop 0)))
+  "unknown elem segment 0")
+
+(assert_invalid
+  (module
+    (func (export "test")
+      (table.init 0 (i32.const 12) (i32.const 1) (i32.const 1))))
+  "unknown table 0")
+
+(assert_invalid
+  (module
+    (elem funcref (ref.func 0))
+    (func (result i32) (i32.const 0))
+    (func (export "test")
+      (elem.drop 4)))
+  "unknown elem segment 4")
+
+(assert_invalid
+  (module
+    (elem funcref (ref.func 0))
+    (func (result i32) (i32.const 0))
+    (func (export "test")
+      (table.init 4 (i32.const 12) (i32.const 1) (i32.const 1))))
+  "unknown table 0")
+
+
+(module
+  (table $t0 30 30 funcref)
+  (table $t1 28 28 funcref)
+  (elem (table $t0) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t0) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (elem.drop 2)
+    ))
+(invoke "test")
+
+(module
+  (table $t0 30 30 funcref)
+  (table $t1 28 28 funcref)
+  (elem (table $t0) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t0) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.init 2 (i32.const 12) (i32.const 1) (i32.const 1))
+    ))
+(assert_trap (invoke "test") "out of bounds table access")
+
+(module
+  (table $t0 30 30 funcref)
+  (table $t1 28 28 funcref)
+  (elem (table $t0) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t0) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))
+    (table.init 1 (i32.const 21) (i32.const 1) (i32.const 1))))
+(invoke "test")
+
+(module
+  (table $t0 30 30 funcref)
+  (table $t1 28 28 funcref)
+  (elem (table $t0) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t0) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (elem.drop 1)
+    (elem.drop 1)))
+(invoke "test")
+
+(module
+  (table $t0 30 30 funcref)
+  (table $t1 28 28 funcref)
+  (elem (table $t0) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t0) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (elem.drop 1)
+    (table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))))
+(assert_trap (invoke "test") "out of bounds table access")
+
+(module
+  (table $t0 30 30 funcref)
+  (table $t1 28 28 funcref)
+  (elem (table $t0) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t0) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.init 1 (i32.const 12) (i32.const 0) (i32.const 5))
+    ))
+(assert_trap (invoke "test") "out of bounds table access")
+
+(module
+  (table $t0 30 30 funcref)
+  (table $t1 28 28 funcref)
+  (elem (table $t0) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t0) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.init 1 (i32.const 12) (i32.const 2) (i32.const 3))
+    ))
+(assert_trap (invoke "test") "out of bounds table access")
+
+(module
+  (table $t0 30 30 funcref)
+  (table $t1 28 28 funcref)
+  (elem (table $t0) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t0) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.init $t0 1 (i32.const 28) (i32.const 1) (i32.const 3))
+    ))
+(assert_trap (invoke "test") "out of bounds table access")
+
+(module
+  (table $t0 30 30 funcref)
+  (table $t1 28 28 funcref)
+  (elem (table $t0) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t0) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.init $t0 1 (i32.const 12) (i32.const 4) (i32.const 0))
+    ))
+(invoke "test")
+
+(module
+  (table $t0 30 30 funcref)
+  (table $t1 28 28 funcref)
+  (elem (table $t0) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t0) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.init $t0 1 (i32.const 12) (i32.const 5) (i32.const 0))
+    ))
+(assert_trap (invoke "test") "out of bounds table access")
+
+(module
+  (table $t0 30 30 funcref)
+  (table $t1 28 28 funcref)
+  (elem (table $t0) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t0) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.init $t0 1 (i32.const 30) (i32.const 2) (i32.const 0))
+    ))
+(invoke "test")
+
+(module
+  (table $t0 30 30 funcref)
+  (table $t1 28 28 funcref)
+  (elem (table $t0) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t0) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.init $t0 1 (i32.const 31) (i32.const 2) (i32.const 0))
+    ))
+(assert_trap (invoke "test") "out of bounds table access")
+
+(module
+  (table $t0 30 30 funcref)
+  (table $t1 28 28 funcref)
+  (elem (table $t0) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t0) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.init $t0 1 (i32.const 30) (i32.const 4) (i32.const 0))
+    ))
+(invoke "test")
+
+(module
+  (table $t0 30 30 funcref)
+  (table $t1 28 28 funcref)
+  (elem (table $t0) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t0) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.init $t0 1 (i32.const 31) (i32.const 5) (i32.const 0))
+    ))
+(assert_trap (invoke "test") "out of bounds table access")
+
+(module
+  (table $t0 30 30 funcref)
+  (table $t1 28 28 funcref)
+  (elem (table $t1) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t1) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.init $t1 1 (i32.const 26) (i32.const 1) (i32.const 3))
+    ))
+(assert_trap (invoke "test") "out of bounds table access")
+
+(module
+  (table $t0 30 30 funcref)
+  (table $t1 28 28 funcref)
+  (elem (table $t1) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t1) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.init $t1 1 (i32.const 12) (i32.const 4) (i32.const 0))
+    ))
+(invoke "test")
+
+(module
+  (table $t0 30 30 funcref)
+  (table $t1 28 28 funcref)
+  (elem (table $t1) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t1) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.init $t1 1 (i32.const 12) (i32.const 5) (i32.const 0))
+    ))
+(assert_trap (invoke "test") "out of bounds table access")
+
+(module
+  (table $t0 30 30 funcref)
+  (table $t1 28 28 funcref)
+  (elem (table $t1) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t1) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.init $t1 1 (i32.const 28) (i32.const 2) (i32.const 0))
+    ))
+(invoke "test")
+
+(module
+  (table $t0 30 30 funcref)
+  (table $t1 28 28 funcref)
+  (elem (table $t1) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t1) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.init $t1 1 (i32.const 29) (i32.const 2) (i32.const 0))
+    ))
+(assert_trap (invoke "test") "out of bounds table access")
+
+(module
+  (table $t0 30 30 funcref)
+  (table $t1 28 28 funcref)
+  (elem (table $t1) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t1) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.init $t1 1 (i32.const 28) (i32.const 4) (i32.const 0))
+    ))
+(invoke "test")
+
+(module
+  (table $t0 30 30 funcref)
+  (table $t1 28 28 funcref)
+  (elem (table $t1) (i32.const 2) func 3 1 4 1)
+  (elem funcref
+    (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8))
+  (elem (table $t1) (i32.const 12) func 7 5 2 3 6)
+  (elem funcref
+    (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6))
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.init $t1 1 (i32.const 29) (i32.const 5) (i32.const 0))
+    ))
+(assert_trap (invoke "test") "out of bounds table access")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (i32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (i32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (i32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (f32.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (f32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (f32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (f32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (i64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (i64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (i64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (i64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (f64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (f64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (f64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (f64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (i32.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (i32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (i32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (i32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (f32.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (f32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (f32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (f32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (i64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (i64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (i64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (i64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (f64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (f64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (f64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (f64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (i32.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (i32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (i32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (i32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (f32.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (f32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (f32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (f32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (i64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (i64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (i64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (i64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (f64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (f64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (f64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (f64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (i32.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (i32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (i32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (i32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (f32.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (f32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (f32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (f32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (i64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (i64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (i64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (i64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (f64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (f64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (f64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0))
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (f64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(module
+  (type (func (result i32)))
+  (table 32 64 funcref)
+  (elem funcref
+    (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3)
+    (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7)
+    (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11)
+    (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15))
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $offs i32) (param $len i32)
+    (table.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 24) (i32.const 16)) "out of bounds table access")
+(assert_trap (invoke "test" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 1)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 2)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 3)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 4)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 5)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 11)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 12)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 13)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 14)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 15)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 16)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 29)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 30)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 31)) "uninitialized element")
+
+(module
+  (type (func (result i32)))
+  (table 32 64 funcref)
+  (elem funcref
+    (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3)
+    (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7)
+    (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11)
+    (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15))
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $offs i32) (param $len i32)
+    (table.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 25) (i32.const 16)) "out of bounds table access")
+(assert_trap (invoke "test" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 1)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 2)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 3)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 4)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 5)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 11)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 12)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 13)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 14)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 15)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 16)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 29)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 30)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 31)) "uninitialized element")
+
+(module
+  (type (func (result i32)))
+  (table 160 320 funcref)
+  (elem funcref
+    (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3)
+    (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7)
+    (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11)
+    (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15))
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $offs i32) (param $len i32)
+    (table.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 96) (i32.const 32)) "out of bounds table access")
+(assert_trap (invoke "test" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 1)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 2)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 3)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 4)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 5)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 11)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 12)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 13)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 14)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 15)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 16)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 29)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 30)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 31)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 32)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 33)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 34)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 35)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 36)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 37)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 38)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 39)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 40)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 41)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 42)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 43)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 44)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 45)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 46)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 47)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 48)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 49)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 50)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 51)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 52)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 53)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 54)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 55)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 56)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 57)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 58)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 59)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 60)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 61)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 62)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 63)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 64)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 65)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 66)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 67)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 68)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 69)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 70)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 71)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 72)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 73)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 74)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 75)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 76)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 77)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 78)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 79)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 80)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 81)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 82)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 83)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 84)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 85)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 86)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 87)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 88)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 89)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 90)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 91)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 92)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 93)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 94)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 95)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 96)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 97)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 98)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 99)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 100)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 101)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 102)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 103)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 104)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 105)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 106)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 107)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 108)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 109)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 110)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 111)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 112)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 113)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 114)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 115)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 116)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 117)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 118)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 119)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 120)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 121)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 122)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 123)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 124)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 125)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 126)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 127)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 128)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 129)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 130)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 131)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 132)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 133)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 134)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 135)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 136)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 137)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 138)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 139)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 140)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 141)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 142)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 143)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 144)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 145)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 146)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 147)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 148)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 149)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 150)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 151)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 152)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 153)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 154)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 155)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 156)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 157)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 158)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 159)) "uninitialized element")
+
+(module
+  (type (func (result i32)))
+  (table 160 320 funcref)
+  (elem funcref
+    (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3)
+    (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7)
+    (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11)
+    (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15))
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $offs i32) (param $len i32)
+    (table.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 97) (i32.const 31)) "out of bounds table access")
+(assert_trap (invoke "test" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 1)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 2)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 3)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 4)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 5)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 11)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 12)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 13)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 14)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 15)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 16)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 29)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 30)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 31)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 32)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 33)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 34)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 35)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 36)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 37)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 38)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 39)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 40)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 41)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 42)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 43)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 44)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 45)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 46)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 47)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 48)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 49)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 50)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 51)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 52)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 53)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 54)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 55)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 56)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 57)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 58)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 59)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 60)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 61)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 62)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 63)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 64)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 65)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 66)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 67)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 68)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 69)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 70)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 71)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 72)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 73)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 74)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 75)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 76)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 77)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 78)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 79)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 80)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 81)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 82)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 83)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 84)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 85)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 86)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 87)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 88)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 89)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 90)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 91)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 92)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 93)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 94)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 95)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 96)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 97)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 98)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 99)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 100)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 101)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 102)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 103)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 104)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 105)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 106)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 107)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 108)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 109)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 110)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 111)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 112)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 113)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 114)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 115)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 116)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 117)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 118)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 119)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 120)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 121)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 122)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 123)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 124)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 125)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 126)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 127)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 128)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 129)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 130)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 131)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 132)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 133)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 134)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 135)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 136)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 137)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 138)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 139)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 140)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 141)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 142)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 143)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 144)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 145)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 146)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 147)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 148)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 149)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 150)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 151)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 152)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 153)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 154)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 155)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 156)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 157)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 158)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 159)) "uninitialized element")
+
+(module
+  (type (func (result i32)))
+  (table 64 64 funcref)
+  (elem funcref
+    (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3)
+    (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7)
+    (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11)
+    (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15))
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $offs i32) (param $len i32)
+    (table.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 48) (i32.const 4294967280)) "out of bounds table access")
+(assert_trap (invoke "test" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 1)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 2)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 3)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 4)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 5)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 11)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 12)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 13)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 14)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 15)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 16)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 29)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 30)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 31)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 32)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 33)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 34)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 35)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 36)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 37)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 38)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 39)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 40)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 41)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 42)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 43)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 44)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 45)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 46)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 47)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 48)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 49)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 50)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 51)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 52)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 53)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 54)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 55)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 56)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 57)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 58)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 59)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 60)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 61)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 62)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 63)) "uninitialized element")
+
+(module
+  (type (func (result i32)))
+  (table 16 16 funcref)
+  (elem funcref
+    (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3)
+    (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7)
+    (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11)
+    (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15))
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $offs i32) (param $len i32)
+    (table.init 0 (local.get $offs) (i32.const 8) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 0) (i32.const 4294967292)) "out of bounds table access")
+(assert_trap (invoke "test" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 1)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 2)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 3)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 4)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 5)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 11)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 12)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 13)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 14)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 15)) "uninitialized element")
+
+(module
+  (table 1 funcref)
+  ;; 65 elem segments. 64 is the smallest positive number that is encoded
+  ;; differently as a signed LEB.
+  (elem funcref) (elem funcref) (elem funcref) (elem funcref)
+  (elem funcref) (elem funcref) (elem funcref) (elem funcref)
+  (elem funcref) (elem funcref) (elem funcref) (elem funcref)
+  (elem funcref) (elem funcref) (elem funcref) (elem funcref)
+  (elem funcref) (elem funcref) (elem funcref) (elem funcref)
+  (elem funcref) (elem funcref) (elem funcref) (elem funcref)
+  (elem funcref) (elem funcref) (elem funcref) (elem funcref)
+  (elem funcref) (elem funcref) (elem funcref) (elem funcref)
+  (elem funcref) (elem funcref) (elem funcref) (elem funcref)
+  (elem funcref) (elem funcref) (elem funcref) (elem funcref)
+  (elem funcref) (elem funcref) (elem funcref) (elem funcref)
+  (elem funcref) (elem funcref) (elem funcref) (elem funcref)
+  (elem funcref) (elem funcref) (elem funcref) (elem funcref)
+  (elem funcref) (elem funcref) (elem funcref) (elem funcref)
+  (elem funcref) (elem funcref) (elem funcref) (elem funcref)
+  (elem funcref) (elem funcref) (elem funcref) (elem funcref)
+  (elem funcref)
+  (func (table.init 64 (i32.const 0) (i32.const 0) (i32.const 0))))

+ 119 - 0
tests/requirement-engineering/gc-aot/wasm-apps/table_set.wast

@@ -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"
+)

+ 804 - 0
tests/requirement-engineering/gc-aot/wasm-apps/type_subtyping.wast

@@ -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"
+)
+

+ 215 - 0
tests/wamr-test-suites/requirement-engineering-test-script/run_requirement.py

@@ -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()

+ 36 - 4
tests/wamr-test-suites/test_wamr.sh

@@ -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